a b/FastRCNN/utils/postProcessing.py
1
from .imageUtils import cropImage
2
from skimage import exposure, morphology, measure, draw
3
import numpy as np
4
import matplotlib.pyplot as plt
5
import math
6
7
8
def watershed_image(img):
9
    """
10
    use watershed flooding algorithm to extract the loop contour
11
    :param img: type(numpy.ndarray) image in CHW format
12
    :return: type(numpy.ndarray) image in HW format
13
    """
14
    img_gray = img[1,:,:]
15
    h, w = img_gray.shape
16
    img1 = exposure.equalize_hist(img_gray)
17
    # invert the image
18
    img2 = np.max(img1) - img1
19
    inner = np.zeros((h, w), np.bool)
20
    centroid = [round(a) for a in findCentroid(img2)]
21
    inner[centroid[0], centroid[1]] = 1
22
    min_size = round((h + w) / 20)
23
    kernel = morphology.disk(min_size)
24
    inner = morphology.dilation(inner, kernel)
25
26
    out = np.zeros((h,w), np.bool)
27
    out[0, 0] = 1
28
    out[h - 1, 0] = 1
29
    out[0, w - 1] = 1
30
    out[h - 1, w - 1] = 1
31
    out = morphology.dilation(out, kernel)
32
    out[0, :] = 1
33
    out[h - 1, :] = 1
34
    out[:, w - 1] = 1
35
    out[:, 0] = 1
36
37
    markers = np.zeros((h, w), np.int)
38
    markers[inner] = 2
39
    markers[out] = 1
40
41
    labels = morphology.watershed(img2, markers)
42
43
    return labels
44
45
def findCentroid(img):
46
    """
47
    find the centroid position of a image by weighted method
48
    :param img: (numpy.ndarray) image in HW format
49
    :return: (tuple) (y,x) coordinates of the centroid
50
    """
51
    h, w = img.shape
52
    #  add weighted method later
53
    return h/2, w/2
54
55
56
def flood_fitting(img):
57
    """
58
    Use watershed flooding algorithm and regional property analysis
59
    to output the fitted ellipse parameters
60
    :param img: (numpy.ndarray) image in CHW format
61
    :return: region property, where property can be accessed through attributes
62
            example:
63
            area, bbox, centroid, major_axis_length, minor_axis_length, orientation
64
    """
65
    labels = watershed_image(img)
66
    results = measure.regionprops(labels - 1)
67
    sorted(results, key=lambda k: k['area'],reverse=True)
68
    # return the one with largest area
69
    return results[0]
70
71
def show_fitted_ellipse(img):
72
    """
73
    Show fitted ellipse on the image
74
    :param img: img in CHW format
75
    :return: plot ellipse on top of the image
76
    """
77
    region1 = flood_fitting(img)
78
    rr, cc = draw.ellipse_perimeter(int(region1['centroid'][0]), int(region1['centroid'][1]),
79
                                    int(region1['minor_axis_length'] / 2),
80
                                    int(region1['major_axis_length'] / 2), -region1['orientation'], img.shape[1:])
81
    plt.imshow(img[1,:,:], cmap='gray')
82
    plt.plot(cc, rr, '.')
83
84
85
def img_ellipse_fitting(img, bboxes):
86
    subimages, bboxes = cropImage(img, bboxes)
87
    y_points = np.array([])
88
    x_points = np.array([])
89
    for subim, bbox in zip(subimages, bboxes):
90
        region1 = flood_fitting(subim)
91
        result = (int(region1['centroid'][0]+bbox[0]), int(region1['centroid'][1]+bbox[1]),
92
                  int(region1['minor_axis_length'] / 2), int(region1['major_axis_length'] / 2),
93
                  -region1['orientation'])
94
        rr,cc = draw.ellipse_perimeter(*result)
95
        y_points = np.concatenate((y_points,rr))
96
        x_points = np.concatenate((x_points,cc))
97
    fig = plt.figure(figsize=(10,10))
98
    plt.imshow(img[0,:,:], cmap='gray')
99
    plt.scatter(x_points,y_points,s=(1*72./fig.dpi)**2,alpha=0.5)
100
101
def img_ellipse_fitting_area(img, bboxes):
102
    subimages, bboxes = cropImage(img, bboxes)
103
    ellipse_info_list = list()
104
    for subim, bbox in zip(subimages, bboxes):
105
        region1 = flood_fitting(subim)
106
        result = (int(region1['centroid'][0]+bbox[0]), int(region1['centroid'][1]+bbox[1]),
107
                  int(region1['minor_axis_length'] / 2), int(region1['major_axis_length'] / 2),
108
                  -region1['orientation'])
109
        ellipse_info_list.append(result)
110
    area = list()
111
    for item in enumerate(ellipse_info_list):
112
        area.append(math.pi * item[1][1] * item[1][2])
113
    plt.hist(area, bins=50)
114
    plt.xlabel('Area of ellipse')
115
    plt.ylabel('Frequency')
116
    plt.title(r'$\mathrm{Distribution\  of\  Ellipse\ Area}$')
117
    fig = plt.figure(figsize=(10, 10))
118
    plt.show()