def segmentation_smoothing(segmentation, sigma_mm, labels=1, background_label=0, voxelsize_mm=None, volume_blowup=1., slab=None, volume_blowup_criterial_function=None, ): """ Shape of output segmentation is smoothed with gaussian filter. Sigma is computed in mm """ # import scipy.ndimage if voxelsize_mm is None: voxelsize_mm = np.asarray([1., 1., 1.]) if volume_blowup_criterial_function is None: volume_blowup_criterial_function = __volume_blowup_criterial_function sigma = float(sigma_mm) / np.array(voxelsize_mm) # print sigma # from PyQt4.QtCore import pyqtRemoveInputHook # pyqtRemoveInputHook() segmentation_selection = ima.select_labels(segmentation, labels=labels, slab=slab) vol1 = np.sum(segmentation_selection) wvol = vol1 * volume_blowup logger.debug('unique segm ' + str(np.unique(segmentation))) segsmooth = scipy.ndimage.filters.gaussian_filter( segmentation_selection.astype(np.float32), sigma) logger.debug('unique segsmooth ' + str(np.unique(segsmooth))) # import ipdb; ipdb.set_trace() # import pdb; pdb.set_trace() # pyed = sed3.sed3(self.orig_scale_segmentation) # pyed.show() logger.debug('wanted volume ' + str(wvol)) logger.debug('sigma ' + str(sigma)) critf = lambda x: volume_blowup_criterial_function( x, wvol, segsmooth) thr = scipy.optimize.fmin(critf, x0=0.5, disp=False)[0] logger.debug('optimal threshold ' + str(thr)) logger.debug('segsmooth ' + str(np.nonzero(segsmooth))) segmentation_selection = (1.0 * (segsmooth > thr) # self.volume_blowup) ).astype(np.int8) vol2 = np.sum(segmentation_selection) with np.errstate(divide="ignore", invalid="ignore"): logger.debug("volume ratio " + str(vol2 / float(vol1))) # import ipdb; ipdb.set_trace() segmentation_replacement( segmentation, label=labels, segmentation_new=segmentation_selection, background_label=background_label, slab=slab, )
def segmentation_replacement(segmentation, segmentation_new, label, background_label=0, slab=None, label_new=1): """ Remove label from segmentation and put there a new one. :param segmentation: :param segmentation_new: :param label: :param background_label: :param slab: :param label_new: :return: """ segmentation_old = ima.select_labels(segmentation, labels=label, slab=slab) segmentation[segmentation_old] = ima.get_nlabels(slab, background_label) segmentation_new = ima.select_labels(segmentation_new, label_new) segmentation[segmentation_new] = ima.get_nlabels(slab, label) return segmentation
def test_branch_labels_with_gui_just_in_module(self): import lisa.organ_segmentation import io3d # datap = io3d.datasets.generate_abdominal() datap = io3d.datasets.generate_synthetic_liver(return_dataplus=True) oseg = lisa.organ_segmentation.OrganSegmentation() oseg.import_dataplus(datap) labeled_branches = lisa.virtual_resection.label_volumetric_vessel_tree( oseg, "porta") data3d = datap["data3d"] segmentation = datap["segmentation"] slab = datap["slab"] organ_label = "liver" seeds = np.zeros_like(data3d, dtype=np.int) seeds[40, 125, 166] = 1 seeds[40, 143, 130] = 2 seeds[40, 125, 115] = 3 seglabel1 = labeled_branches[seeds == 1][0] seglabel2 = labeled_branches[seeds == 2][0] seglabel3 = labeled_branches[seeds == 3][0] import imma.measure import imma.image_manipulation import imma.image_manipulation as ima # import sed3 # ed = sed3.sed3(labeled_branches) # , contour=datap["segmentation"]) # ed.show() organseg = ima.select_labels(segmentation, organ_label, slab) organ_split, connected = lisa.virtual_resection.split_tissue_on_labeled_tree( labeled_branches, seglabel1, [seglabel2, seglabel3], organseg) # import sed3 # # ed = sed3.sed3(labeled_branches, contour=organ_split) # ed = sed3.sed3(organ_split) # ed.show() self.assertTrue(np.array_equal(np.unique(organ_split), [0, 1, 2])) self.assertGreater(np.sum(organ_split == 0), 1000, "At least some background expected") self.assertGreater(np.sum(organ_split == 1), 1000, "At least some object expected") self.assertGreater(np.sum(organ_split == 2), 1000, "At least some object expected")
def segmentation_replacement( segmentation, segmentation_new, label, background_label=0, slab=None, label_new=1 ): """ Remove label from segmentation and put there a new one. :param segmentation: :param segmentation_new: :param label: :param background_label: :param slab: :param label_new: :return: """ segmentation_old = ima.select_labels(segmentation, labels=label, slab=slab) segmentation[segmentation_old] = ima.get_nlabels(slab, background_label) segmentation_new = ima.select_labels(segmentation_new, label_new) segmentation[segmentation_new] = ima.get_nlabels(slab, label) return segmentation
def split_organ_by_two_vessels(datap, seeds, organ_label=1, seed_label1=1, seed_label2=2, weight1=1, weight2=1): """ Input of function is ndarray with 2 labeled vessels and data. Output is segmented organ by vessls using minimum distance criterium. :param datap: dictionary with 3d data, segmentation, and other information "data3d": 3d-ndarray with intensity data "voxelsize_mm", "segmentation": 3d ndarray with image segmentation "slab": segmentation labels :param seeds: ndarray with same size as data3d 1: first part of portal vein (or defined in seed1_label) 2: second part of portal vein (or defined in seed2_label) :param weight1: distance weight from seed_label1 :param weight2: distance weight from seed_label2 """ weight1 = 1 if weight1 is None else weight1 slab = datap["slab"] segmentation = datap["segmentation"] if type(seed_label1) != list: seed_label1 = [seed_label1] if type(seed_label2) != list: seed_label2 = [seed_label2] # dist se tady počítá od nul jenom v jedničkách dist1 = scipy.ndimage.distance_transform_edt( 1 - ima.select_labels(seeds, seed_label1, slab), # seeds != seed_label1, sampling=datap['voxelsize_mm'] ) dist2 = scipy.ndimage.distance_transform_edt( 1 - ima.select_labels(seeds, seed_label2, slab), # seeds != seed_label2, sampling=datap['voxelsize_mm'] ) # import skfmm # dist1 = skfmm.distance( # labeled != l1, # dx=datap['voxelsize_mm'] # ) # dist2 = skfmm.distance( # labeled != l2, # dx=datap['voxelsize_mm'] # ) # print 'skfmm' # from PyQt4.QtCore import pyqtRemoveInputHook; pyqtRemoveInputHook() # import ipdb; ipdb.set_trace() # from PyQt4.QtCore import pyqtRemoveInputHook # pyqtRemoveInputHook() # import ipdb; ipdb.set_trace() # BREAKPOINT # segm = (dist1 < dist2) * (data['segmentation'] != data['slab']['none']) target_organ_segmentation = ima.select_labels(segmentation, organ_label, slab) segm = ((target_organ_segmentation * ((dist1 / weight1) > (dist2 / weight2))).astype('int8') + target_organ_segmentation.astype('int8')) return segm, dist1, dist2
def split_tissue_on_labeled_tree(labeled_branches, trunk_label, branch_labels, tissue_segmentation, neighbors_list=None, ignore_labels=None, ignore_trunk=True, on_missed_branch="split", ): """ Based on pre-labeled vessel tree split surrounding tissue into two part. The connected sub tree is computed and used internally. :param labeled_branches: ndimage with labeled volumetric vessel tree. :param trunk_label: int :param branch_labels: list of ints :param tissue_segmentation: ndimage with bool type. Organ is True, the rest is False. :param ignore_trunk: True or False :param ignore_labels: list of labels which will be ignored :param on_missed_branch: str, ["split", "organ_label", exception]. Missed label is label directly connected to trunk but with no branch label inside. "split" will ignore mised label. "orig" will leave the original area label. "exception", will throw the exception. :return: """ # bl = lisa.virtual_resection.branch_labels(oseg, "porta") import imma.measure import imma.image_manipulation import imma.image_manipulation as ima if ignore_labels is None: ignore_labels = [] ignore_labels = list(ignore_labels) if ignore_trunk: ignore_labels.append(trunk_label) if neighbors_list is None: exclude = [0] exclude.extend(ignore_labels) neighbors_list = imma.measure.neighbors_list( labeled_branches, None, # [seglabel1, seglabel2, seglabel3], exclude=exclude) #exclude=[imma.image_manipulation.get_nlabels(slab, ["liver"]), 0]) # ex # print(neighbors_list) # find whole branche # segmentations = [None] * len(branch_labels) segmentation = np.zeros_like(labeled_branches, dtype=int) new_branches = [] connected = [None] * len(branch_labels) for i, branch_label in enumerate(branch_labels): import copy ignore_other_branches = copy.copy(branch_labels) ignore_other_branches.pop(i) ignore_labels_i = [0] ignore_labels_i.extend(ignore_other_branches) ignore_labels_i.extend(ignore_labels) connected_i = imma.measure.get_connected_labels( neighbors_list, branch_label, ignore_labels_i) # segmentations[i] = ima.select_labels(labeled_branches, connected_i).astype(np.int8) select = ima.select_labels(labeled_branches, connected_i).astype(np.int8) select = select > 0 if np.max(segmentation[select]) > 0: logger.debug("Missing branch connected to branch and other branch or trunk.") union = (segmentation * select) > 0 segmentation[select] = i + 1 if on_missed_branch == "split": segmentation[union] = 0 elif on_missed_branch == "orig": new_branche_label = len(branch_labels) + len(new_branches) + 1 logger.debug("new branch label {}".format(new_branche_label)) segmentation[union] = new_branche_label new_branches.append(new_branche_label) elif on_missed_branch == "exception": raise ValueError("Missing one vessel") else: raise ValueError("Unknown 'on_missed_label' parameter.") else: segmentation[select] = i + 1 # error # else: # segmentation[select] = i + 1 connected[i] = connected_i seg = segmentation # if np.max(np.sum(segmentations, 0)) > 1: # raise ValueError("Missing one vessel") # # for i, branch_label in enumerate(branch_labels): # segmentations[i] = segmentations[i] * (i + 1) # seg = np.sum(segmentations, 0) # ignore_labels1 = [0, trunk_label, branch_label2] # ignore_labels1.extend(ignore_labels) # ignore_labels2 = [0, trunk_label, branch_label] # ignore_labels2.extend(ignore_labels) # connected2 = imma.measure.get_connected_labels( # neighbors_list, branch_label, ignore_labels1) # connected3 = imma.measure.get_connected_labels( # neighbors_list, branch_label2, ignore_labels2) # # # seg = ima.select_labels(segmentation, organ_label, slab).astype(np.int8) # seg1 = ima.select_labels(labeled_branches, connected2).astype(np.int8) # seg2 = ima.select_labels(labeled_branches, connected3).astype(np.int8) # seg = seg1 + seg2 * 2 # if np.max(seg) > 2: # ValueError("Missing one vessel") dseg = ima.distance_segmentation(seg) logger.debug("output unique labels {}".format(np.unique(dseg))) # organseg = ima.select_labels(segmentation, organ_label, slab).astype(np.int8) dseg[~tissue_segmentation.astype(np.bool)] = 0 return dseg, connected
def split_vessel(datap, seeds, vessel_volume_threshold=0.95, dilatation_iterations=1, input_label="porta", output_label1 = 1, output_label2 = 2, input_seeds_cut_label=1, input_seeds_separate_label=3, input_seeds_label2=None, method="reach volume", ): """ :param datap: data plus format with data3d, segmentation, slab ... :param seeds: 3d ndarray same size as data3d, label 1 is place where should be vessel cuted. Label 2 points to the vessel with output label 1 after the segmentation :param vessel_volume_threshold: this parameter defines the iteration stop rule if method "reach volume is selected :param dilatation_iterations: :param input_label: which vessel should be splited :param output_label1: output label for vessel part marked with right button (if it is used) :param output_label2: ouput label for not-marked vessel part :param method: "separate labels" or "reach volume". The first method needs 3 input seeds and it is more stable. :param input_seeds_separate_label: after the segmentation the object containing this label in seeds would be labeled with output_label1 :param input_seeds_label2: This parameter is usedf the method is "separate labels". After the segmentation the object containing this label in seeds would be labeled with output_label1. :return: """ split_obj0 = (seeds == input_seeds_cut_label).astype(np.int8) split_obj = split_obj0.copy() # numeric_label = imma.get_nlabel(datap["slab"], input_label) if method == "separate labels": input_label = np.max(datap["segmentation"][seeds == input_seeds_label2]) vessels = ima.select_labels(datap["segmentation"], input_label, slab=datap["slab"]) # if type(input_label) is str: # numeric_label = datap['slab'][input_label] # else: # numeric_label = input_label # vessels = datap['segmentation'] == numeric_label vesselstmp = vessels sumall = np.sum(vessels == 1) # split_obj = scipy.ndimage.binary_dilation(split_obj, iterations = 5 ) # vesselstmp = vessels * (1 - split_obj) lab, n_obj = scipy.ndimage.label(vesselstmp) logger.debug("number of objects " + str(n_obj)) # while n_obj < 2 : # dokud neni z celkoveho objektu ustipnuto alespon 80 procent not_complete = True while not_complete: if method == "reach volume": not_complete = np.sum(lab == qmisc.max_area_index(lab, n_obj)) > (vessel_volume_threshold * sumall) elif method == "separate labels": # misc. # imma.get_nlabel(datap["slab"], ) # imma.select_labels(seeds,input_seeds_separate_label) seglab1 = np.max(lab[seeds == input_seeds_separate_label]) seglab2 = np.max(lab[seeds == input_seeds_label2]) if (seglab1 > 0) and (seglab2 > 0) and (seglab1 != seglab2): not_complete = False else: IOError("Unknown method " + str(method)) split_obj = scipy.ndimage.binary_dilation(split_obj, iterations=dilatation_iterations) vesselstmp = vessels * (1 - split_obj) lab, n_obj = scipy.ndimage.label(vesselstmp) if method == "reach volume": # všechny objekty, na které se to rozpadlo # pyed = sed3.sed3(lab) # pyed.show() obj1 = get_biggest_object(lab) # vymaz nejvetsiho lab[obj1 == 1] = 0 obj2 = get_biggest_object(lab) pixel = 0 pixels = obj1[seeds == input_seeds_separate_label] if len(pixels) > 0: pixel = pixels[0] # from PyQt4.QtCore import pyqtRemoveInputHook # pyqtRemoveInputHook() # import ipdb; ipdb.set_trace() # BREAKPOINT if pixel > 0: ol1 = output_label1 ol2 = output_label2 else: ol2 = output_label1 ol1 = output_label2 # first selected pixel with right button lab = ol1 * obj1 + ol2 * obj2 elif method == "separate labels": lab = (lab == seglab1) * output_label1 + (lab == seglab2) * output_label2 cut_by_user = split_obj0 return lab, cut_by_user
def split_organ_by_two_vessels(datap, seeds, organ_label=1, seed_label1=1, seed_label2=2, weight1=1, weight2=1): """ Input of function is ndarray with 2 labeled vessels and data. Output is segmented organ by vessls using minimum distance criterium. :param datap: dictionary with 3d data, segmentation, and other information "data3d": 3d-ndarray with intensity data "voxelsize_mm", "segmentation": 3d ndarray with image segmentation "slab": segmentation labels :param seeds: ndarray with same size as data3d 1: first part of portal vein (or defined in seed1_label) 2: second part of portal vein (or defined in seed2_label) :param weight1: distance weight from seed_label1 :param weight2: distance weight from seed_label2 """ weight1 = 1 if weight1 is None else weight1 slab = datap["slab"] segmentation = datap["segmentation"] if type(seed_label1) != list: seed_label1 = [seed_label1] if type(seed_label2) != list: seed_label2 = [seed_label2] # dist se tady počítá od nul jenom v jedničkách dist1 = scipy.ndimage.distance_transform_edt( 1 - ima.select_labels(seeds, seed_label1, slab), # seeds != seed_label1, sampling=datap['voxelsize_mm']) dist2 = scipy.ndimage.distance_transform_edt( 1 - ima.select_labels(seeds, seed_label2, slab), # seeds != seed_label2, sampling=datap['voxelsize_mm']) # import skfmm # dist1 = skfmm.distance( # labeled != l1, # dx=datap['voxelsize_mm'] # ) # dist2 = skfmm.distance( # labeled != l2, # dx=datap['voxelsize_mm'] # ) # print 'skfmm' # from PyQt4.QtCore import pyqtRemoveInputHook; pyqtRemoveInputHook() # import ipdb; ipdb.set_trace() # from PyQt4.QtCore import pyqtRemoveInputHook # pyqtRemoveInputHook() # import ipdb; ipdb.set_trace() # BREAKPOINT # segm = (dist1 < dist2) * (data['segmentation'] != data['slab']['none']) target_organ_segmentation = ima.select_labels(segmentation, organ_label, slab) segm = ((target_organ_segmentation * ((dist1 / weight1) > (dist2 / weight2))).astype('int8') + target_organ_segmentation.astype('int8')) return segm, dist1, dist2
def split_tissue_on_bifurcation( labeled_branches, trunk_label, branch_labels, tissue_segmentation, neighbors_list=None, ignore_labels=None, ignore_trunk=True, ): """ Based on pre-labeled vessel tree split surrounding tissue into two part. The connected sub tree is computed and used internally. :param labeled_branches: ndimage with labeled volumetric vessel tree. :param trunk_label: int :param branch_labels: list of ints :param tissue_segmentation: ndimage with bool type. Organ is True, the rest is False. :param ignore_trunk: True or False :param ignore_labels: list of labels which will be ignored :return: """ # bl = lisa.virtual_resection.branch_labels(oseg, "porta") import imma.measure import imma.image_manipulation import imma.image_manipulation as ima if ignore_labels is None: ignore_labels = [] ignore_labels = list(ignore_labels) if ignore_trunk: ignore_labels.append(trunk_label) if neighbors_list is None: exclude = [0] exclude.extend(ignore_labels) neighbors_list = imma.measure.neighbors_list( labeled_branches, None, # [seglabel1, seglabel2, seglabel3], exclude=exclude) #exclude=[imma.image_manipulation.get_nlabels(slab, ["liver"]), 0]) # ex # print(neighbors_list) # find whole branche segmentations = [None] * len(branch_labels) connected = [None] * len(branch_labels) for i, branch_label in enumerate(branch_labels): import copy ignore_other_branches = copy.copy(branch_labels) ignore_other_branches.pop(i) ignore_labels_i = [0] ignore_labels_i.extend(ignore_other_branches) ignore_labels_i.extend(ignore_labels) connected_i = imma.measure.get_connected_labels( neighbors_list, branch_label, ignore_labels_i) segmentations[i] = ima.select_labels(labeled_branches, connected_i).astype(np.int8) connected[i] = connected_i if np.max(np.sum(segmentations, 0)) > 1: ValueError("Missing one vessel") for i, branch_label in enumerate(branch_labels): segmentations[i] = segmentations[i] * (i + 1) seg = np.sum(segmentations, 0) # ignore_labels1 = [0, trunk_label, branch_label2] # ignore_labels1.extend(ignore_labels) # ignore_labels2 = [0, trunk_label, branch_label] # ignore_labels2.extend(ignore_labels) # connected2 = imma.measure.get_connected_labels( # neighbors_list, branch_label, ignore_labels1) # connected3 = imma.measure.get_connected_labels( # neighbors_list, branch_label2, ignore_labels2) # # # seg = ima.select_labels(segmentation, organ_label, slab).astype(np.int8) # seg1 = ima.select_labels(labeled_branches, connected2).astype(np.int8) # seg2 = ima.select_labels(labeled_branches, connected3).astype(np.int8) # seg = seg1 + seg2 * 2 # if np.max(seg) > 2: # ValueError("Missing one vessel") dseg = ima.distance_segmentation(seg) # organseg = ima.select_labels(segmentation, organ_label, slab).astype(np.int8) dseg[~tissue_segmentation.astype(np.bool)] = 0 return dseg, connected
def split_vessel( datap, seeds, vessel_volume_threshold=0.95, dilatation_iterations=1, input_label="porta", output_label1=1, output_label2=2, input_seeds_cut_label=1, input_seeds_separate_label=3, input_seeds_label2=None, method="reach volume", ): """ :param datap: data plus format with data3d, segmentation, slab ... :param seeds: 3d ndarray same size as data3d, label 1 is place where should be vessel cuted. Label 2 points to the vessel with output label 1 after the segmentation :param vessel_volume_threshold: this parameter defines the iteration stop rule if method "reach volume is selected :param dilatation_iterations: :param input_label: which vessel should be splited :param output_label1: output label for vessel part marked with right button (if it is used) :param output_label2: ouput label for not-marked vessel part :param method: "separate labels" or "reach volume". The first method needs 3 input seeds and it is more stable. :param input_seeds_separate_label: after the segmentation the object containing this label in seeds would be labeled with output_label1 :param input_seeds_label2: This parameter is usedf the method is "separate labels". After the segmentation the object containing this label in seeds would be labeled with output_label1. :return: """ split_obj0 = (seeds == input_seeds_cut_label).astype(np.int8) split_obj = split_obj0.copy() # numeric_label = imma.get_nlabel(datap["slab"], input_label) if method == "separate labels": input_label = np.max( datap["segmentation"][seeds == input_seeds_label2]) vessels = ima.select_labels(datap["segmentation"], input_label, slab=datap["slab"]) # if type(input_label) is str: # numeric_label = datap['slab'][input_label] # else: # numeric_label = input_label # vessels = datap['segmentation'] == numeric_label vesselstmp = vessels sumall = np.sum(vessels == 1) # split_obj = scipy.ndimage.binary_dilation(split_obj, iterations = 5 ) # vesselstmp = vessels * (1 - split_obj) lab, n_obj = scipy.ndimage.label(vesselstmp) logger.debug("number of objects " + str(n_obj)) # while n_obj < 2 : # dokud neni z celkoveho objektu ustipnuto alespon 80 procent not_complete = True while not_complete: if method == "reach volume": not_complete = np.sum(lab == qmisc.max_area_index(lab, n_obj)) > ( vessel_volume_threshold * sumall) elif method == "separate labels": # misc. # imma.get_nlabel(datap["slab"], ) # imma.select_labels(seeds,input_seeds_separate_label) seglab1 = np.max(lab[seeds == input_seeds_separate_label]) seglab2 = np.max(lab[seeds == input_seeds_label2]) if (seglab1 > 0) and (seglab2 > 0) and (seglab1 != seglab2): not_complete = False else: IOError("Unknown method " + str(method)) split_obj = scipy.ndimage.binary_dilation( split_obj, iterations=dilatation_iterations) vesselstmp = vessels * (1 - split_obj) lab, n_obj = scipy.ndimage.label(vesselstmp) if method == "reach volume": # všechny objekty, na které se to rozpadlo # pyed = sed3.sed3(lab) # pyed.show() obj1 = get_biggest_object(lab) # vymaz nejvetsiho lab[obj1 == 1] = 0 obj2 = get_biggest_object(lab) pixel = 0 pixels = obj1[seeds == input_seeds_separate_label] if len(pixels) > 0: pixel = pixels[0] # from PyQt4.QtCore import pyqtRemoveInputHook # pyqtRemoveInputHook() # import ipdb; ipdb.set_trace() # BREAKPOINT if pixel > 0: ol1 = output_label1 ol2 = output_label2 else: ol2 = output_label1 ol1 = output_label2 # first selected pixel with right button lab = ol1 * obj1 + ol2 * obj2 elif method == "separate labels": lab = (lab == seglab1) * output_label1 + (lab == seglab2) * output_label2 cut_by_user = split_obj0 return lab, cut_by_user