def dist_to_spine(self): if self.spine_wvs is None: self.get_spine() ld = scipy.ndimage.morphology.distance_transform_edt(1 - self.spine_wvs) ld = ld * float(self.working_vs[0]) # convert distances to mm return resize_to_shape(ld, self.orig_shape)
def get_lungs_orig( self ): # TODO - this doesnt work correctly, is segmenting a lot of unneeded stuff lungs = scipy.ndimage.filters.gaussian_filter(self.data3dr, sigma=[4, 2, 2]) > -150 lungs[0, :, :] = 1 lungs = scipy.ndimage.morphology.binary_fill_holes(lungs) labs, n = scipy.ndimage.measurements.label(lungs == 0) cornerlab = [ labs[0, 0, 0], labs[0, 0, -1], labs[0, -1, 0], labs[0, -1, -1], labs[-1, 0, 0], labs[-1, 0, -1], labs[-1, -1, 0], labs[-1, -1, -1] ] lb = np.median(cornerlab) labs[labs == lb] = 0 labs[labs == labs[0, 0, 0]] = 0 labs[labs == labs[0, 0, -1]] = 0 labs[labs == labs[0, -1, 0]] = 0 labs[labs == labs[0, -1, -1]] = 0 labs[labs == labs[-1, 0, 0]] = 0 labs[labs == labs[-1, 0, -1]] = 0 labs[labs == labs[-1, -1, 0]] = 0 labs[labs == labs[-1, -1, -1]] = 0 lungs = labs > 0 self.lungs = lungs #self.body = (labs == 80) return resize_to_shape(lungs, self.orig_shape)
def get_spine(self): """ Should have been named get_bones() """ # prepare required data if self.body is None: self.get_body() # self.body # filter out noise in data data3dr = scipy.ndimage.filters.median_filter(self.data3dr, 3) # tresholding # > 240 - still includes kidneys and small part of heart # > 280 - still a small bit of kidneys # > 350 - only edges of bones bones = data3dr > 320 del (data3dr) bones[self.body == 0] = 0 # cut out anything not inside body # close holes in data bones = scipy.ndimage.morphology.binary_closing( bones, structure=np.ones( (3, 3, 3))) # TODO - fix removal of data on edge slices # compute center self.spine_center_wvs = np.mean(np.nonzero(bones), 1) self.spine_center_mm = self.spine_center_wvs * self.working_vs / self.voxelsize_mm.astype( np.double) # self.center2 = np.mean(np.nonzero(bones), 2) self.spine_wvs = bones return resize_to_shape(bones, self.orig_shape)
def get_spine(self, skip_resize=False): """ Should have been named get_bones() """ # prepare required data if self.body is None: self.get_body(skip_resize=True) # self.body # filter out noise in data data3dr = scipy.ndimage.filters.median_filter(self.data3dr, 3) # tresholding # > 240 - still includes kidneys and small part of heart # > 280 - still a small bit of kidneys # > 350 - only edges of bones bones = data3dr > 320; del(data3dr) bones[self.body==0] = 0 # cut out anything not inside body # close holes in data bones = scipy.ndimage.morphology.binary_closing(bones, structure=np.ones((3,3,3))) # TODO - fix removal of data on edge slices # compute center self.spine_center_wvs = np.mean(np.nonzero(bones), 1) self.spine_center_mm = self.spine_center_wvs * self.working_vs / self.voxelsize_mm.astype(np.double) # self.center2 = np.mean(np.nonzero(bones), 2) self.spine_wvs = bones if skip_resize: return bones else: return resize_to_shape(bones, self.orig_shape)
def dist_diaphragm(self): if self.diaphragm_mask is None: self.get_diaphragm_mask() dst = (scipy.ndimage.morphology.distance_transform_edt( self.diaphragm_mask) - scipy.ndimage.morphology.distance_transform_edt( 1 - self.diaphragm_mask)) return resize_to_shape(dst, self.orig_shape)
def weak_dist_bone(self, bone_hull, body): """ Metoda pro zjisteni, jak blizko jsme stredu (nejvzdalenejsimu mistu od povrchu) """ blank_body = np.ones(body.shape) bone_edge_dist = scipy.ndimage.morphology.distance_transform_edt(bone_hull) bone_edge_dist_maximum = np.max(bone_edge_dist) bone_edge_dist_focus = bone_edge_dist > 0*bone_edge_dist_maximum blank_body[:] = bone_edge_dist_focus ld = scipy.ndimage.morphology.distance_transform_edt(blank_body) return resize_to_shape(ld, self.ss.orig_shape)
def weak_dist_bone(self, bone_hull, body): """ Metoda pro zjisteni, jak blizko jsme stredu (nejvzdalenejsimu mistu od povrchu) """ blank_body = np.ones(body.shape) bone_edge_dist = scipy.ndimage.morphology.distance_transform_edt( bone_hull) bone_edge_dist_maximum = np.max(bone_edge_dist) bone_edge_dist_focus = bone_edge_dist > 0 * bone_edge_dist_maximum blank_body[:] = bone_edge_dist_focus ld = scipy.ndimage.morphology.distance_transform_edt(blank_body) return resize_to_shape(ld, self.ss.orig_shape)
def dist_to_ribs(self): """ Distance to ribs. The distance is grater than zero inside of body and outside of body """ if self.ribs is None: self.get_ribs() ld = scipy.ndimage.morphology.distance_transform_edt(1 - self.ribs) ld = ld * float(self.working_vs[0]) # convert distances to mm return resize_to_shape(ld, self.orig_shape)
def dist_to_chest(self): if self.chest is None: self.get_ribs() ld_positive = scipy.ndimage.morphology.distance_transform_edt( self.chest) ld_negative = scipy.ndimage.morphology.distance_transform_edt( 1 - self.chest) ld = ld_positive - ld_negative ld = ld * float(self.working_vs[0]) # convert distances to mm return resize_to_shape(ld, self.orig_shape)
def dist_axial(self): if self.diaphragm_mask is None: self.get_diaphragm_mask(skip_resize=True) axdst = np.ones(self.data3dr.shape, dtype=np.int16) axdst[0 ,: ,:] = 0 iz, ix, iy = np.nonzero(self.diaphragm_mask) # print 'dia level ', self.diaphragm_mask_level axdst = scipy.ndimage.morphology.distance_transform_edt(axdst) - int(self.diaphragm_mask_level) axdst = axdst * self.working_vs[0] return resize_to_shape(axdst, self.orig_shape)
def dist_axial(self): if self.diaphragm_mask is None: self.get_diaphragm_mask() axdst = np.ones(self.data3dr.shape, dtype=np.int16) axdst[0, :, :] = 0 iz, ix, iy = np.nonzero(self.diaphragm_mask) # print 'dia level ', self.diaphragm_mask_level axdst = scipy.ndimage.morphology.distance_transform_edt(axdst) - int( self.diaphragm_mask_level) return resize_to_shape(axdst, self.orig_shape)
def dist_to_surface(self): """ Positive values in mm inside of body. :return: """ if self.body is None: self.get_body(skip_resize=True) # return self._resize_and_dist(self.body) ld = scipy.ndimage.morphology.distance_transform_edt(self.body) ld = ld*float(self.working_vs[0]) # convert distances to mm return resize_to_shape(ld, self.orig_shape)
def get_body(self): # create segmented 3d data body = OrganDetectionAlgo.getBody(\ scipy.ndimage.filters.gaussian_filter(self.data3dr, sigma=2), \ self.working_vs) self.body = body # get body width and height widths = [] heights = [] for z in range(body.shape[0]): x_sum = np.sum(body[z, :, :], axis=0) # suma kazdeho sloupcu x_start = next((i for i, x in enumerate(list(x_sum)) if x != 0), None) x_end = next( (i for i, x in enumerate(reversed(list(x_sum))) if x != 0), None) if x_start is None or x_end is None: width = 0 else: width = (body.shape[2] - x_end) - x_start widths.append(width) y_sum = np.sum(body[z, :, :], axis=1) # suma kazdeho radku y_start = next((i for i, y in enumerate(list(y_sum)) if y != 0), None) y_end = next( (i for i, y in enumerate(reversed(list(y_sum))) if y != 0), None) if y_start is None or y_end is None: height = 0 else: height = (body.shape[1] - y_end) - y_start heights.append(height) # get value which is bigger then 90% of calculated values (to ignore bad data) body_width = np.percentile(np.asarray(widths), 90.0) body_height = np.percentile(np.asarray(heights), 90.0) # convert to original resolution body_width = body_width * (self.orig_shape[2] / float(self.body.shape[2])) body_height = body_height * (self.orig_shape[1] / float(self.body.shape[1])) # conver to mm self.body_width = body_width * float(self.voxelsize_mm[2]) self.body_height = body_height * float(self.voxelsize_mm[1]) return resize_to_shape(self.body, self.orig_shape)
def dist_diaphragm(self): """ Get positive values in superior to (above) diaphragm and negative values inferior (under) diaphragm. :return: """ if self.diaphragm_mask is None: self.get_diaphragm_mask(skip_resize=True) dst = (scipy.ndimage.morphology.distance_transform_edt( self.diaphragm_mask)#, sampling=self.voxelsize_mm) - scipy.ndimage.morphology.distance_transform_edt( 1 - self.diaphragm_mask)#, sampling=self.voxelsize_mm) ) dst = dst * self.working_vs[0] return resize_to_shape(dst, self.orig_shape)
def get_body(self, skip_resize=False): # create segmented 3d data body = OrganDetectionAlgo.getBody(\ scipy.ndimage.filters.gaussian_filter(self.data3dr, sigma=2), \ self.working_vs) self.body = body # get body width and height widths = []; heights = [] for z in range(body.shape[0]): x_sum = np.sum(body[z, :, :], axis=0) # suma kazdeho sloupcu x_start = next((i for i, x in enumerate(list(x_sum)) if x!=0), None) x_end = next((i for i, x in enumerate(reversed(list(x_sum))) if x!=0), None) if x_start is None or x_end is None: width = 0 else: width = (body.shape[2]-x_end) - x_start widths.append(width) y_sum = np.sum(body[z, :, :], axis=1) # suma kazdeho radku y_start = next((i for i, y in enumerate(list(y_sum)) if y!=0), None) y_end = next((i for i, y in enumerate(reversed(list(y_sum))) if y!=0), None) if y_start is None or y_end is None: height = 0 else: height = (body.shape[1]-y_end) - y_start heights.append(height) # get value which is bigger then 90% of calculated values (to ignore bad data) body_width = np.percentile(np.asarray(widths), 90.0) body_height = np.percentile(np.asarray(heights), 90.0) # convert to original resolution body_width = body_width * (self.orig_shape[2]/float(self.body.shape[2])) body_height = body_height * (self.orig_shape[1]/float(self.body.shape[1])) # conver to mm self.body_width = body_width * float(self.voxelsize_mm[2]) self.body_height = body_height * float(self.voxelsize_mm[1]) if skip_resize: return self.body else: return resize_to_shape(self.body, self.orig_shape)
def get_lungs_orig(self, skip_resize=False): lungs_density_threshold_hu = -150 lungs = scipy.ndimage.filters.gaussian_filter(self.data3dr, sigma=[4, 2, 2]) > lungs_density_threshold_hu if self.head_first: bottom_slice_id = -1 else: bottom_slice_id = 0 lungs[bottom_slice_id, :, :] = 1 lungs = scipy.ndimage.morphology.binary_fill_holes(lungs) labs, n = scipy.ndimage.measurements.label(lungs==0) cornerlab = [ labs[0,0,0], labs[0,0,-1], labs[0,-1,0], labs[0,-1,-1], labs[-1,0,0], labs[-1,0,-1], labs[-1,-1,0], labs[-1,-1,-1] ] lb = np.median(cornerlab) labs[labs==lb] = 0 labs[labs==labs[0,0,0]] = 0 labs[labs==labs[0,0,-1]] = 0 labs[labs==labs[0,-1,0]] = 0 labs[labs==labs[0,-1,-1]] = 0 labs[labs==labs[-1,0,0]] = 0 labs[labs==labs[-1,0,-1]] = 0 labs[labs==labs[-1,-1,0]] = 0 labs[labs==labs[-1,-1,-1]] = 0 lungs = labs > 0 self.lungs = lungs #self.body = (labs == 80) if skip_resize: return self.lungs else: return resize_to_shape(lungs, self.orig_shape)
def uncrop(data, crinfo, orig_shape, resize=False): crinfo = fix_crinfo(crinfo) data_out = np.zeros(orig_shape, dtype=data.dtype) # print 'uncrop ', crinfo # print orig_shape # print data.shape if resize: data = resize_to_shape(data, crinfo[:, 1] - crinfo[:, 0]) startx = np.round(crinfo[0][0]).astype(int) starty = np.round(crinfo[1][0]).astype(int) startz = np.round(crinfo[2][0]).astype(int) data_out[ # np.round(crinfo[0][0]).astype(int):np.round(crinfo[0][1]).astype(int)+1, # np.round(crinfo[1][0]).astype(int):np.round(crinfo[1][1]).astype(int)+1, # np.round(crinfo[2][0]).astype(int):np.round(crinfo[2][1]).astype(int)+1 startx:startx + data.shape[0], starty:starty + data.shape[1], startz:startz + data.shape[2]] = data return data_out
def get_diaphragm_mask(self, axis=0): if self.lungs is None: self.get_lungs() ia, ib, ic = self._get_ia_ib_ic(axis) data = self.lungs ou = self.get_diaphragm_profile_image(axis=axis) # reconstruction mask array mask = np.zeros(data.shape) for i in range(mask.shape[ia]): if ia == 0: mask[i, :, :] = ou > i elif ia == 1: mask[:, i, :] = ou > i elif ia == 2: mask[:, :, i] = ou > i self.diaphragm_mask = mask # maximal point is used for axial ze # ro plane self.diaphragm_mask_level = np.median(ou) self.center0 = self.diaphragm_mask_level * self.working_vs[0] return resize_to_shape(self.diaphragm_mask, self.orig_shape)
def get_diaphragm_mask(self, axis=0, skip_resize=False): """ Get False in inferior to diaphragm and True in superior to diaphragm. :param axis: :param skip_resize: :return: Boolean 3D ndarray """ if self.lungs is None: self.get_lungs() ia, ib, ic = self._get_ia_ib_ic(axis) data = self.lungs ou = self.get_diaphragm_profile_image(axis=axis) # reconstruction mask array mask = np.zeros(data.shape) for i in range(mask.shape[ia]): if ia == 0: mask[i,:,:] = ou > i elif ia == 1: mask[:,i,:] = ou > i elif ia == 2: mask[:,:,i] = ou > i if not self.head_first: # invert mask mask = mask == False self.diaphragm_mask = mask # maximal point is used for axial ze # ro plane self.diaphragm_mask_level = np.median(ou) self.center0 = self.diaphragm_mask_level * self.working_vs[0] if skip_resize: return self.diaphragm_mask return resize_to_shape(self.diaphragm_mask, self.orig_shape)
def get_lungs_martin(self): ''' Improved version of get.lungs function. Call with ss.get_lungs if get_lungs_martin is default. first part checks if the CT-bed enables a clear segmentation of the background. Then we threshold and label all cavities. After that, we compare the mean value of the real grayscale-image in these labeled areas and only take the brighter ones. (Because in lung areas there are "white" alveoli) ''' lungs = scipy.ndimage.filters.gaussian_filter(self.data3dr, sigma=[4, 2, 2]) > -450 lungs[0, :, :] = 1 lungs = scipy.ndimage.morphology.binary_fill_holes(lungs) labs, n = scipy.ndimage.measurements.label(lungs == 0) cornerlab = [ labs[0, 0, 0], labs[0, 0, -1], labs[0, -1, 0], labs[0, -1, -1], labs[-1, 0, 0], labs[-1, 0, -1], labs[-1, -1, 0], labs[-1, -1, -1] ] lb = np.median(cornerlab) labs[labs == lb] = 0 labs[labs == labs[0, 0, 0]] = 0 labs[labs == labs[0, 0, -1]] = 0 labs[labs == labs[0, -1, 0]] = 0 labs[labs == labs[0, -1, -1]] = 0 labs[labs == labs[-1, 0, 0]] = 0 labs[labs == labs[-1, 0, -1]] = 0 labs[labs == labs[-1, -1, 0]] = 0 labs[labs == labs[-1, -1, -1]] = 0 lungs = labs > 0 self.lungs = lungs # self.body = (labs == 80) # new code transformed into function segmented = self.data3dr < -400 preselection_cavities = lungs * segmented #setting the first slice to one to close all of the cavities, so the fill holes works better first_slice = copy.copy(preselection_cavities[-1, :, :]) # -1 means last slice, which is here the uppest in the image preselection_cavities[-1, :, :] = 1 precav_filled = scipy.ndimage.morphology.binary_fill_holes(preselection_cavities) precav_filled[-1, :, :] = first_slice precav_erosion = scipy.ndimage.morphology.binary_erosion(precav_filled) labeled = skimage.morphology.label(precav_erosion) for f in range(1, np.max(labeled) + 1): cavity = self.data3dr[labeled == f] cavity_mean_intensity = np.std(cavity) if cavity_mean_intensity > 50: #not too sure about the value of 50 #idea would be to take the mean value of the highest ones and set the little lower one as the limit # this sets not lung-areas to zero. Theoretically :D precav_erosion[labeled == f] = 0 #print(cavity_mean_intensity) precav_erosion = scipy.ndimage.morphology.binary_dilation(precav_filled) #dilation becuase of erosion before # return precav_erosion self.lungs = precav_erosion return resize_to_shape(precav_erosion, self.orig_shape)
def _resize_to_orig_shape(self, data): return resize_to_shape(data, self.orig_shape)
def dist_to_lungs(self): if self.lungs is None: self.get_lungs() ld = scipy.ndimage.morphology.distance_transform_edt(1 - self.lungs) ld = ld*float(self.working_vs[0]) # convert distances to mm return resize_to_shape(ld, self.orig_shape)
def dist_to_spine(self): if self.spine_wvs is None: self.get_spine(skip_resize=True) ld = scipy.ndimage.morphology.distance_transform_edt(1 - self.spine_wvs) ld = ld*float(self.working_vs[0]) # convert distances to mm return resize_to_shape(ld, self.orig_shape)
def dist_to_surface(self): if self.body is None: self.get_body() ld = scipy.ndimage.morphology.distance_transform_edt(self.body) ld = ld * float(self.working_vs[0]) # convert distances to mm return resize_to_shape(ld, self.orig_shape)
def get_lungs_martin(self): ''' Improved version of get.lungs function. Call with ss.get_lungs if get_lungs_martin is default. first part checks if the CT-bed enables a clear segmentation of the background. Then we threshold and label all cavities. After that, we compare the mean value of the real grayscale-image in these labeled areas and only take the brighter ones. (Because in lung areas there are "white" alveoli) ''' lungs = scipy.ndimage.filters.gaussian_filter(self.data3dr, sigma=[4, 2, 2]) > -450 lungs[0, :, :] = 1 lungs = scipy.ndimage.morphology.binary_fill_holes(lungs) labs, n = scipy.ndimage.measurements.label(lungs == 0) cornerlab = [ labs[0, 0, 0], labs[0, 0, -1], labs[0, -1, 0], labs[0, -1, -1], labs[-1, 0, 0], labs[-1, 0, -1], labs[-1, -1, 0], labs[-1, -1, -1] ] lb = np.median(cornerlab) labs[labs == lb] = 0 labs[labs == labs[0, 0, 0]] = 0 labs[labs == labs[0, 0, -1]] = 0 labs[labs == labs[0, -1, 0]] = 0 labs[labs == labs[0, -1, -1]] = 0 labs[labs == labs[-1, 0, 0]] = 0 labs[labs == labs[-1, 0, -1]] = 0 labs[labs == labs[-1, -1, 0]] = 0 labs[labs == labs[-1, -1, -1]] = 0 lungs = labs > 0 self.lungs = lungs # self.body = (labs == 80) # new code transformed into function segmented = self.data3dr < -400 preselection_cavities = lungs * segmented #setting the first slice to one to close all of the cavities, so the fill holes works better first_slice = copy.copy( preselection_cavities[-1, :, :] ) # -1 means last slice, which is here the uppest in the image preselection_cavities[-1, :, :] = 1 precav_filled = scipy.ndimage.morphology.binary_fill_holes( preselection_cavities) precav_filled[-1, :, :] = first_slice precav_erosion = scipy.ndimage.morphology.binary_erosion(precav_filled) labeled = skimage.morphology.label(precav_erosion) for f in range(1, np.max(labeled) + 1): cavity = self.data3dr[labeled == f] cavity_mean_intensity = np.std(cavity) if cavity_mean_intensity > 50: #not too sure about the value of 50 #idea would be to take the mean value of the highest ones and set the little lower one as the limit # this sets not lung-areas to zero. Theoretically :D precav_erosion[labeled == f] = 0 #print(cavity_mean_intensity) precav_erosion = scipy.ndimage.morphology.binary_dilation( precav_filled) #dilation becuase of erosion before # return precav_erosion self.lungs = precav_erosion return resize_to_shape(precav_erosion, self.orig_shape)