Diff of /lung_segmentation.py [000000] .. [70b6b3]

Switch to unified view

a b/lung_segmentation.py
1
import numpy as np
2
import skimage.measure
3
import skimage.segmentation
4
import skimage.morphology
5
import skimage.filters
6
import scipy.ndimage
7
import utils_plots
8
9
10
def segment_HU_scan(x):
11
    mask = np.asarray(x < -350, dtype='int32')
12
    for iz in xrange(mask.shape[0]):
13
        skimage.segmentation.clear_border(mask[iz], in_place=True)
14
        skimage.morphology.binary_opening(mask[iz], selem=skimage.morphology.disk(5), out=mask[iz])
15
        if np.sum(mask[iz]):
16
            mask[iz] = skimage.morphology.convex_hull_image(mask[iz])
17
    return mask
18
19
20
def segment_HU_scan_frederic(x, threshold=-350):
21
    mask = np.copy(x)
22
    binary_part = mask > threshold
23
    selem1 = skimage.morphology.disk(8)
24
    selem2 = skimage.morphology.disk(2)
25
    selem3 = skimage.morphology.disk(13)
26
27
    for iz in xrange(mask.shape[0]):
28
        # fill the body part
29
        filled = scipy.ndimage.binary_fill_holes(binary_part[iz])  # fill body
30
        filled_borders_mask = skimage.morphology.binary_erosion(filled, selem1)
31
        mask[iz] *= filled_borders_mask
32
33
34
        mask[iz] = skimage.morphology.closing(mask[iz], selem2)
35
        mask[iz] = skimage.morphology.erosion(mask[iz], selem3)
36
        mask[iz] = mask[iz] < threshold
37
38
    return mask
39
40
41
def segment_HU_scan_elias(x, threshold=-350, pid='test', plot=False, verbose=False):
42
    mask = np.copy(x)
43
    binary_part = mask > threshold
44
    selem1 = skimage.morphology.disk(8)
45
    selem2 = skimage.morphology.disk(2)
46
    selem3 = skimage.morphology.disk(13)
47
48
    for iz in xrange(mask.shape[0]):
49
        # fill the body part
50
        filled = scipy.ndimage.binary_fill_holes(binary_part[iz])  # fill body
51
        filled_borders_mask = skimage.morphology.binary_erosion(filled, selem1)
52
        mask[iz] *= filled_borders_mask
53
54
        mask[iz] = skimage.morphology.closing(mask[iz], selem2)
55
        mask[iz] = mask[iz] < threshold
56
57
    # params
58
    overlap_treshold = 7
59
    ratio_overlap_treshold = 0.015
60
61
    #discard disconnected regions, start at the middle slice and go to the head
62
    for iz in range(mask.shape[0]/2, mask.shape[0]-1):
63
        overlap = mask[iz] * mask[iz+1] 
64
        label_image = skimage.measure.label(mask[iz+1])
65
        if verbose: 
66
            print 'iz', iz
67
        for idx, region in enumerate(skimage.measure.regionprops(label_image)):
68
            total_overlap = 0
69
            for coordinates in region.coords:                
70
                total_overlap += overlap[coordinates[0], coordinates[1]]
71
            ratio_overlap = 1.*total_overlap/region.area
72
            if verbose:
73
                print 'region', idx, ', t_overlap', total_overlap, ', r_overlap ', ratio_overlap, ', area ', region.area, ', center', np.round(region.centroid)
74
            if total_overlap < overlap_treshold or ratio_overlap < ratio_overlap_treshold:
75
                if verbose:
76
                    print 'region', idx, 'in slice z=', iz-1, 'has a low overlap (', total_overlap, ratio_overlap, ') and will be discarded'
77
                for coordinates in region.coords: 
78
                    mask[iz+1, coordinates[0], coordinates[1]] = 0
79
80
    #discard disconnected regions, start at the middle slice and go to the head
81
    for iz in range(mask.shape[0]/2,0,-1 ):
82
        overlap = mask[iz] * mask[iz-1] 
83
        label_image = skimage.measure.label(mask[iz-1])
84
        if verbose: 
85
            print 'iz', iz
86
        for idx, region in enumerate(skimage.measure.regionprops(label_image)):
87
            total_overlap = 0
88
            for coordinates in region.coords:                
89
                total_overlap += overlap[coordinates[0], coordinates[1]]
90
            ratio_overlap = 1.*total_overlap/region.area
91
            if verbose: 
92
                print 'region', idx, ', t_overlap', total_overlap, ', r_overlap ', ratio_overlap, ', area ', region.area, ', center', np.round(region.centroid)
93
            if total_overlap < overlap_treshold or ratio_overlap < ratio_overlap_treshold:
94
                if verbose: 
95
                    print 'region', idx, 'in slice z=', iz-1, 'has a low overlap (', total_overlap, ratio_overlap, ') and will be discarded'
96
                for coordinates in region.coords: 
97
                    mask[iz-1, coordinates[0], coordinates[1]] = 0
98
99
100
    #erode out the blood vessels and the borders of the lung for a cleaner mask
101
    for iz in xrange(mask.shape[0]):
102
        mask[iz] = skimage.morphology.binary_dilation(mask[iz], selem3)
103
        #mask[iz] = scipy.ndimage.binary_fill_holes(mask[iz])
104
105
106
    if plot:
107
        utils_plots.plot_all_slices(x, mask, pid, './plots/segment_HU_scan_elias/')
108
109
    return mask
110
111
112
def segment_HU_scan_ira(x, threshold=-350, min_area=300):
113
    mask = np.asarray(x < threshold, dtype='int8')
114
115
    for zi in xrange(mask.shape[0]):
116
        skimage.segmentation.clear_border(mask[zi, :, :], in_place=True)
117
118
    # noise reduction
119
    mask = skimage.morphology.binary_opening(mask, skimage.morphology.cube(2))
120
    mask = np.asarray(mask, dtype='int8')
121
122
    # label regions
123
    label_image = skimage.measure.label(mask)
124
    region_props = skimage.measure.regionprops(label_image)
125
    sorted_regions = sorted(region_props, key=lambda x: x.area, reverse=True)
126
    lung_label = sorted_regions[0].label
127
    lung_mask = np.asarray((label_image == lung_label), dtype='int8')
128
129
    # convex hull mask
130
    lung_mask_convex = np.zeros_like(lung_mask)
131
    for i in range(lung_mask.shape[2]):
132
        if np.any(lung_mask[:, :, i]):
133
            lung_mask_convex[:, :, i] = skimage.morphology.convex_hull_image(lung_mask[:, :, i])
134
135
    # old mask inside the convex hull
136
    mask *= lung_mask_convex
137
    label_image = skimage.measure.label(mask)
138
    region_props = skimage.measure.regionprops(label_image)
139
    sorted_regions = sorted(region_props, key=lambda x: x.area, reverse=True)
140
141
    for r in sorted_regions[1:]:
142
        if r.area > min_area:
143
            # make an image only containing that region
144
            label_image_r = label_image == r.label
145
            # grow the mask
146
            label_image_r = scipy.ndimage.binary_dilation(label_image_r,
147
                                                          structure=scipy.ndimage.generate_binary_structure(3, 2))
148
            # compute the overlap with true lungs
149
            overlap = label_image_r * lung_mask
150
            if not np.any(overlap):
151
                for i in range(label_image_r.shape[0]):
152
                    if np.any(label_image_r[i]):
153
                        label_image_r[i] = skimage.morphology.convex_hull_image(label_image_r[i])
154
                lung_mask_convex *= 1 - label_image_r
155
156
    return lung_mask_convex