def test_morphsnakes_incorrect_ndim(): img = np.zeros((4, 4, 4, 4)) ls = np.zeros((4, 4, 4, 4)) with testing.raises(ValueError): morphological_chan_vese(img, iterations=1, init_level_set=ls) with testing.raises(ValueError): morphological_geodesic_active_contour(img, iterations=1, init_level_set=ls)
def test_morphsnakes_simple_shape_chan_vese(): img = gaussian_blob() ls1 = circle_level_set(img.shape, (5, 5), 3) ls2 = circle_level_set(img.shape, (5, 5), 6) acwe_ls1 = morphological_chan_vese(img, iterations=10, init_level_set=ls1) acwe_ls2 = morphological_chan_vese(img, iterations=10, init_level_set=ls2) assert_array_equal(acwe_ls1, acwe_ls2) assert acwe_ls1.dtype == acwe_ls2.dtype == np.int8
def test_init_level_sets(): image = np.zeros((6, 6)) checkerboard_ls = morphological_chan_vese(image, 0, 'checkerboard') checkerboard_ref = np.array([[0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 0]], dtype=np.int8) disk_ls = morphological_geodesic_active_contour(image, 0, 'disk') disk_ref = np.array([[0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1], [0, 1, 1, 1, 1, 1], [0, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 0]], dtype=np.int8) assert_array_equal(checkerboard_ls, checkerboard_ref) assert_array_equal(disk_ls, disk_ref)
def test_init_level_sets(): image = np.zeros((6, 6)) checkerboard_ls = morphological_chan_vese(image, 0, 'checkerboard') checkerboard_ref = np.array([[0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 0]], dtype=np.int8) circle_ls = morphological_geodesic_active_contour(image, 0, 'circle') circle_ref = np.array([[0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1], [0, 1, 1, 1, 1, 1], [0, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 0]], dtype=np.int8) assert_array_equal(checkerboard_ls, checkerboard_ref) assert_array_equal(circle_ls, circle_ref)
def test_morphsnakes_3d(): image = np.zeros((7, 7, 7)) evolution = [] def callback(x): evolution.append(x.sum()) ls = morphological_chan_vese(image, 5, 'circle', iter_callback=callback) # Check that the initial circle level set is correct assert evolution[0] == 81 # Check that the final level set is correct assert ls.sum() == 0 # Check that the contour is shrinking at every iteration for v1, v2 in zip(evolution[:-1], evolution[1:]): assert v1 >= v2
def test_morphsnakes_3d(): image = np.zeros((7, 7, 7)) evolution = [] def callback(x): evolution.append(x.sum()) ls = morphological_chan_vese(image, 5, 'circle', iter_callback=callback) # Check that the initial circle level set is correct assert evolution[0] == 81 # Check that the final level set is correct assert ls.sum() == 0 # Check that the contour is shrinking at every iteration for v1, v2 in zip(evolution[:-1], evolution[1:]): assert v1 >= v2
def morphChaneVese(image, itr=120, p=3): """ calculate the segmentation mask of the image using morphological_chan_vese built in function. Args: img: RGB image to calculate the segmentation mask over it. itr: number of iterations used to get the segmentation mask, default = 120. p: square width of the initial segmentation mask, default = 3. Returns: Binary image represents the filled object. """ image = copy.deepcopy(image) #turn RGB image to gray scaled one. image = rgb2gray(image) #apply hestogram equalization to enhance the image. image = equalize_hist(image) #set the initial segmentation mask base on p value. init_ls = checkerboard_level_set(image.shape, p) #calculate the mask using morphological_chan_vese algorithm. mask = morphological_chan_vese(image, iterations=itr, init_level_set=init_ls, smoothing=2) #return the calculated mask return mask
def test_morphsnakes_black(): img = np.zeros((11, 11)) ls = circle_level_set(img.shape, (5, 5), 3) ref_zeros = np.zeros(img.shape, dtype=np.int8) ref_ones = np.ones(img.shape, dtype=np.int8) acwe_ls = morphological_chan_vese(img, iterations=6, init_level_set=ls) assert_array_equal(acwe_ls, ref_zeros) gac_ls = morphological_geodesic_active_contour(img, iterations=6, init_level_set=ls) assert_array_equal(gac_ls, ref_zeros) gac_ls2 = morphological_geodesic_active_contour(img, iterations=6, init_level_set=ls, balloon=1, threshold=-1, smoothing=0) assert_array_equal(gac_ls2, ref_ones) assert acwe_ls.dtype == gac_ls.dtype == gac_ls2.dtype == np.int8
def test_morphsnakes_black(): img = np.zeros((11, 11)) ls = disk_level_set(img.shape, center=(5, 5), radius=3) ref_zeros = np.zeros(img.shape, dtype=np.int8) ref_ones = np.ones(img.shape, dtype=np.int8) acwe_ls = morphological_chan_vese(img, num_iter=6, init_level_set=ls) assert_array_equal(acwe_ls, ref_zeros) gac_ls = morphological_geodesic_active_contour(img, num_iter=6, init_level_set=ls) assert_array_equal(gac_ls, ref_zeros) gac_ls2 = morphological_geodesic_active_contour(img, num_iter=6, init_level_set=ls, balloon=1, threshold=-1, smoothing=0) assert_array_equal(gac_ls2, ref_ones) assert acwe_ls.dtype == gac_ls.dtype == gac_ls2.dtype == np.int8
def segment_with_level_sets(img): """ Function to perform segmentation with level sets. img_gray should not contain hairs nor black zones Parameters ---------- binary Binary mask with result of level sets Returns ------- output_image Binary image with segmentation result """ #First, find out if it is necessary to appy inpainting to remove black zones img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) r1 = img_gray[:5, :5] r2 = img_gray[:5, -5:] r3 = img_gray[-5:, :5] r4 = img_gray[-5:, -5:] if (np.mean(r1) < 50 or np.mean(r2) < 50 or np.mean(r3) < 50 or np.mean(r4) < 50 ): #If zones of the corners are too dark, apply ellipse inpainting elliptical_mask = 1 - mask_eliptical(img_gray) to_process = cv.inpaint(img_gray, elliptical_mask, 21, cv.INPAINT_NS) else: to_process = img_gray init_ls = checkerboard_level_set(img_gray.shape, 6) ls = morphological_chan_vese(to_process, 35, init_level_set=init_ls, smoothing=3) segmented = find_segmented(ls) return segmented
def supercluster(self, clustered_data): #print ("clu data = ",clustered_data) gimage = inverse_gaussian_gradient(clustered_data, 10, 1.5) print("Fatto") # Initial level set # this makes alternate squares active at the first iteration of 10 macro-pixels #init_ls = checkerboard_level_set(clustered_data.shape, 10) init_ls = np.zeros(clustered_data.shape, dtype=np.int8) init_ls[10:-10, 10:-10] = 1 # List with intermediate results for plotting the evolution #evolution = [] #callback = self.store_evolution_in(evolution) #ls = morphological_geodesic_active_contour(gimage, 400, init_ls, # smoothing=1, balloon=-1, # threshold=0.6) #iter_callback=callback) ls = morphological_chan_vese(gimage, 400, init_ls, smoothing=1, lambda1=8., lambda2=10.) print("Bene!") return ls
def get_snake(file, plot=False): def store_evolution_in(lst): def _store(x): lst.append(np.copy(x)) return _store evolution = [] callback = store_evolution_in(evolution) raster_filepath = os.path.dirname(file) + "/" raster_filename = os.path.basename(file) with rasterio.open(file, driver='GTiff') as src: kwargs = src.meta kwargs.update(count=1, dtype=rasterio.uint8) input = src.read(1).astype(rasterio.uint8) if plot: plt.imshow(input, cmap='gray') plt.show() init_lvl_set = checkerboard_level_set(input.shape) lvl_set = morphological_chan_vese(input, 100, init_level_set=init_lvl_set, iter_callback=callback, smoothing=1) if plot: plt.imshow(lvl_set, cmap='gray') plt.show() noise_reduced = morph_transform(lvl_set.astype(rasterio.uint8), 9, 9) if plot: plt.imshow(noise_reduced) plt.show() out_filename = raster_filepath + raster_filename.split( sep=".")[0] + "_chan_vese.tif" with rasterio.open(out_filename, 'w', **kwargs) as dst: dst.write_band(1, noise_reduced.astype(rasterio.uint8)) return lvl_set
def create(imgg, Buffer, Buffer_images): img2 = cv2.cvtColor(imgg, cv2.COLOR_BGR2GRAY) # img2 = cv2.equalizeHist(img2) kp2, des2 = orb.detectAndCompute(img2, None) points = np.array([[[1, 1]]]) for i in range(13): img1 = Buffer_images[i] ii = i kp1, des1 = orb.detectAndCompute(img1, None) matches1 = bf.match(des1, des2) matches1 = sorted(matches1, key=lambda x: x.distance) matches = matches1[:50] good_new = np.array([[[1, 1]]]) good_old = np.array([[[1, 1]]]) for i in range(0, len(matches)): # print('VLEZE VO TOCKI') x = np.float32(kp1[matches[i].queryIdx].pt[0]) y = np.float32(kp1[matches[i].queryIdx].pt[1]) good_new = np.append(good_new, [[[x, y]]], axis=0) x = np.float32(kp2[matches[i].trainIdx].pt[0]) y = np.float32(kp2[matches[i].trainIdx].pt[1]) good_old = np.append(good_old, [[[x, y]]], axis=0) good_new = np.delete(good_new, 0, 0) good_old = np.delete(good_old, 0, 0) try: M, mask = cv2.findHomography(good_old, good_new, cv2.RANSAC, ransacReprojThreshold=25) # 15 mask = np.array(mask, dtype=bool) mask = np.invert(mask) newX = np.ma.array(good_old, mask=np.column_stack((mask, mask))) newX = newX[~newX.mask] newX1 = newX.reshape(-1, 1, 2) except: print(ii) points = np.append(points, newX1, axis=0) points, index = np.unique(points, axis=0, return_index=True) new1 = points.reshape(-1, 2) dbscan = cluster.DBSCAN(eps=50, min_samples=20) X = new1 dbscan.fit(X) if hasattr(dbscan, 'labels_'): y_pred = dbscan.labels_.astype(np.int) else: y_pred = dbscan.predict(X) # l1 = X[y_pred == 0, 0] l1 = np.asarray(X[y_pred == 0, 0], dtype=np.uint32) # l2 = X[y_pred == 0, 1] l2 = np.asarray(X[y_pred == 0, 1], dtype=np.uint32) ll1 = len(l1) ll2 = len(l2) if ll1 > 5 and ll1 > 5: points1 = np.asarray([l1, l2]).transpose() hull = ConvexHull(points1, incremental=True) polygon = [] for x, y in points1[hull.vertices]: polygon.append((x, y)) img = Image.new('L', (imgg.shape[1], imgg.shape[0]), 0) ImageDraw.Draw(img).polygon(polygon, outline=1, fill=1) maskSNAKE = np.array(img) frame = imgg.copy() hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) # YCR_CB) a = hsv[:, :, 0] image = img_as_float(a) init_ls = maskSNAKE ker = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (9, 9)) init_ls = cv2.dilate(init_ls, ker, iterations=1) evolution = [] callback = store_evolution_in(evolution) ls1 = morphological_chan_vese(image, 20, init_level_set=init_ls, lambda1=2, lambda2=0.4, smoothing=0, iter_callback=callback) # ls1 = ls ls = ls1.astype(np.uint8) kernel = np.ones((16, 16), np.uint8) kernel1 = np.ones((8, 8), np.uint8) erosion = cv2.morphologyEx(ls, cv2.MORPH_OPEN, kernel) erosion = cv2.erode(erosion, kernel1, iterations=1) # img1 = Image.fromarray(imgg, 'RGB') _, contours, hierarchy = cv2.findContours( erosion, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1) # contours, hierarchy su1 = 0 su2 = 0 # needs to be restructured from here if len(contours) > 0: img_true = np.array(ls1).ravel() img_pred = np.array(erosion).ravel() iou = jaccard_similarity_score( img_true, img_pred) # jaccard_score(img_true, img_pred) print('ENTERED CONTOURS') a = sorted(contours, key=lambda contour: cv2.contourArea(contour), reverse=True) # print(a) # print(cv2.contourArea(a[0])) maxContour = cv2.contourArea(a[0]) maxContourData = a[0] mask = np.zeros_like(erosion) if maxContour > 1: cv2.fillPoly(mask, [maxContourData], 1) su1 = sum(mask[(l2, l1)]) else: iou = None if len(contours) > 1: maxContour1 = cv2.contourArea(a[1]) maxContourData1 = a[1] mask1 = np.zeros_like(erosion) if maxContour1 > 1: cv2.fillPoly(mask1, [maxContourData1], 1) su2 = sum(mask1[(l2, l1)]) if su1 >= su2 and su1 > 20: c = maxContourData c = c.astype(np.float32) elif su2 >= su1 and su2 > 20: c = maxContourData1 c = c.astype(np.float32) else: c = None # to here # template = img2 if c is not None: maxx = np.int0(np.amax(c[:, 0, 0])) minx = np.int0(np.amin(c[:, 0, 0])) maxy = np.int0(np.amax(c[:, 0, 1])) miny = np.int0(np.amin(c[:, 0, 1])) template = img2 * maskSNAKE template = template[miny:maxy, minx:maxx] clusterSize = ll1 kp3, des3 = orb.detectAndCompute(template, None) # Sum of strongest 20 pp = sorted(kp3, key=operator.attrgetter('response'), reverse=True) sum3 = sum(node.response for node in pp[:20]) if len(kp3) > 20: pp = sorted(kp3, key=operator.attrgetter('response'), reverse=True) sum3 = sum(node.response for node in pp[:20]) if ll1 > 0.9 * Buffer["7"][2]: n = 7 name = 'b' + str(n) + '.jpg' cv2.imwrite(name, template) Buffer_images[n] = template Buffer[str(n)] = [len(kp3), sum3, clusterSize] elif ll1 > 0.8 * Buffer["8"][2]: n = 8 name = 'b' + str(n) + '.jpg' cv2.imwrite(name, template) Buffer_images[n] = template Buffer[str(n)] = [len(kp3), sum3, clusterSize] elif ll1 > 0.7 * Buffer["9"][2]: n = 9 name = 'b' + str(n) + '.jpg' cv2.imwrite(name, template) Buffer_images[n] = template Buffer[str(n)] = [len(kp3), sum3, clusterSize] else: clusterSize = 0 return c, iou, Buffer, Buffer_images else: c = None iou = None return c, iou, Buffer, Buffer_images
def coreSegmenterOutput(I, probMap, initialmask, preBlur, findCenter): hsize = int((float(I.shape[0]) * float(0.1))) vsize = int((float(I.shape[1]) * float(0.1))) nucGF = cv2.resize(I, (vsize, hsize), cv2.INTER_CUBIC) # Irs = cv2.resize(I,(vsize,hsize),cv2.INTER_CUBIC) # I=I.astype(np.float) # r,c = I.shape # I+=np.random.rand(r,c)*1e-6 # c1 = uniform_filter(I, 3, mode='reflect') # c2 = uniform_filter(I*I, 3, mode='reflect') # nucGF = np.sqrt(c2 - c1*c1)*np.sqrt(9./8) # nucGF[np.isnan(nucGF)]=0 #active contours hsize = int(float(nucGF.shape[0])) vsize = int(float(nucGF.shape[1])) initialmask = cv2.resize(initialmask, (vsize, hsize), cv2.INTER_NEAREST) initialmask = dilation(initialmask, disk(15)) > 0 # init=np.argwhere(eroded>0) nucGF = gaussian(nucGF, 0.7) nucGF = nucGF / np.amax(nucGF) # initialmask = nucGF>0 nuclearMask = morphological_chan_vese(nucGF, 100, init_level_set=initialmask, smoothing=10, lambda1=1.001, lambda2=1) # nuclearMask = chan_vese(nucGF, mu=1.5, lambda1=6, lambda2=1, tol=0.0005, max_iter=2000, dt=15, init_level_set=initialmask, extended_output=True) # nuclearMask = nuclearMask[0] TMAmask = nuclearMask # nMaskDist =distance_transform_edt(nuclearMask) # fgm = peak_local_max(h_maxima(nMaskDist, 2*preBlur),indices =False) # markers= np.logical_or(erosion(1-nuclearMask,disk(3)),fgm) # TMAmask=watershed(-nMaskDist,label(markers),watershed_line=True) # TMAmask = nuclearMask*(TMAmask>0) TMAmask = remove_small_objects( TMAmask > 0, round(TMAmask.shape[0]) * round(TMAmask.shape[1]) * 0.005) TMAlabel = label(TMAmask) # find object closest to center if findCenter == True: stats = regionprops(TMAlabel) counter = 1 minDistance = -1 index = [] for props in stats: centroid = props.centroid distanceFromCenter = np.sqrt((centroid[0] - nucGF.shape[0] / 2)**2 + (centroid[1] - nucGF.shape[1] / 2)**2) # if distanceFromCenter<0.6/2*np.sqrt(TMAlabel.shape[0]*TMAlabel.shape[1]): if distanceFromCenter < minDistance or minDistance == -1: minDistance = distanceFromCenter index = counter counter = counter + 1 # dist = 0.6/2*np.sqrt(TMAlabel.shape[0]*TMAlabel.shape[1]) TMAmask = morphology.binary_closing(TMAlabel == index, disk(3)) return TMAmask
# Morphological ACWE #image = img_as_float(data.camera()) from skimage import io file_name = 'test3.dcm' image = io.imread(file_name) # Initial level set init_ls = checkerboard_level_set(image.shape, 6) # List with intermediate results for plotting the evolution evolution = [] callback = store_evolution_in(evolution) iteracoes = 35 ls = morphological_chan_vese(image, iteracoes, init_level_set=init_ls, smoothing=1, iter_callback=callback) fig, axes = plt.subplots(2, 2, figsize=(8, 8)) ax = axes.flatten() ax[0].imshow(image, cmap="gray") ax[0].set_axis_off() ax[0].contour(ls, [0.5], colors='r') ax[0].set_title("Morphological ACWE segmentation", fontsize=12) ax[1].imshow(ls, cmap="gray") ax[1].set_axis_off() contour = ax[1].contour(evolution[2], [0.5], colors='g') contour.collections[0].set_label("Iteration 2")
def active_contour(image): def store_evolution_in(lst): def _store(x): lst.append(np.copy(x)) return _store image = img_as_float(data.camera()) init_ls = checkerboard_level_set(image.shape, 6) evolution = [] callback = store_evolution_in(evolution) ls = morphological_chan_vese(image, 35, init_level_set=init_ls, smoothing=3, iter_callback=callback) fig, axes = plt.subplots(2, 2, figsize=(8, 8)) ax = axes.flatten() ax[0].imshow(image, cmap="gray") ax[0].set_axis_off() ax[0].contour(ls, [0.5], colors='r') ax[0].set_title("Morphological ACWE segmentation", fontsize=12) ax[1].imshow(ls, cmap="gray") ax[1].set_axis_off() contour = ax[1].contour(evolution[2], [0.5], colors='g') contour.collections[0].set_label("Iteration 2") contour = ax[1].contour(evolution[7], [0.5], colors='y') contour.collections[0].set_label("Iteration 7") contour = ax[1].contour(evolution[-1], [0.5], colors='r') contour.collections[0].set_label("Iteration 35") ax[1].legend(loc="upper right") title = "Morphological ACWE evolution" ax[1].set_title(title, fontsize=12) image = img_as_float(data.coins()) gimage = inverse_gaussian_gradient(image) init_ls = np.zeros(image.shape, dtype=np.int8) init_ls[10:-10, 10:-10] = 1 evolution = [] callback = store_evolution_in(evolution) ls = morphological_geodesic_active_contour(gimage, 230, init_ls, smoothing=1, balloon=-1, threshold=0.69, iter_callback=callback) ax[2].imshow(image, cmap="gray") ax[2].set_axis_off() ax[2].contour(ls, [0.5], colors='r') ax[2].set_title("Morphological GAC segmentation", fontsize=12) ax[3].imshow(ls, cmap="gray") ax[3].set_axis_off() contour = ax[3].contour(evolution[0], [0.5], colors='g') contour.collections[0].set_label("Iteration 0") contour = ax[3].contour(evolution[100], [0.5], colors='y') contour.collections[0].set_label("Iteration 100") contour = ax[3].contour(evolution[-1], [0.5], colors='r') contour.collections[0].set_label("Iteration 230") ax[3].legend(loc="upper right") title = "Morphological GAC evolution" ax[3].set_title(title, fontsize=12) fig.tight_layout() plt.show()
def morphological(image): # Morphological ACWE img = img_as_float(skimage.color.rgb2gray(image)) # Initial level set init_ls = checkerboard_level_set(img.shape, 6) # List with intermediate results for plotting the evolution evolution = [] callback = store_evolution_in(evolution) ls = morphological_chan_vese(img, 200, init_level_set=init_ls, smoothing=4, iter_callback=callback) fig, axes = plt.subplots(2, 2, figsize=(8, 8)) ax = axes.flatten() ax[0].imshow(img, cmap="gray") ax[0].set_axis_off() ax[0].contour(ls, [0.5], colors='r') ax[0].set_title("Morphological ACWE segmentation", fontsize=12) ax[1].imshow(ls, cmap="gray") ax[1].set_axis_off() contour = ax[1].contour(evolution[2], [0.5], colors='g') contour.collections[0].set_label("Iteration 2") contour = ax[1].contour(evolution[7], [0.5], colors='y') contour.collections[0].set_label("Iteration 7") contour = ax[1].contour(evolution[-1], [0.5], colors='r') contour.collections[0].set_label("Iteration 35") ax[1].legend(loc="upper right") title = "Morphological ACWE evolution" ax[1].set_title(title, fontsize=12) # Morphological GAC img = img_as_float(skimage.color.rgb2gray(image)) gimage = inverse_gaussian_gradient(img) # Initial level set init_ls = np.zeros(img.shape, dtype=np.int8) init_ls[10:-10, 10:-10] = 1 # List with intermediate results for plotting the evolution evolution = [] callback = store_evolution_in(evolution) ls = morphological_geodesic_active_contour(gimage, 230, init_ls, smoothing=5, balloon=-1, threshold=0.5, iter_callback=callback) ax[2].imshow(img, cmap="gray") ax[2].set_axis_off() ax[2].contour(ls, [0.5], colors='r') ax[2].set_title("Morphological GAC segmentation", fontsize=12) ax[3].imshow(ls, cmap="gray") ax[3].set_axis_off() contour = ax[3].contour(evolution[0], [0.5], colors='g') contour.collections[0].set_label("Iteration 0") contour = ax[3].contour(evolution[100], [0.5], colors='y') contour.collections[0].set_label("Iteration 100") contour = ax[3].contour(evolution[-1], [0.5], colors='r') contour.collections[0].set_label("Iteration 230") ax[3].legend(loc="upper right") title = "Morphological GAC evolution" ax[3].set_title(img, fontsize=12) fig.tight_layout() plt.show()
def run(self): self.beginTaskRun() # Get input 0 : input = self.getInput(0) # Get output : output = self.getOutput(0) # Get parameters : param = self.getParam() # Get image from input/output (numpy array): srcImage = input.getImage() # Convert to grey Image if RGB if len(srcImage.shape) == 3: image = cv2.cvtColor(srcImage, cv2.COLOR_RGB2GRAY) else: image = srcImage # Convert to float imagef = img_as_float(image) # enhances borders if param.mgac_amplification_contour == "Inverse gaussian gradient": gimage = inverse_gaussian_gradient(imagef) else: gimage = imagef # initial level set initlevelSetInput = self.getInput(2) if initlevelSetInput.isDataAvailable(): initlevelSetBinary = initlevelSetInput.getImage() if param.method == "mgac": proc_img = morphological_geodesic_active_contour( gimage, param.mgac_iterations, init_level_set=initlevelSetBinary, smoothing=param.mgac_smoothing, threshold=param.mgac_threshold, balloon=param.mgac_balloon, iter_callback=(lambda callback: self.emitStepProgress() )).astype(np.uint8) * 255 else: proc_img = morphological_chan_vese( gimage, param.mcv_iterations, init_level_set=initlevelSetBinary, smoothing=param.mcv_smoothing, lambda1=param.mcv_lambda1, lambda2=param.mcv_lambda2, iter_callback=(lambda callback: self.emitStepProgress() )).astype(np.uint8) * 255 else: # input graph -> by user / by previous aoperation in worflow graphInput = self.getInput(1) if graphInput.isDataAvailable(): self.createGraphicsMask(imagef.shape[1], imagef.shape[0], graphInput) binImg = self.getGraphicsMask(0) if param.method == "mgac": proc_img = morphological_geodesic_active_contour( gimage, param.mgac_iterations, init_level_set=binImg, smoothing=param.mgac_smoothing, threshold=param.mgac_threshold, balloon=param.mgac_balloon, iter_callback=( lambda callback: self.emitStepProgress())).astype( np.uint8) * 255 else: proc_img = morphological_chan_vese( gimage, param.mcv_iterations, init_level_set=binImg, smoothing=param.mcv_smoothing, lambda1=param.mcv_lambda1, lambda2=param.mcv_lambda2, iter_callback=( lambda callback: self.emitStepProgress())).astype( np.uint8) * 255 else: raise Exception( "No initial level-set given: it must be graphics input or binary image." ) # set output mask binary image output.setImage(proc_img) # add foward input image self.forwardInputImage(0, 1) # Call endTaskRun to finalize process self.endTaskRun()
I = pydicom.dcmread('000001.dcm') I = I.pixel_array x = I.copy() y = x.resize((256, 256)) max = np.amax(I) sigma = 0.08 sigma_est = np.mean(estimate_sigma(I, multichannel=False)) patch_kw = dict(patch_size=5, patch_distance=6, multichannel=False) I = denoise_nl_means(I, h=1.15 * sigma_est, fast_mode=False, **patch_kw) image = np.copy(I) print(image[10, 10]) print(image[100, 150]) print(np.amax(image[50, 190:210])) print(np.amax(image)) max = np.amax(image) eimage = (image * 255 / max)**5 #eimage = image ** (3) init_ls = checkerboard_level_set(image.shape, 6) evolution = [] callback = store_evolution_in(evolution) ls = morphological_chan_vese(eimage, 35, init_level_set=init_ls, smoothing=3, iter_callback=callback) plt.imshow(image, cmap=plt.cm.bone) plt.contour(ls, [0.5], colors='r') plt.show()
def execute(self, arg, trans): # Number of Chan-Vese iterations nIter = 20 std = 1.5 # [mm], original squareSize = 1.5 # [mm] saveMetaImage = False savePNGImage = False # Actual work - now done using SciPy # Gaussian smoothing dx, dy, dz = arg.GetSpacing() sx, sy = std / dx, std / dy smoother = vtk.vtkImageGaussianSmooth() smoother.SetStandardDeviations(sx, sy) smoother.SetDimensionality(2) smoother.SetInputData(arg) smoother.Update() if savePNGImage: writer = vtk.vtkPNGWriter() writer.SetFileName('./output.png') writer.SetInputConnection(smoother.GetOutputPort()) writer.Write() if saveMetaImage: # Save to disk writer = vtk.vtkMetaImageWriter() writer.SetFileName('./output.mhd') writer.SetInputConnection(smoother.GetOutputPort()) writer.Write() smoothedData = smoother.GetOutput() # Convert VTK to NumPy image dims = arg.GetDimensions() vtk_array = smoothedData.GetPointData().GetScalars() nComponents = vtk_array.GetNumberOfComponents() npData = vtk_to_numpy(vtk_array).reshape( dims[2], dims[1], dims[0], nComponents)[:, :, :, 0].reshape(dims[1], dims[0]) # Seed for active contours iSquareSize = int(squareSize / dx) init_ls = checkerboard_level_set(npData.shape, iSquareSize) contours = morphological_chan_vese(npData, nIter, init_level_set=init_ls, smoothing=2) # Add singleton to get 3-dimensional data data = contours[None, :] # Convert Numpy to VTK data importer = vtk.vtkImageImport() importer.SetDataScalarType(vtk.VTK_SIGNED_CHAR) importer.SetDataExtent(0, data.shape[2] - 1, 0, data.shape[1] - 1, 0, data.shape[0] - 1) importer.SetWholeExtent(0, data.shape[2] - 1, 0, data.shape[1] - 1, 0, data.shape[0] - 1) importer.SetImportVoidPointer(data.data) importer.Update() vtkData = importer.GetOutput() vtkData.SetSpacing(smoothedData.GetSpacing()) vtkData.SetOrigin(0, 0, 0) # Contour filter contourFilter = vtk.vtkContourFilter() iso_value = 0.5 contourFilter.SetInputData(vtkData) contourFilter.SetValue(0, iso_value) contourFilter.Update() contourFilter.ReleaseDataFlagOn() # Compute normals normals = vtk.vtkPolyDataNormals() normals.SetInputConnection(contourFilter.GetOutputPort()) normals.SetFeatureAngle(60.0) normals.ReleaseDataFlagOn() # Join line segments stripper = vtk.vtkStripper() stripper.SetInputConnection(normals.GetOutputPort()) stripper.ReleaseDataFlagOn() stripper.Update() # Transform data from scaled screen to world coordinates transformFilter = vtk.vtkTransformPolyDataFilter() transformFilter.SetInputConnection(stripper.GetOutputPort()) transformFilter.SetTransform(trans) transformFilter.Update() result = transformFilter.GetOutput() # Emit done with output self.done.emit(result)
def segment_lesion(image, mode="KMeans"): ## Unsupervised Segmentation # K-Means Clustering if (mode == "KMeans"): # K-Means Clustering deim = denoise(cv2.cvtColor(image, cv2.COLOR_RGB2GRAY), weight=150) kmeans = KMeans(n_clusters=2, random_state=0, n_jobs=-1).fit(deim.reshape(-1, 1)) mask = (kmeans.labels_).reshape(deim.shape[0], deim.shape[1]).astype('uint8') # Expectation-Maximization Gaussian Mixture Model elif (mode == "EM"): # K-Means Clustering feature_vector = (denoise(cv2.cvtColor(image, cv2.COLOR_RGB2GRAY), weight=150)).reshape(-1, 1) kmeans = KMeans(n_clusters=2, random_state=0, n_jobs=-1).fit(feature_vector) KMpredict = kmeans.predict(feature_vector) # Expectation Step: Initialization with K-Means KM_BG = feature_vector[KMpredict == 0] KM_FG = feature_vector[KMpredict == 1] # Expectation Step: Mean and Covariance mean_BG = np.mean(KM_BG, axis=0) mean_FG = np.mean(KM_FG, axis=0) covar_BG = np.cov(KM_BG, rowvar=False) covar_FG = np.cov(KM_FG, rowvar=False) # Expectation Step: Prior Probabilities prob_BG = KM_BG.shape[0] / feature_vector.shape[0] prob_FG = KM_FG.shape[0] / feature_vector.shape[0] # Iterative Update min_change = 0.01 max_steps = 5 for i in range(max_steps): # Expectation Step: Probability Density Function PDF_BG = multivariate_normal.pdf(feature_vector, mean=mean_BG, cov=covar_BG) PDF_FG = multivariate_normal.pdf(feature_vector, mean=mean_FG, cov=covar_FG) weights_BG = (prob_BG * PDF_BG) / ((prob_FG * PDF_FG) + (prob_BG * PDF_BG)) weights_FG = (prob_FG * PDF_FG) / ((prob_FG * PDF_FG) + (prob_BG * PDF_BG)) weights = np.concatenate( (weights_BG.reshape(-1, 1), weights_FG.reshape(-1, 1)), axis=1) log_B = sum((np.log(sum(weights)))) # Maximization Step: New Probabilities _, counts = np.unique(np.argmax(weights, axis=1), return_counts=True) prob_BG = counts[0] / feature_vector.shape[0] prob_FG = counts[1] / feature_vector.shape[0] # Maximization Step: New Mean and Covariance mean_BG = (1 / counts[0]) * (weights[:, 0] @ feature_vector) mean_FG = (1 / counts[1]) * (weights[:, 1] @ feature_vector) covar_BG = (1 / counts[0]) * ( weights[:, 0] * np.transpose(feature_vector - mean_BG)) @ ( feature_vector - mean_BG) covar_FG = (1 / counts[1]) * ( weights[:, 1] * np.transpose(feature_vector - mean_FG)) @ ( feature_vector - mean_FG) # Maximization Step: Probability Density Function PDF_BG = multivariate_normal.pdf(feature_vector, mean=mean_BG, cov=covar_BG) PDF_FG = multivariate_normal.pdf(feature_vector, mean=mean_FG, cov=covar_FG) weights_BG = (prob_BG * PDF_BG) / ((prob_FG * PDF_FG) + (prob_BG * PDF_BG)) weights_FG = (prob_FG * PDF_FG) / ((prob_FG * PDF_FG) + (prob_BG * PDF_BG)) weights = np.concatenate( (weights_BG.reshape(-1, 1), weights_FG.reshape(-1, 1)), axis=1) log_N = sum((np.log(sum(weights)))) # Update Trackers, Verify Conditions change_log = np.linalg.norm(log_N - log_B) if (change_log <= min_change): continue else: break # Output Image Reconstruction mask = (np.argmax(weights, axis=1)).reshape(-1, 1) mask = np.reshape(mask, (image.shape[0], image.shape[1])).astype('uint8') # Chan-Vese Active Contours elif (mode == "active_contours"): # Morphological ACWE image = img_as_float(cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)) # Initial level Set init_ls = checkerboard_level_set(image.shape, 6) # List with Intermediate Results for Plotting the Evolution evolution = [] callback = store_evolution_in(evolution) mask = morphological_chan_vese(image, 5, init_level_set=init_ls, smoothing=10, iter_callback=callback).astype(np.uint8) # Watershed elif (mode == "mod_watershed"): ret, thresh = cv2.threshold(cv2.cvtColor(image, cv2.COLOR_RGB2GRAY), 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) kernel = np.ones((3, 3), np.uint8) opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2) sure_bg = cv2.dilate(opening, kernel, iterations=3) dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5) ret, sure_fg = cv2.threshold(dist_transform, 0.01 * dist_transform.max(), 255, 0) ls = np.uint8(sure_fg) / 255 circle_mask = create_circular_mask(image.shape[0], image.shape[1], radius=220) ls = ls * circle_mask # Discard Edge-to-Edge Connected Component large = getLargestCC(ls).astype(np.uint8) if (corner_mean(large) > 1): large = getLargestCC(ls - large).astype(np.uint8) # Post-Process Masks post = ndimage.binary_fill_holes(large, structure=np.ones( (5, 5))).astype(bool) else: print("ERROR: Undefined Segmentation Mode") ## Segmentation Label Selection # Define Target Scope candidate_mask_1 = mask.copy() * create_circular_mask( image.shape[0], image.shape[1], radius=230) candidate_mask_2 = (np.invert(mask.copy()) + 2) * create_circular_mask( image.shape[0], image.shape[1], radius=230) # Compute Area of Convex Hulls convex_hull_1 = convex_hull_image(candidate_mask_1) convex_hull_2 = convex_hull_image(candidate_mask_2) # Set Segmentation Component Labels kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (10, 10)) if (np.sum(convex_hull_1) < np.sum(convex_hull_2)): dilation = cv2.dilate(candidate_mask_1, kernel, iterations=1) mask = ndimage.binary_fill_holes(dilation, structure=np.ones((5, 5))) else: dilation = cv2.dilate(candidate_mask_2, kernel, iterations=1) mask = ndimage.binary_fill_holes(dilation, structure=np.ones((5, 5))) if (np.sum(mask) < 5000): mask = create_circular_mask(image.shape[0], image.shape[1], radius=230) return mask
def _store(x): lst.append(np.copy(x)) return _store # Morphological ACWE image = img_as_float(data.camera()) # Initial level set init_ls = checkerboard_level_set(image.shape, 6) # List with intermediate results for plotting the evolution evolution = [] callback = store_evolution_in(evolution) ls = morphological_chan_vese(image, 35, init_level_set=init_ls, smoothing=3, iter_callback=callback) fig, axes = plt.subplots(2, 2, figsize=(8, 8)) ax = axes.flatten() ax[0].imshow(image, cmap="gray") ax[0].set_axis_off() ax[0].contour(ls, [0.5], colors='r') ax[0].set_title("Morphological ACWE segmentation", fontsize=12) ax[1].imshow(ls, cmap="gray") ax[1].set_axis_off() contour = ax[1].contour(evolution[2], [0.5], colors='g') contour.collections[0].set_label("Iteration 2") contour = ax[1].contour(evolution[7], [0.5], colors='y') contour.collections[0].set_label("Iteration 7")
def action_active_contour(self, label, min_pixels=20, iterations=100): label_img = np.copy(self.frame[..., self.feature]) # get centroid of selected label props = regionprops(np.where(label_img == label, label, 0))[0] # make bounding box size to encompass some background box_height = props['bbox'][2] - props['bbox'][0] y1 = max(0, props['bbox'][0] - box_height // 2) y2 = min(self.project.height, props['bbox'][2] + box_height // 2) box_width = props['bbox'][3] - props['bbox'][1] x1 = max(0, props['bbox'][1] - box_width // 2) x2 = min(self.project.width, props['bbox'][3] + box_width // 2) # relevant region of label image to work on label_img = label_img[y1:y2, x1:x2] # use existing label as initial level set for contour calculations level_set = np.where(label_img == label, 1, 0) # normalize input 2D frame data values to range [0.0, 1.0] adjusted_raw_frame = Normalize()(self.raw_frame[..., self.channel]) predict_area = adjusted_raw_frame[y1:y2, x1:x2] # returns 1 where label is predicted to be based on contouring, 0 background contoured = morphological_chan_vese( predict_area, iterations, init_level_set=level_set ) # contoured area should get original label value contoured_label = contoured * label # contours tend to fit very tightly, a small expansion here works well contoured_label = dilation(contoured_label, disk(3)) # don't want to leave the original (un-contoured) label in the image # never overwrite other labels with new contoured label cond = np.logical_or(label_img == label, label_img == 0) safe_overlay = np.where(cond, contoured_label, label_img) # label must be present in safe_overlay for this to be a valid contour result # very few pixels of contoured label indicate contour prediction not worth keeping pixel_count = np.count_nonzero(safe_overlay == label) if pixel_count < min_pixels: safe_overlay = np.copy(self.frame[y1:y2, x1:x2, self.feature]) # put it back in the full image so can use centroid coords for post-contour cleanup full_frame = np.copy(self.frame[..., self.feature]) full_frame[y1:y2, x1:x2] = safe_overlay # avoid automated label cleanup if centroid (flood seed point) is not the right label if full_frame[int(props['centroid'][0]), int(props['centroid'][1])] != label: img_trimmed = full_frame else: # morphology and logic used by pixel-trimming action, with object centroid as seed contig_cell = flood( image=full_frame, seed_point=(int(props['centroid'][0]), int(props['centroid'][1])), ) # any pixels in img_ann that have value 'label' and are NOT connected to # hole_fill_seed get changed to 0, all other pixels retain their original value img_trimmed = np.where( np.logical_and(np.invert(contig_cell), full_frame == label), 0, full_frame, ) # update image; cell_info should never change as a result of this self.frame[y1:y2, x1:x2, self.feature] = img_trimmed[y1:y2, x1:x2] self.y_changed = True
#init = np.array([r, c]).T smoothed_img = gaussian(img_gray, 4) snake = active_contour(smoothed_img, biggest_contour, alpha=0.001, beta=20, gamma=0.001, w_edge=0) gimage = inverse_gaussian_gradient(img) evolution = [] #callback = store_evolution_in(evolution) ls = morphological_chan_vese(gimage, 230, 'circle', smoothing=3, lambda1=1, lambda2=1) for i in ls: # print(i) img[i[0]][i[1]] = 255 fig, ax = plt.subplots(figsize=(7, 7)) ax.imshow(img, cmap=plt.cm.gray) ax.plot(snake[:, 1], snake[:, 0], '-r', lw=2) ax.contour(ls, [0.5], colors='b') ax.set_xticks([]), ax.set_yticks([]) ax.axis([0, img.shape[1], img.shape[0], 0]) plt.show()
def process(self, args, sigma=0.8, iterations=25, writeback=False): """ use expansive active contours to transform point geometries into best-fit boundary polygons demarking object footprints """ # open centroid shape file centroid = self.openCentroidFile(args.centroid_pathname) # open image file image = self.openImageFile(args.image_pathname) # create footprint shape file footprint = self.createOutputFile(args.out_pathname, image) # check validity of files if centroid is not None and image is not None and footprint is not None: # convert centroid locations to pixel coordinates coords = self.getCentroidImageCoordinates(centroid, image) # random.shuffle( coords ) # for each x, y centroid location for idx, coord in enumerate(coords): # check valid sub-image if coord[0] + self._object_size < image[ 'ds'].RasterXSize and coord[ 1] + self._object_size < image['ds'].RasterYSize: # extract sub-image - check for error sub_image = image['band'].ReadAsArray( coord[0], coord[1], self._object_size, self._object_size) sub_image = gaussian_filter(sub_image, sigma=sigma) sub_image = sub_image / (2 ^ 16 - 1) # define initial state of active contour init_ls = circle_level_set( sub_image.shape, (self._object_halfsize, self._object_halfsize), 5) if writeback is True: # callback for animation ls = morphological_chan_vese( sub_image, iterations=iterations, init_level_set=init_ls, smoothing=1, lambda1=1, lambda2=1, iter_callback=self.visualCallback(sub_image)) else: # callback for animation ls = morphological_chan_vese(sub_image, iterations=iterations, init_level_set=init_ls, smoothing=1, lambda1=1, lambda2=1) # compute simplified polygon polyline = self.getPolyline(ls) # convert polyline to geometry wkt = self.getGeometry(polyline, coord, image['transform']) # create new polygon feature feature = ogr.Feature(footprint['defn']) feature.SetField('id', idx) feature.SetGeometry(ogr.CreateGeometryFromWkt(wkt)) # add feature footprint['layer'].CreateFeature(feature) feature = None # create animated gif if idx == 5 and writeback: imageio.mimsave( 'C:\\Users\\Chris.Williams\\Desktop\\animate.gif', self._images, fps=5, palettesize=64, subrectangles=True) break # delete variables to force write footprint['layer'] = None footprint['ds'] = None # buffer up footprint polygons by 3 metres self.getBufferedPolygons(args.out_pathname, 3) return
def edge_segmentation(img, strength_threshold=8, coherence_threshold=0.5, mode=4, ch_ethreshold=0.8, ws_ethreshold=0.2, ws_mdisk_size=5, ws_mthreshold=20, ws_gdisk_size=2, ws_glevel_threshold=4, cv_ethreshold=0, cv_mu=0.1, cv_lamda_1=0.06, cv_lamda_2=1, cv_tol=1e-3, cv_max_iter=2000, cv_dt=0.52, cv_init_level_set="checkerboard", mcv_init_level_set="edges", mcv_c1=1.0, mcv_c2=1.0, mcv_max_iter=35, mcv_smoothing=1, mcv_sigma=5): IM_SIZE = 400 img = (cv2.resize(img, (IM_SIZE, IM_SIZE))).astype(np.float32) root_n = 5 edges = edge_detection(img, root_n, strength_threshold=strength_threshold, coherence_threshold=coherence_threshold ) # root_n should be odd number #8-0.5 final_image = np.zeros((img.shape[0], img.shape[1])) if mode == 0: # thresholding edges for convex hull with threshold to remove as much noise as possible edges[edges >= ch_ethreshold] = 1 edges[edges < ch_ethreshold] = 0 chull = convex_hull(edges) final_image[:chull.shape[0], :chull.shape[1]] = chull return final_image elif mode == 1: # thresholding edges for watershed on edges with low threshold to include as much edges as possible edges[edges >= ws_ethreshold] = 1 edges[edges < ws_ethreshold] = 0 watershed_edges_bin = watershed_edges(edges) final_image[:watershed_edges_bin.shape[0], :watershed_edges_bin. shape[1]] = watershed_edges_bin return final_image elif mode == 2: edge_chull = edges edge_watershed = edge_chull.copy() # thresholding edges for convex hull with threshold to remove as much noise as possible edge_chull[edge_chull >= ch_ethreshold] = 1 edge_chull[edge_chull < ch_ethreshold] = 0 # thresholding edges for watershed on edges with low threshold to include as much edges as possible edge_watershed[edge_watershed >= ws_ethreshold] = 1 edge_watershed[edge_watershed < ws_ethreshold] = 0 chull = convex_hull(edge_chull) watershed_edges_bin = watershed_edges(edge_watershed, ws_mdisk_size, ws_mthreshold, ws_gdisk_size, ws_glevel_threshold) watershed_cull = chull * watershed_edges_bin[:chull.shape[0], :chull. shape[1]] final_image[:watershed_cull.shape[0], :watershed_cull. shape[1]] = watershed_cull return final_image elif mode == 3: # Feel free to play around with the parameters to see how they impact the result edges[edges != cv_ethreshold] = 1 cv_init_level_set = cv_init_level_set.split(',') cv_init_level = cv_init_level_set[0] if cv_init_level_set[0] == "edges": cv_init_level = edges elif cv_init_level_set[0] == "original gray": cv_init_level = rgb2gray(img) cv_init_level = cv_init_level[:edges.shape[0], :edges.shape[1]] elif cv_init_level_set[0] == "path": cv_init_level = io.imread(cv_init_level_set[1]) cv_init_level = (cv2.resize(cv_init_level, (IM_SIZE, IM_SIZE))).astype(np.float32) cv_init_level = rgb2gray(cv_init_level) cv_init_level = cv_init_level[:edges.shape[0], :edges.shape[1]] cv = chan_vese(edges, mu=cv_mu, lambda1=cv_lamda_1, lambda2=cv_lamda_2, tol=cv_tol, max_iter=cv_max_iter, dt=cv_dt, init_level_set=cv_init_level) mask = cv final_image[:mask.shape[0], :mask.shape[1]] = mask return final_image else: E = np.zeros((img.shape[0], img.shape[1])) E[:edges.shape[0], :edges.shape[1]] = edges mcv_init_level_set = mcv_init_level_set.split(',') mcv_init_level = mcv_init_level_set[0] if mcv_init_level_set[0] == "edges": mcv_init_level = E elif mcv_init_level_set[0] == "original gray": mcv_init_level = rgb2gray(img) elif mcv_init_level_set[0] == "path": mcv_init_level = io.imread(mcv_init_level_set[1]) mcv_init_level = (cv2.resize( mcv_init_level, (IM_SIZE, IM_SIZE))).astype(np.float32) mcv_init_level = rgb2gray(mcv_init_level) mask = mcv_c1 * (gaussian( mcv_c2 * E + morphological_chan_vese(rgb2gray(img), iterations=mcv_max_iter, init_level_set=mcv_init_level, smoothing=mcv_smoothing), sigma=mcv_sigma)) return mask
def morphological_cv(self, image): image = rgb2gray(image) mask = seg.morphological_chan_vese(image, iterations=1000, init_level_set='circle') return mask
# -*- coding: utf-8 -*- """ Created on Thu Jan 9 11:32:08 2020 @author: wjswan524 """ import numpy as np from skimage import segmentation as seg segs = seg.morphological_chan_vese(volred, iterations=3, init_level_set='checkerboard', smoothing=1) segred = np.zeros((713, 642, 924)) for i in range(713): for j in range(642): for k in range(924): segred[i, j, k] = segs[i, j, (k + 20)] pores = 0. solid = 0. for i in range(713): for j in range(642): for k in range(924): if segred[i, j, k] == 0: pores += 1. elif segred[i, j, k] == 1: solid += 1.
resolution[0] *=2 data = data[::2] # if resolution[0] < 2.: # downfac = np.floor(2. / resolution[0]).astype(np.int) # resolution[0] *= downfac # data = data[::downfac] data = median_filter(data, size=1, footprint=get_footprint(3, 2)) data = median_filter(data, size=1, footprint=get_footprint(3, 2)) data = gaussian_filter(data, sigma=[.25, .75,.75]) data = gaussian_filter(data, sigma=[.25, .75,.75]) data = gaussian_filter(data, sigma=[.25, .75,.75]) mask = data > mh.otsu(data, True) factor = .5 contour = morphological_chan_vese(data, iterations=10, init_level_set=mask, smoothing=1, lambda1=1, lambda2=1) contour = dilate(contour) for ii in xrange(len(contour)): contour[ii] = binary_fill_holes(contour[ii]) data = np.invert(data) lab_img = steepest_ascent(data, resolution=resolution, mask=mask, connectivity=2) def merge_labels_euclidean_path_threshold(lab_img, int_img, threshold, upper_distance_limit): # Get coordinates # Get neighbours within radius ''' Single attempt ''' z0, y0, x0 = 33, 323, 93
def level_set3D(data, seed3D, resol, lambda1=1, lambda2=4, smoothing=0, iterations=100, rad=3, method='ACWE', alpha=100, sigma=2, balloon=1): ## init res_fac = resol[1] / resol[ 0] # resolution factor to scale chunk to real dimensions N = 60 # approximately the chunk size (in mm) around nodule num_slices = int(round(N / res_fac)) # number of slices before reg = 30 # window of interest centered around seed point s = seed3D[1:] # 2D seed point for (x,y)-plane num = seed3D[0] # slice number seed point is selected from # apply lungmask on each slice of interest around seed point tmp_data = np.zeros((num_slices, data.shape[1], data.shape[2])) ii = 0 for i in range(data.shape[0]): if (i >= num - int(round(num_slices / 2)) and i <= num + int(round(num_slices / 2)) - 1): mask = lungmask_pro(data[i, :, :].copy()) tmp = data[i, :, :].copy() tmp[mask == 0] = np.amin( tmp ) # OBS: -1024 maybe not far away enough from lung intensities tmp_data[ii, :, :] = tmp.copy() ii += 1 # only apply level set on small volume around seed point -> increases speed and accuracy for fixed number of iterations tmp = tmp_data.copy() tmp = tmp[:, s[0] - reg:s[0] + reg, s[1] - reg:s[1] + reg] # transform chunk to true size (in mm) by stretching the slice-axis relevant to a resolution factor tmp = zoom(tmp.copy(), zoom=[res_fac, 1, 1], order=1) # apply 3D level set from single seed point from initial 3D blob around current seed point inits = circle_level_set(tmp.shape, center=(int(num_slices / 2 * res_fac), reg, reg), radius=rad) # choose between two types of level set methods if method == 'ACWE': tmp = morphological_chan_vese(tmp.copy(), iterations=iterations, init_level_set=inits, smoothing=smoothing, lambda1=lambda1, lambda2=lambda2).astype(int) elif method == 'GAC': tmp = tmp.astype(np.float32) tmp = inverse_gaussian_gradient(tmp, alpha=alpha, sigma=alpha) tmp = morphological_geodesic_active_contour(tmp, iterations=iterations, init_level_set=inits, smoothing=smoothing, threshold='auto', balloon=1) else: print('Please choose a valid method!') return None # if no nodule was segmented, break if (len(np.unique(tmp)) == 1): #print('No nodule was segmented. Try changing parameters...') return None # check if leakage has occured #if ((tmp[0,0,0] > 0) or (tmp[0,0,-1] > 0) or (tmp[0,-1,0] > 0) or (tmp[0,-1,-1] > 0) or (tmp[-1,0,0] > 0) or (tmp[-1,-1,0] > 0) or (tmp[-1,0,-1] > 0) or (tmp[-1,-1,-1] > 0)): # if ((len(np.unique(tmp[0,:,:])) > 1) or (len(np.unique(tmp[:,0,:])) > 1) or (len(np.unique(tmp[:,:,0])) > 1) or # (len(np.unique(tmp[-1,:,:])) > 1) or (len(np.unique(tmp[:,-1,:])) > 1) or (len(np.unique(tmp[:,:,-1])) > 1)): # print("Leakage problems? Growing reached boundaries... Discards segmentation") # return None # only keep segments connected to seed point (blood vessels will hopefully not be connected with nodule after level set, if leakage has occured) labels_tmp = label(tmp.copy()) res = np.zeros(tmp.shape) if (labels_tmp[int(num_slices / 2 * res_fac), reg, reg] > 0): res[labels_tmp == labels_tmp[int(num_slices / 2 * res_fac), reg, reg]] = 1 # need to transform chunk back to original size res = zoom(res.copy(), zoom=[1 / res_fac, 1, 1], order=1) # # just in case some parts are not connected anymore after interpolation -> remove not connected components # labels_tmp = label(res.copy()) # res = np.zeros(res.shape) # if (labels_tmp[int(num_slices/2), reg, reg] > 0): # res[labels_tmp == labels_tmp[int(num_slices/2), reg, reg]] = 1 # get the final nodule mask to the original image stack shape # but handle cases where seed point is selected at ends of image stack, and window is outside of range new_res = np.zeros(data.shape) if (num + int(num_slices / 2) > new_res.shape[0]): new_res[num - int(num_slices / 2):num + int(num_slices / 2), s[0] - reg:s[0] + reg, s[1] - reg:s[1] + reg] = res[:num + int(num_slices / 2) - new_res.shape[0]] elif (num - int(num_slices / 2) < 0): new_res[0:num + int(num_slices / 2), s[0] - reg:s[0] + reg, s[1] - reg:s[1] + reg] = res[:num + int(num_slices / 2)] else: new_res[num - int(np.floor(num_slices / 2)):num + int(np.ceil(num_slices / 2)), s[0] - reg:s[0] + reg, s[1] - reg:s[1] + reg] = res return new_res