def foreground(img,save_folder,v,inumber): try: h = ex.equalize_hist(img[:,:])*255 oi = np.zeros_like(img, dtype=np.uint16) oi[(img > threshold_otsu(img)) == True] = 1 oh = np.zeros_like(img, dtype=np.uint16) oh[(h > threshold_otsu(h)) == True] = 1 nm = img.shape[0] * img.shape[1] w1 = np.sum(oi)/(nm) w2 = np.sum(oh)/(nm) ots = np.zeros_like(img, dtype=np.uint16) new =( w1 * img) + (w2 * h) ots[(new > threshold_otsu(new)) == True] = 1 conv_hull = convex_hull_image(ots) conv_hull = convex_hull_image(ots) ch = np.multiply(conv_hull, 1) fore_image = ch * img back_image = (1 - ch) * img except Exception: fore_image = img.copy() back_image = np.zeros_like(img, dtype=np.uint16) conv_hull = np.zeros_like(img, dtype=np.uint16) ch = np.multiply(conv_hull, 1) # if not os.path.isdir(save_folder + os.sep + v[1]['ID']): return fore_image, back_image, conv_hull, img[conv_hull], img[conv_hull==False]
def select_label(img, file_name): labels = measure.label(img, connectivity=2) if labels.max() == 1: img = img.astype('bool') img = morphology.convex_hull_image(img) img = morphology.binary_dilation(img, morphology.disk(3)) return img props = measure.regionprops(labels) areas = list(map(lambda x: x.area, props)) max_area = np.max(areas) min_area = int(max_area / 1.3) img = morphology.remove_small_objects(labels, min_size=min_area, connectivity=1) img = img.astype('bool') labels = measure.label(img, connectivity=2) if labels.max() == 1: img = img.astype('bool') img = morphology.convex_hull_image(img) props = measure.regionprops(labels) areas = list(map(lambda x: x.area, props)) r = math.sqrt(areas[0] / pi) img = morphology.binary_dilation(img, morphology.disk(int(r / 3))) else: img = img.astype('bool') with open( '/home/zhangqianru/data/seg_of_rectum/div_of_rectum/model_results_with_seg/special_1', 'a') as f: f.write(file_name + '\n') return img
def test_non_c_contiguous(): # 2D Fortran-contiguous image = np.ones((2, 2), order='F', dtype=bool) assert_array_equal(convex_hull_image(image), image) # 3D Fortran-contiguous image = np.ones((2, 2, 2), order='F', dtype=bool) assert_array_equal(convex_hull_image(image), image) # 3D non-contiguous image = np.transpose(np.ones((2, 2, 2), dtype=bool), [0, 2, 1]) assert_array_equal(convex_hull_image(image), image)
def get_vat_mask(f_mask, abdominal_water_mask): """FIXME! briefly describe function :param f_mask: :param abdominal_water_mask: :returns: :rtype: """ vat_mask = convex_hull_image(abdominal_water_mask) & f_mask vat_mask = convex_hull_image(binary_opening(vat_mask)) & f_mask return vat_mask
def find_center(mask, key): """ Find the centroid of the binary mask. Args: mask (array): Binary array mask. key (string): Key to access the sample elements. Also used in training for prediction. """ mask = np.uint8(mask > 0) if key == 'image' or key == 'target': if not is_predictable(mask): return 0, 0 else: mask = convex_hull_image(mask).astype(np.uint8) output = cv2.connectedComponentsWithStats(mask, 8, cv2.CV_32S) elif key == 'pred': try: if not is_predictable(mask): return 0, 0 output = cv2.connectedComponentsWithStats(mask, 8, cv2.CV_32S) if len(output[3]) != 2: # only two centroids: one for background and one for grape raise IndexError('Could not find centroids of one grape.') except IndexError: mask = convex_hull_image(mask).astype(np.uint8) if not is_predictable(mask): return 0, 0 output = cv2.connectedComponentsWithStats(mask, 8, cv2.CV_32S) if len(output[3]) != 2: return 0, 0 # centroids of grape class is always in index 1 (last) coords = output[3][-1] if np.isnan(coords[0]) or np.isnan(coords[1]): return 0, 0 x_f, y_f = int(np.floor(coords[0])), int(np.floor(coords[1])) x_c, y_c = int(np.ceil(coords[0])), int(np.ceil(coords[1])) if mask[y_f, x_f] == 1: x, y = x_f, y_f elif mask[y_c, x_c] == 1: x, y = x_c, y_c elif mask[y_c, x_f] == 1: x, y = x_f, y_c elif mask[y_f, x_c] == 1: x, y = x_c, y_c else: x, y = 0, 0 return x, y
def segmentation(cropped): #cropped = equalization(cropped) # ------------- k-means algorithm -------------------------- seg = Segment() # Here, we extract a label map, an image of the resulting clusters, and the table of the cluster centers # (here, 4 clusters and 4 centers) label, result, center = seg.kmeans(cropped) # We extract the pixels belonging to the cluster with highest gray-level # (belonging to the OC) extracted = seg.extractComponent(cropped, label, np.argmax(center)) # Binarisation ret, thresh = cv2.threshold(extracted, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) # Morphological closing kernel = np.ones((3, 3), np.uint8) #closing_oc = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel) opening_oc = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel) center[np.argmax(center)] = 0 # We extract the pixels belonging to the cluster with the second highest gray-level # (belonging to the OD) extracted2 = seg.extractComponent(cropped, label, np.argmax(center)) # Binarisation de l'image résultat d'extraction du DO ret2, thresh2 = cv2.threshold(extracted2, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) complete_od = disque_optique_entier(thresh2, thresh) # Morphological operation #closing_od = cv2.morphologyEx(complete_od, cv2.MORPH_CLOSE, kernel) opening_od = cv2.morphologyEx(complete_od, cv2.MORPH_OPEN, kernel) """ ------------- Convex hull transform -------------------------- """ OC_chull = convex_hull_image(opening_oc) #hullPoints = ConvexHull(OC_chull) #print(hullPoints) OC_chull = OC_chull * 255 OD_chull = convex_hull_image(opening_od) OD_chull = OD_chull * 255 return result, opening_oc, opening_od, OC_chull, OD_chull
def find_refine_boundaries(img: "NDArray[np.uint8]", segments_slic: "NDArray[int]", tissue_img: "NDArray[np.uint8]") -> "NDArray[bool]": """ Find and refine boundaries of the tissue image using convex hull. Inputs: img : 2D ndarray. Input image, must be grayscale. segments_slic : 2D ndarray. Integer mask indicating SLIC segment labels. tissue_img : 2D ndarray. Binary integer mask indicating the tissue. Output: tissue_img : 2D bool ndarray. Binary integer refined mask indicating the tissue. """ assert img.dtype == np.uint8, 'Wrong numpy dtype, expected "np.uint8" but got "{}"'.format( img.dtype) assert img.ndim == 2, 'Wrong numpy dimension, expected "2" but got "{}" with shape {}'.format( img.ndim, img.shape) # Find boundaries boundaries = find_boundaries(tissue_img, connectivity=2, mode='thick') labels = np.unique(segments_slic[boundaries]) # Convex hull on boundaries for region in regionprops(segments_slic, img): if region.label in labels: min_r, min_c, max_r, max_c = region.bbox img_tile = tissue_img[min_r:max_r, min_c:max_c] outlier_hull_img = convex_hull_image(img_tile) #tissue_img[min_r:max_r, min_c:max_c] = (outlier_hull_img * 255).astype('uint8') tissue_img[min_r:max_r, min_c:max_c] = (outlier_hull_img * 1) return tissue_img.astype('bool')
def ImageEffect_ConvexHull(I, obj=False): if obj: I_rgb = cv2.cvtColor(I, cv2.COLOR_RGBA2GRAY) I_filtered = morphology.convex_hull_object(I_rgb) else: I_filtered = morphology.convex_hull_image(I[:, :, :3]) return FilterPostProcess(I, I_filtered)
def nucleiBinarySplit(mask, thr): mask00 = ndi.binary_fill_holes(mask) maskConv = convex_hull_image(mask00) maskB = tinyDottsRemove(maskConv - mask) notConv = np.sum(maskB) / np.sum(mask00) if (notConv < thr): return mask00 nn = np.max(label(maskB)) if nn > 1: while (np.max(label(maskB)) == nn): maskB = binary_closing(binary_dilation(maskB, selem=disk(1)), selem=disk(2)) pass maskC = binary_dilation(skeletonize(maskB), selem=disk(1)) maskD = tinyDottsRemove(binary_erosion( imgToMask(binary_dilation(maskConv, selem=disk(1)) + (-1) * maskC), selem=disk(1)), minimum=10) maskE = binary_opening(maskD, selem=disk(1)) #maskE = imgToMask(maskD - maskConv) #maskF = ndi.binary_fill_holes(maskE) markers = ndi.label(maskE)[0] markers[np.where(mask00 == 0)] = 0 labels = watershed(-mask, markers, mask=mask) return labels
def hull(self): thresh_ivt = self.green_channel_thresh() # non-hull part: False, hull part: True chull = convex_hull_image(thresh_ivt) # view the hull image #plant part: 2, non-hull part: 0 (False) (black), hull-part excluding plant: 1 (True) gray chull_diff = np.where(thresh_ivt == 255, 2, chull)
def cluster_process(labels, original, activations): rbase = np.zeros(labels.shape) rubase = np.zeros(labels.shape) rubase[range(0,20),:] = 1 rubase[:,range(0,20)] = 1 rubase[range(-20,-1),:] = 1 rubase[:,range(-20,-1)] = 1 for i in range(1, int(np.max(labels))+1): base = np.zeros(labels.shape) base[labels==i] = 1 li = len(base.nonzero()[0]) if li>0: hull = convex_hull_image(base) lh =len(hull.nonzero()[0]) sel_org = base*original sel_act = base*activations cond = (li > 4000 and float(lh) / float(li) < 1.07 and perimeter(base)**2.0 / li < 30) or np.max(base * rubase) > 0.5 # print li>4000 and float(lh)/float(li)<1.07, perimeter(base)**2.0/li<30, np.max(base*rubase)>0.5, np.min(original[base>0]) hard_array =[li > 4000, float(lh) / float(li) < 1.07] optional_array = [perimeter(base)**2.0/li < 25, np.percentile(sel_org[sel_org>0], 5) > 0.2, np.percentile(sel_act, 90) - np.percentile(sel_act, 90)] print hard_array, optional_array if debug and li>1000: rs(base,'subspread cluster') if cond: rbase = rbase + base rbase[rubase.astype(np.bool)] = 1 return dilation(rbase, selem)
def find_eye(label_img, img): # image_label_overlay = label2rgb(label_image, image=img) # fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(6, 6)) # ax.imshow(image_label_overlay) for region in regionprops(label_image): # skip small images if region.area < 100: continue # draw rectangle around segmented coins minr, minc, maxr, maxc = region.bbox rect = mpatches.Rectangle((minc, minr), maxc - minc, maxr - minr, fill=False, edgecolor='red', linewidth=2) # ax.add_patch(rect) img[minr:maxr, minc:maxc] = convex_hull_image(img[minr:maxr, minc:maxc]) binary_mask = imresize(img, base_shape) / 255 ### binarization ### binary_mask = (binary_mask > 0.01) * 1 ### find right rectangles ### koeff = base_shape / new_shape return binary_mask, koeff[0] * minr, koeff[0] * maxr, koeff[ 1] * minc, koeff[1] * maxc
def process_mask(mask): """ :param mask: 输入的mask :return: """ """ 1. 对每一个slices的2d图像进行处理 "1. 获得当前层的凸包,如果当潜藏的凸包面积过大,或者没有没有mask,则放弃凸包的提取,直接赋值原始的图像 2. 对当前凸包mask进行膨胀处理,获得膨胀凸包 """ convex_mask = np.copy(mask) for i_layer in range(convex_mask.shape[0]): mask1 = np.ascontiguousarray(mask[i_layer]) if np.sum(mask1) > 0: mask2 = convex_hull_image(mask1) if np.sum(mask2) > 1.5 * np.sum( mask1): # 凸包生成的凸多边形太过分,掩盖了原始mask1的大致形状信息,则放弃凸包处理 mask2 = mask1 else: # 没有mask目标 mask2 = mask1 convex_mask[i_layer] = mask2 struct = generate_binary_structure(3, 1) dilatedMask = binary_dilation(convex_mask, structure=struct, iterations=10) return dilatedMask
def convex_hull(image, selem=None, out=None): orig_phantom = img_as_ubyte(image) fig, ax = plt.subplots() ax.imshow(orig_phantom, cmap=plt.cm.gray) def plot_comparison(original, filtered, filter_name): fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(8, 4), sharex=True, sharey=True) ax1.imshow(original, cmap=plt.cm.gray) ax1.set_title('original') ax1.axis('off') ax2.imshow(filtered, cmap=plt.cm.gray) ax2.set_title(filter_name) ax2.axis('off') phantom = orig_phantom.copy() phantom[340:350, 200:210] = 255 phantom[100:110, 200:210] = 0 phantom = orig_phantom.copy() phantom[10:30, 200:210] = 0 #img = imageGlobal hull1 = convex_hull_image(image == 0) plot_comparison(image, hull1, 'convex hull') plt.show()
def deep_struct_filter(self, data3dr_tmp, body): """ Najde vsechny hluboke (v ose z) objekty a jejich okoli 5 pixelu """ min_bone_thr = 220 bone = (data3dr_tmp>min_bone_thr) & body bone_sum = np.sum(bone, axis = 0) #> 150 bone_mask = bone_sum>=1 bone_hull = convex_hull_image(bone_mask)#convex_hull_image(bone_mask) 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) dh = weak_dist_bone(bone_hull, body) blur = scipy.ndimage.filters.gaussian_filter(copy.copy(data3dr_tmp), sigma=[17, 3, 3]) > 100 db = scipy.ndimage.morphology.distance_transform_edt(1-blur) dbf = db >= 6 struct_filter = ((dbf==False) & (dh>15))==False return struct_filter
def deep_struct_filter(self, data3dr_tmp, body): """ Najde vsechny hluboke (v ose z) objekty a jejich okoli 5 pixelu """ min_bone_thr = 220 bone = (data3dr_tmp > min_bone_thr) & body bone_sum = np.sum(bone, axis=0) #> 150 bone_mask = bone_sum >= 1 bone_hull = convex_hull_image(bone_mask) #convex_hull_image(bone_mask) 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) dh = weak_dist_bone(bone_hull, body) blur = scipy.ndimage.filters.gaussian_filter(copy.copy(data3dr_tmp), sigma=[17, 3, 3]) > 100 db = scipy.ndimage.morphology.distance_transform_edt(1 - blur) dbf = db >= 6 struct_filter = ((dbf == False) & (dh > 15)) == False return struct_filter
def post_process_v2(mask): """Mainly remove the convex areas""" bw = label(mask == 1) # 1) detach mislabeled pixels bw = binary_opening(bw, rectangle(2, 20)) # 2) remove small objects bw = remove_small_objects(bw, min_size=4096, connectivity=2) # 3) solve the defeat, typically the convex outline coords = corner_peaks(corner_harris(bw, k=0.2), min_distance=5) valid = [c for c in coords if 100 < c[1] < 476] # only cares about this valid range if valid: y, x = zip(*valid) # corners appear in pair if len(y) % 2 == 0: # select the lowest pair left_x, right_x = [func(x[0], x[1]) for func in (min, max)] sep_x = np.arange(left_x, right_x + 1).astype(int) sep_y = np.floor(np.linspace(y[0], y[1] + 1, len(sep_x))).astype(int) # make the gap manually bw[sep_y, sep_x] = 0 bw = binary_opening(bw, disk(6)) else: mask = np.zeros_like(bw) mask[y, x] = 1 chull = convex_hull_image(mask) bw = np.logical_xor(chull, bw) bw = binary_opening(bw, disk(6)) return bw
def internal_filter(self, lungs, coronal, body): #lungs = ss.get_lungs() lungs_sum = np.sum(lungs, axis = 0)>=5 lungs_hull = convex_hull_image(lungs_sum) def dist_lungs(lungs_hull, body): """ Metoda pro zjisteni, jak blizko jsme stredu (nejvzdalenejsimu mistu od povrchu) """ blank_body = np.ones(body.shape) lungs_edge_dist = scipy.ndimage.morphology.distance_transform_edt(lungs_hull) lungs_edge_dist_maximum = np.max(lungs_edge_dist) lungs_edge_dist_focus = lungs_edge_dist > 0.2 * lungs_edge_dist_maximum # 0.1 puvodne blank_body[:] = lungs_edge_dist_focus ld = scipy.ndimage.morphology.distance_transform_edt(blank_body) # resized_to_orig = resize_to_shape(ld, self.ss.orig_shape) # return resized_to_orig return ld dist_lungs_with_body = dist_lungs(lungs_hull, body) lungs_mask = (dist_lungs_with_body > 0 ) & (coronal > 0) #print_2D_gray(lungs_mask[100]) #print_it_all(ss, data3dr_tmp, lungs_mask*3, "001") def improve_lungs(dist_lungs_hulls, final_area_filter): """ Upravi masku lungs pro specialni ucely """ lungs_hulls = dist_lungs_hulls > 0 new_filter = np.zeros(final_area_filter.shape) for i, area_slice in enumerate(final_area_filter): convex = convex_hull_image(area_slice) new_filter[i] = lungs_hulls[i] & convex return new_filter return lungs_mask
def shift(img): """Shift a binary image randomly within the frame Uses a convex hull calculation to make sure it doesn't translate the image out of the frame. """ hull = morphology.convex_hull_image(1-img) horizontal = np.where(np.sum(hull, axis=0) > 0)[0] vertical = np.where(np.sum(hull, axis=1) > 0)[0] max_left = -np.min(horizontal) max_right = img.shape[1] - np.max(horizontal) max_down = -np.min(vertical) max_up = img.shape[0] - np.max(vertical) shift_x = np.random.randint(max_left, max_right) shift_y = np.random.randint(max_down, max_up) #print "SHIFT", shift_x, shift_y def shift(xy): xy[:, 0] -= shift_x xy[:, 1] -= shift_y return xy return np.logical_not(transform.warp(np.logical_not(img), shift))
def get_segmented_lungs(im): # Step 1: Convert into a binary image. binary = im < -400 # Step 2: Remove the blobs connected to the border of the image. cleared = clear_border(binary) # Step 3: Label the image. label_image = label(cleared) # Step 4: Keep the labels with 2 largest areas. areas = [r.area for r in regionprops(label_image)] areas.sort() if len(areas) > 2: for region in regionprops(label_image): if region.area < areas[-2]: for coordinates in region.coords: label_image[coordinates[0], coordinates[1]] = 0 binary = label_image > 0 # Step 5: Erosion operation with a disk of radius 2. This operation is seperate the lung nodules attached to the blood vessels. selem = disk(2) binary = binary_erosion(binary, selem) # Step 6: Closure operation with a disk of radius 10. This operation is to keep nodules attached to the lung wall. selem = disk(10) # CHANGE BACK TO 10 binary = binary_closing(binary, selem) # Step 7: Fill in the small holes inside the binary mask of lungs. edges = roberts(binary) binary = ndi.binary_fill_holes(edges) # Step 8: Superimpose the binary mask on the input image. # get_high_vals = binary == 0 # im[get_high_vals] = -2000 if np.sum(binary) > 4: binary = dilation(binary, square(5)) binary = convex_hull_image(binary) return binary
def bbox(row): mask_list = [] max_len = 40 x_min = -20 x_max = 180 x_start = np.argmin(np.abs(row['xcm_um'] - x_min)) x_stop = np.argmin(np.abs(row['xcm_um'] - x_max)) image = row['mask'][x_start:x_stop] for i, mask in enumerate(image): x_min = np.min(np.where(mask)[0]) x_max = np.max(np.where(mask)[0]) y_min = np.min(np.where(mask)[1]) y_max = np.max(np.where(mask)[1]) width = x_max - x_min height = y_max - y_min # Apply convex hull to avoid introducing bias and improve fit chull = convex_hull_image(mask) screened = chull[x_min:x_max, y_min:y_max] screened = tf.expand_dims(tf.convert_to_tensor(screened), axis=-1) screened = tf.image.pad_to_bounding_box(screened, int( (90 - width) / 2), int((90 - height) / 2), 90, 90).numpy() rr, cc = skimage.draw.ellipse(r=45, c=45, r_radius=row['b'][i] * 2.0, c_radius=row['a'][i] * 2.0, shape=(90, 90)) ellipse = np.zeros((90, 90, 1)) ellipse[rr, cc] = 1 mask_list.append(np.stack((screened, ellipse), axis=2)[:, :, :, 0]) if len(mask_list) < max_len: for _ in range(max_len - len(mask_list)): mask_list.append(np.zeros((90, 90, 2), dtype=bool)) return np.stack(mask_list)
def onclick(self,event): if event.inaxes==ax: if event.button==1: if np.sum(MASKs[self.ind])==0: cx, cy = circle_perimeter(int(event.ydata), int(event.xdata), 3) MASKs[self.ind][cx,cy] = (220, 80, 20, 1) original_image = np.copy(MASKs[self.ind][:,:,3]) chull = convex_hull_image(original_image) MASKs[self.ind][chull,:] = (255, 0, 0, .4) ax.cla() data = areaFile.attrs['ROI_patches'][:,:,self.ind] ax.imshow(data,cmap='binary_r') ax.imshow(MASKs[self.ind]) elif event.button==3: MASKs[self.ind] = np.zeros(MASKs[self.ind].shape) data = areaFile.attrs['ROI_patches'][:,:,self.ind] ax.cla() ax.imshow(data,cmap='binary_r') ax.imshow(MASKs[self.ind])
def get_convex(ori_seg_path, save_path): for file_name in os.listdir(ori_seg_path): img = imageio.imread(os.path.join(ori_seg_path, file_name)) img = np.where(img > 0, True, False) convex = morphology.convex_hull_image(img).astype('uint8') convex = np.where(convex > 0, 255, 0).astype('uint8') imageio.imwrite(os.path.join(save_path, file_name), convex)
def convex_hull_dilate(binary_mask, dilate_factor=1.5, iterations=10): """ Replace each slice with convex hull of it then dilate. Convex hulls used only if it does not increase area by dilate_factor. This applies mainly to the inferior slices because inferior surface of lungs is concave. binary_mask: 3D binary numpy array with the same shape of the image, that only region of interest is True. One side of the lung in this specifical case. dilate_factor: float, factor of increased area after dilation iterations: int, number of iterations for dilation return: 3D binary numpy array with the same shape of the image, that only region of interest is True. Each binary mask is ROI of one side of the lung. """ binary_mask_dilated = np.array(binary_mask) for i in range(binary_mask.shape[0]): slice_binary = binary_mask[i] if np.sum(slice_binary) > 0: slice_convex = morphology.convex_hull_image(slice_binary) if np.sum(slice_convex) <= dilate_factor * np.sum(slice_binary): binary_mask_dilated[i] = slice_convex struct = scipy.ndimage.morphology.generate_binary_structure(3, 1) binary_mask_dilated = scipy.ndimage.morphology.binary_dilation( binary_mask_dilated, structure=struct, iterations=10) return binary_mask_dilated
def change_perspective(image): orig = image image = color.rgb2gray(image) image = skimage.morphology.dilation(image, skimage.morphology.disk(5)) image = feature.canny(image, sigma=3) image = morphology.convex_hull_image(image) (im_height, im_width) = image.shape loc = np.array(np.where(image)).T target_points = np.float32([[0, 0], [im_height, 0], [0, im_width], [im_height, im_width]]) top_left = loc[np.argmin( np.linalg.norm(target_points[0] - loc, axis=1, ord=1))] top_right = loc[np.argmin( np.linalg.norm(target_points[1] - loc, axis=1, ord=1))] bot_left = loc[np.argmin( np.linalg.norm(target_points[2] - loc, axis=1, ord=1))] bot_right = loc[np.argmin( np.linalg.norm(target_points[3] - loc, axis=1, ord=1))] current_points = np.float32([top_left, top_right, bot_left, bot_right]) matrix = cv2.getPerspectiveTransform(target_points, current_points) result = skimage.transform.warp(orig, matrix) # skimage.io.imshow(result) return result
def warp_coeffs_to_template(I, T, plot=True, initial_warp_matrix = None): Ib = I Tb = (T != [255,255,255]).all(axis=2) if initial_warp_matrix is None: convex = morphology.convex_hull_image(morphology.binary_erosion(Ib)) # convex = morphology.convex_hull_image(Ib) bbox = measure.regionprops(convex.astype(int))[0].bbox w = bbox[2] - bbox[0] h = bbox[3] - bbox[1] initial_warp_matrix = np.array([ [h / T.shape[1], 0, bbox[1]], [0, w / T.shape[0], bbox[0]]], dtype=np.float32) criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 400, 0.0001) ecc, warp_matrix = cv2.findTransformECC( Tb.astype(np.float32), Ib.astype(np.float32), initial_warp_matrix.astype(np.float32), cv2.MOTION_AFFINE, criteria, None, 1) Tbr = cv2.warpAffine(Tb.astype(np.float32), warp_matrix, dsize=tuple(np.array(Ib.shape)[::-1])) if plot: fig, ax = plt.subplots() ax.cla() ax.imshow(Ib , alpha=0.5) ax.imshow(Tbr, alpha=0.5) plt.title('input-to-template warp') plt.show() return warp_matrix, Tbr
def chull_area(image): #print(image) #im = np.copy(image) #print(im) #im[im > 0] = 1 hull = convex_hull_image(image > 0) return np.count_nonzero(hull)
def patch_up_roi(roi, sigma=0.5, truncate=2): """ After being non-linearly transformed, ROIs tend to have holes in them. We perform a couple of computational geometry operations on the ROI to fix that up. Parameters ---------- roi : 3D binary array The ROI after it has been transformed. sigma : float The sigma for initial Gaussian smoothing. truncate : float The truncation for the Gaussian Returns ------- ROI after dilation and hole-filling """ return convex_hull_image( gaussian(ndim.binary_fill_holes(roi), sigma=sigma, truncate=truncate) > 0)
def calculate_oct_roi_mask(img, tresh=1e-10): """ Calculate the interesting region MASK of the image using entropy :param img: :param tresh: entropy cutoff threshold :return: mask of the interesting region (MASK = 1 interesting) """ if img.ndim == 2: im_slice = skimage.img_as_float(img.astype(np.float32) / 128. - 1.) elif img.ndim == 3: im_slice = skimage.img_as_float(img[:, :, 1].astype(np.float32) / 128. - 1.) assert img.ndim in {2, 3} im_slice_ = entropy(im_slice, disk(11)) im_slice_ = im_slice_ / (np.max(im_slice_) + 1e-16) im_slice_ = np.asarray(im_slice_ > tresh, dtype=np.int8) selem = disk(35) im_slice_ = binary_closing(im_slice_, selem=selem) im_slice_ = convex_hull_image(im_slice_) plt.imshow(im_slice, cmap='gray') plt.imshow(im_slice_, cmap='jet', alpha=0.5) plt.pause(.1) return im_slice_
def comp_external_contour(orig,thresh): img_height, img_width, img_channels = orig.shape #Convert the mean shift image to grayscale, then apply Otsu's thresholding gray = cv2.cvtColor(orig, cv2.COLOR_BGR2GRAY) convexhull = convex_hull_image(thresh) img_convexhull = np.uint8(convexhull)*255 #Obtain the threshold image using OTSU adaptive filter thresh_hull = cv2.threshold(img_convexhull, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] #find contours and get the external one image_result, contours, hier = cv2.findContours(img_convexhull, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) print("len(contours)") print(len(contours)) # Measure properties regions = regionprops(img_convexhull) #center location of region y_cvh, x_cvh = regions[0].centroid print("Convexhull center of root system: {0}, {1} \n".format(int(x_cvh),int(y_cvh))) convexhull_diameter = regions[0].equivalent_diameter return img_convexhull,convexhull_diameter, y_cvh, x_cvh
def get_bg_mask(img): #if img.ndim == 3: # bg_mask = img.any(axis=-1) # bg_mask = np.invert(bg_mask) # consistent with np.ma, True if masked # # make multichannel (is it really this hard?) # bg_mask = np.repeat(bg_mask[:,:,np.newaxis], 3, axis=2) # #else: # bg_mask = (img != 0) # bg_mask = np.invert(bg_mask) # see above #bound = segmentation.find_boundaries(bg_mask, mode='inner', background=1) #bg_mask[bound] = 1 #min_size = img.shape[0] * img.shape[1] // 4 #holes = morphology.remove_small_holes(bg_mask, min_size=min_size) #bg_mask[holes] = 1 #bg_mask = segmentation.find_boundaries(img) #bg_mask = morphology.remove_small_objects(bg_mask) #bg_mask = morphology.remove_small_holes(bg_mask) bg_mask = morphology.convex_hull_image(img) bg_mask = np.zeros_like(img) return bg_mask
def boundary_polygon(self, time): """ Get coordinates of object boundary in counter-clockwise order """ ti = np.where(time == self.times)[0][0] com_x, com_y = self.center_of_mass(time) # If at least one point along perimeter of the mask rectangle is unmasked, find_boundaries() works. # But if all perimeter points are masked, find_boundaries() does not find the object. # Therefore, pad the mask with zeroes first and run find_boundaries on the padded array. padded_mask = np.pad(self.masks[ti], 1, 'constant', constant_values=0) chull = convex_hull_image(padded_mask) boundary_image = find_boundaries(chull, mode='inner', background=0) # Now remove the padding. boundary_image = boundary_image[1:-1, 1:-1] boundary_x = self.x[ti].ravel()[boundary_image.ravel()] boundary_y = self.y[ti].ravel()[boundary_image.ravel()] r = np.sqrt((boundary_x - com_x)**2 + (boundary_y - com_y)**2) theta = np.arctan2((boundary_y - com_y), (boundary_x - com_x)) * 180.0 / np.pi + 360 polar_coords = np.array([(r[x], theta[x]) for x in range(r.size)], dtype=[('r', 'f4'), ('theta', 'f4')]) coord_order = np.argsort(polar_coords, order=['theta', 'r']) ordered_coords = np.vstack( [boundary_x[coord_order], boundary_y[coord_order]]) return ordered_coords
def active_snake(image_file, num_iters): #Parse image path and create result image path path, filename = os.path.split(image_file) print("processing image : {0} \n".format(str(filename))) #load the image and perform pyramid mean shift filtering to aid the thresholding step imgcolor = cv2.imread(image_file) img_gray = cv2.cvtColor(imgcolor, cv2.COLOR_BGR2GRAY) # Image binarization by applying otsu threshold thresh = threshold_otsu(img_gray) binary = img_gray > thresh # Extract convex hull of the binary image convexhull = convex_hull_image(invert(binary)) # label image regions label_image_convexhull = label(convexhull) # Measure properties of labeled image regions. regions = regionprops(label_image_convexhull) # center location of region y0, x0 = regions[0].centroid #print(y0,x0) print("Coordinates of centroid: {0} , {0} \n".format(y0, x0)) # axis length of region d_major = regions[0].major_axis_length d_minor = regions[0].minor_axis_length diameter = regions[0].equivalent_diameter minr, minc, maxr, maxc = regions[0].bbox d_bbox = max(maxr - minr, maxc - minc) radius = int(max(d_major, d_minor, d_bbox) / 2) + 20 print("Radius of convex hull region is: {0} \n".format(radius)) gI = morphsnakes.gborders(img_gray, alpha=5, sigma=1) # Morphological GAC. Initialization of the level-set. mgac = morphsnakes.MorphGAC(gI, smoothing=1, threshold=0.24, balloon=-1) mgac.levelset = circle_levelset(img_gray.shape, (y0, x0), radius, scalerow=0.75) # Visual evolution. morphsnakes.evolve_visual(mgac, num_iters=num_iters, background=imgcolor) #define result path for simplified segmentation result result_img_path = save_path_ac + str(filename[0:-4]) + '.png' # suppose that img's dtype is 'float64' img_uint8 = img_as_ubyte(mgac.levelset) cv2.imwrite(result_img_path, img_uint8)
def run(img, **args): if len(img.shape) > 2 and img.shape[2] == 4: img = color.rgba2rgb(img) if len(img.shape) == 2: img = color.gray2rgb(img) img = color.rgb2grey(img) return to_base64(convex_hull_image(img, **args))
def patch_up_roi(roi, bundle_name="ROI"): """ After being non-linearly transformed, ROIs tend to have holes in them. We perform a couple of computational geometry operations on the ROI to fix that up. Parameters ---------- roi : 3D binary array The ROI after it has been transformed. sigma : float The sigma for initial Gaussian smoothing. truncate : float The truncation for the Gaussian bundle_name : str, optional Name of bundle, which may be useful for error messages. Default: None Returns ------- ROI after dilation and hole-filling """ hole_filled = ndim.binary_fill_holes(roi > 0) if not np.any(hole_filled): raise ValueError(( f"{bundle_name} found to be empty after " "applying the mapping.")) try: return convex_hull_image(hole_filled) except QhullError: return hole_filled
def internal_filter(self, lungs, coronal, body): #lungs = ss.get_lungs() lungs_sum = np.sum(lungs, axis=0) >= 5 lungs_hull = convex_hull_image(lungs_sum) def dist_lungs(lungs_hull, body): """ Metoda pro zjisteni, jak blizko jsme stredu (nejvzdalenejsimu mistu od povrchu) """ blank_body = np.ones(body.shape) lungs_edge_dist = scipy.ndimage.morphology.distance_transform_edt( lungs_hull) lungs_edge_dist_maximum = np.max(lungs_edge_dist) lungs_edge_dist_focus = lungs_edge_dist > 0.2 * lungs_edge_dist_maximum # 0.1 puvodne blank_body[:] = lungs_edge_dist_focus ld = scipy.ndimage.morphology.distance_transform_edt(blank_body) # resized_to_orig = resize_to_shape(ld, self.ss.orig_shape) # return resized_to_orig return ld dist_lungs_with_body = dist_lungs(lungs_hull, body) lungs_mask = (dist_lungs_with_body > 0) & (coronal > 0) #print_2D_gray(lungs_mask[100]) #print_it_all(ss, data3dr_tmp, lungs_mask*3, "001") def improve_lungs(dist_lungs_hulls, final_area_filter): """ Upravi masku lungs pro specialni ucely """ lungs_hulls = dist_lungs_hulls > 0 new_filter = np.zeros(final_area_filter.shape) for i, area_slice in enumerate(final_area_filter): convex = convex_hull_image(area_slice) new_filter[i] = lungs_hulls[i] & convex return new_filter return lungs_mask
def add_auto_masks_area(areaFile,addMasks=False): from skimage.morphology import binary_dilation, binary_erosion, disk from skimage import exposure from skimage.transform import hough_circle from skimage.morphology import convex_hull_image from skimage.feature import canny from skimage.draw import circle_perimeter import h5py MASKs = np.zeros(areaFile.attrs['ROI_patches'].shape) if 'ROI_masks' in (areaFile.attrs.iterkeys()): print 'Masks have already been created' awns = raw_input('Would you like to redo them from scratch: (answer y/n): ') else: awns = 'y' if awns=='y': MASKs = np.zeros(areaFile.attrs['ROI_patches'].shape) for i in range(areaFile.attrs['ROI_patches'].shape[2]): patch = areaFile.attrs['ROI_patches'][:,:,i] tt0 = exposure.equalize_hist(patch) tt = 255*tt0/np.max(tt0) thresh = 1*tt>0.3*255 thresh2 = 1*tt<0.1*255 tt[thresh] = 255 tt[thresh2] = 0 edges = canny(tt, sigma=2, low_threshold=20, high_threshold=30) try_radii = np.arange(3,5) res = hough_circle(edges, try_radii) ridx, r, c = np.unravel_index(np.argmax(res), res.shape) r, c, try_radii[ridx] image = np.zeros([20,20,4]) cx, cy = circle_perimeter(c, r, try_radii[ridx]+2) try: image[cy, cx] = (220, 80, 20, 1) original_image = np.copy(image[:,:,3]) chull = convex_hull_image(original_image) image[chull,:] = (255, 0, 0, .4) except: pass MASKs[:,:,i] = (1*image[:,:,-1]>0) if addMasks: areaFile.attrs['ROI_masks'] = MASKs else: pass return np.array(MASKs)
def improve_lungs(dist_lungs_hulls, final_area_filter): """ Upravi masku lungs pro specialni ucely """ lungs_hulls = dist_lungs_hulls > 0 new_filter = np.zeros(final_area_filter.shape) for i, area_slice in enumerate(final_area_filter): convex = convex_hull_image(area_slice) new_filter[i] = lungs_hulls[i] & convex return new_filter
def find_convex_hull_rectangle(grey_image, mask=None, canny_threshold=50): edge_map = cv2.Canny(grey_image, canny_threshold, 3 * canny_threshold, apertureSize=3) if mask is not None: edge_map = edge_map*mask hull = convex_hull_image(edge_map) (_, contours, _) = cv2.findContours(hull.astype(np.uint8), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) assert len(contours) == 1 rect = cv2.minAreaRect(contours[0]) max_box = cv2.boxPoints(rect) return max_box.astype(np.int)
def test_pathological_qhull_example(): image = np.array( [[0, 0, 0, 0, 1, 0, 0], [0, 0, 1, 1, 1, 1, 1], [1, 1, 1, 0, 0, 0, 0]], dtype=bool) expected = np.array( [[0, 0, 0, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 0, 0, 0]], dtype=bool) assert_array_equal(convex_hull_image(image), expected)
def fill_poly(poly_y, poly_x, shape): bbox = np.zeros((4), dtype=np.int32) bbox[0] = np.min(poly_y) bbox[1] = np.min(poly_x) bbox[2] = np.max(poly_y) bbox[3] = np.max(poly_x) mask = np.zeros(shape, dtype = np.bool_) mask[poly_y.astype(np.int), poly_x.astype(np.int)] = True mask = morph.convex_hull_image(mask).astype(np.int8) return mask, bbox
def wrapper_regions(bestregions, opening_param = 3, mshape = ((0,1,0),(1,1,1),(0,1,0)) ): zdim, xdim, ydim = bestregions.shape wregions = np.zeros_like(bestregions) for sidx in range(zdim): if np.sum(bestregions[sidx]) > 0: wregions[sidx] = convex_hull_image(bestregions[sidx]) return wregions
def improve_bone_hull(bone_area_filter): basic_loc_filter = body & (coronal > 0) mask = np.zeros(bone_area_filter.shape) for i in range(len(bone_area_filter)): try: down_mask = bone_area_filter[i] & basic_loc_filter[i] mask[i] = convex_hull_image(down_mask) | bone_area_filter[i] mask[i] = scipy.ndimage.morphology.binary_fill_holes(mask[i]) except: pass mask = mask > 0 return mask
def test_basic(): image = np.array( [[0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 1, 0, 0, 0, 1, 0, 0], [0, 1, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=bool) expected = np.array( [[0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=bool) assert_array_equal(convex_hull_image(image), expected) # Test that an error is raised on passing a 3D image: image3d = np.empty((5, 5, 5)) with pytest.raises(ValueError): convex_hull_image(image3d)
def process_mask(mask): convex_mask = np.copy(mask) for i_layer in range(convex_mask.shape[0]): mask1 = np.ascontiguousarray(mask[i_layer]) if np.sum(mask1)>0: mask2 = convex_hull_image(mask1) if np.sum(mask2)>2*np.sum(mask1): mask2 = mask1 else: mask2 = mask1 convex_mask[i_layer] = mask2 struct = generate_binary_structure(3,1) dilatedMask = binary_dilation(convex_mask,structure=struct,iterations=10) return dilatedMask
def create_mask(frame): """"Create a big mask that encompasses all the cells""" # detect ridges ridges = enhance_ridges(frame) # threshold ridge image thresh = filters.threshold_otsu(ridges) thresh_factor = 1.1 prominent_ridges = ridges > thresh_factor*thresh prominent_ridges = morphology.remove_small_objects(prominent_ridges, min_size=128) # the mask contains the prominent ridges mask = morphology.convex_hull_image(prominent_ridges) mask = morphology.binary_erosion(mask, disk(10)) return mask
def test_qhull_offset_example(): nonzeros = (([1367, 1368, 1368, 1368, 1369, 1369, 1369, 1369, 1369, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1375, 1375, 1375, 1375, 1375, 1376, 1376, 1376, 1377]), ([151, 150, 151, 152, 149, 150, 151, 152, 153, 148, 149, 150, 151, 152, 153, 154, 147, 148, 149, 150, 151, 152, 153, 154, 155, 146, 147, 148, 149, 150, 151, 152, 153, 154, 146, 147, 148, 149, 150, 151, 152, 153, 154, 147, 148, 149, 150, 151, 152, 153, 148, 149, 150, 151, 152, 149, 150, 151, 150])) image = np.zeros((1392, 1040), dtype=bool) image[nonzeros] = True expected = image.copy() assert_array_equal(convex_hull_image(image), expected)
def test_basic(): image = np.array( [[0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 1, 0, 0, 0, 1, 0, 0], [0, 1, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=bool) expected = np.array( [[0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=bool) assert_array_equal(convex_hull_image(image), expected)
def get_bone_hull(data3dr_tmp, body): # jeste by bylo dobre u patere vynechat konvexni obal bone = (data3dr_tmp>min_bone_thr) & body mask = np.zeros(data3dr_tmp.shape) step = 32 for i in range(len(data3dr_tmp)): mask[i] = np.sum( bone[ int(max(0, i - step / 2)): int(min(len(data3dr_tmp), i + step / 2)) ], axis = 0 ) >= 1 try: mask[i] = convex_hull_image(mask[i]) except: pass mask = mask>0 return mask
def mask_readoutstreaks(image): '''logarithmic image to edge detect faint features This requires the `scikit-image <http://scikit-image.org/>`_ package. ''' from skimage import filters as skfilter from skimage.morphology import convex_hull_image logimage = np.log10(np.clip(image, 1, 1e5)) / 5 # Mask overexposed area + sobel edge detect mask = (skfilter.sobel(logimage) > 0.1) | (image > 0.6 * np.max(image)) # pick out the feature that contain the center # I hope that this always is bit enough mask, lnum = ndimage.label(mask, structure=np.ones((3, 3), dtype=bool)) i = mask[ndimage.center_of_mass(image)] mask = (mask == i) # fill any holes in that region return convex_hull_image(mask)
def find_pupil(darkest_cluster): """Find the pupil area by cleaning the darkest cluster.""" x, y = cluster_mean(darkest_cluster) # Find pupil region cleaned_pupil = np.copy(darkest_cluster) labels = label(darkest_cluster) c = Counter(labels.flatten()) label_pupil = c.most_common(2)[1][0] clean_pupil = labels == label_pupil # Naive radius as the half distance between # the most right element and most left element # of the pupil region sums = np.sum(clean_pupil, axis=1) radius = np.amax(sums) / 2 # Delete areas that are not in the naive radius of the iris for i in range(cleaned_pupil.shape[0]): for j in range(cleaned_pupil.shape[1]): if np.linalg.norm([x - i, y - j]) > 1.1 * radius: cleaned_pupil[i,j] = 0 # Add again the region labelled as the pupil before cleaned_pupil[clean_pupil] += 1 # Find new naive center sums = np.sum(clean_pupil, axis=1) radius = np.amax(sums) / 2 # Fill using a convex hull the pupil chull = convex_hull_image(cleaned_pupil) cleaned_pupil[chull] += 1 return cleaned_pupil, radius
import matplotlib.pyplot as plt from skimage.morphology import convex_hull_image image = np.array( [[0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 1, 0, 0, 0, 1, 0, 0], [0, 1, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=float) original_image = np.copy(image) chull = convex_hull_image(image) image[chull] += 1 # image is now: # [[ 0. 0. 0. 0. 0. 0. 0. 0. 0.] # [ 0. 0. 0. 0. 2. 0. 0. 0. 0.] # [ 0. 0. 0. 2. 1. 2. 0. 0. 0.] # [ 0. 0. 2. 1. 1. 1. 2. 0. 0.] # [ 0. 2. 1. 1. 1. 1. 1. 2. 0.] # [ 0. 0. 0. 0. 0. 0. 0. 0. 0.]] fig, axes = plt.subplots(1, 2, figsize=(9, 3)) ax = axes.ravel() ax[0].set_title('Original picture') ax[0].imshow(original_image, cmap=plt.cm.gray, interpolation='nearest')
sk = skeletonize(horse == 0) plot_comparison(horse, sk, 'skeletonize') ###################################################################### # # As the name suggests, this technique is used to thin the image to 1-pixel # wide skeleton by applying thinning successively. # # Convex hull # =========== # # The ``convex_hull_image`` is the *set of pixels included in the smallest # convex polygon that surround all white pixels in the input image*. Again # note that this is also performed on binary images. hull1 = convex_hull_image(horse == 0) plot_comparison(horse, hull1, 'convex hull') ###################################################################### # As the figure illustrates, ``convex_hull_image`` gives the smallest polygon # which covers the white or True completely in the image. # # If we add a small grain to the image, we can see how the convex hull adapts # to enclose that grain: import numpy as np horse_mask = horse == 0 horse_mask[45:50, 75:80] = 1 hull2 = convex_hull_image(horse_mask)
def main(): print("Usage: python3 img2poly.py <image> <min_dist_canny> <min_dist_extra>\n") img_path = sys.argv[1] min_dist = int(sys.argv[2]) min_distX = int(sys.argv[3]) # validate inputs (check if we have enough points in critical places!) np.random.seed(8) seed(8) img = io.imread(img_path) img_gray = color.rgb2gray(img) canny = feature.canny(img_gray, sigma=3) print("canny done") edges = [] for i in range(len(canny)): for j in range(len(canny[0])): if canny[i][j]: edges += [(i, j)] print("canny size: ", len(edges)) #plt.imshow(canny, cmap = 'gray') #plt.show() #edges = np.transpose(np.nonzero(canny)) uni_points = [] ''' block_size = 100 for i in range(0, len(canny)-block_size, block_size): for j in range(0, len(canny[0])-block_size, block_size): uni_points += [(i+randint(0, block_size), j+randint(0, block_size))] np.random.shuffle(uni_points) ''' '''for i in range(n_upoints): uni_points += [(randint(0, len(canny)-1), randint(0, len(canny[0])-1))] ''' ''' uni_points = poisson(min_dist, len(canny), len(canny[0]), n_upoints) np.random.shuffle(edges) ''' points = poisson_filter(edges, min_dist, len(canny[0]), len(canny)) print("filtered canny size: ", len(points)) uni_points = poisson(min_distX, len(canny), len(canny[0]), 16) print("generated random poisson points: ", len(uni_points)) points += uni_points #img_points = np.zeros((len(canny), len(canny[0]))) #img_points[canny] = 255 #for x,y in points: # img_points[x,y] = 255 #plt.imshow(img_points, cmap = 'gray') #plt.show() points=np.vstack((points,np.array([ [0,0], [0,np.shape(canny)[1] - 1], [np.shape(canny)[0] - 1,0], [np.shape(canny)[0] - 1,np.shape(canny)[1] - 1] ]))) #points=points[:,[1,0]] #points=np.vstack(points) tri=Delaunay(points) #plt.triplot(points[:,0], (-1)*points[:,1], tri.simplices.copy()) #plt.plot(points[:,0], points[:,1], 'o') #plt.show() #img_points = np.zeros((len(canny), len(canny[0]))) img_points = img in_tri = np.zeros((len(canny), len(canny[0]))) total = len(tri.simplices) print("#tri: ", total) count = 0 for t in tri.simplices: count += 1 if (count % 10 == 0): print("%3d%%" % (100*count/total)) in_tri[points[t,0], points[t,1]] = 255 chull = convex_hull_image(in_tri) img_points[chull, 0] = np.mean(img_points[chull, 0]) img_points[chull, 1] = np.mean(img_points[chull, 1]) img_points[chull, 2] = np.mean(img_points[chull, 2]) ''' img_points[chull, 0] = int(np.mean(np.sqrt(img_points[chull, 0]))**2) img_points[chull, 1] = int(np.mean(np.sqrt(img_points[chull, 1]))**2) img_points[chull, 2] = int(np.mean(np.sqrt(img_points[chull, 2]))**2) ''' in_tri[points[t,0], points[t,1]] = 0 plt.imshow(img_points) plt.show()
def distance_transform(network, geometry, offset, **kwargs): r""" Use the Voronoi vertices and perform image analysis to obtain throat properties """ import math import numpy as np from skimage.morphology import convex_hull_image from skimage.measure import regionprops from scipy import ndimage Nt = geometry.num_throats() area = sp.zeros(Nt) perimeter = sp.zeros(Nt) centroid = sp.zeros([Nt, 3]) incentre = sp.zeros([Nt, 3]) inradius = sp.zeros(Nt) equiv_diameter = sp.zeros(Nt) eroded_verts = sp.ndarray(Nt, dtype=object) res = 200 vertices = geometry['throat.vertices'] normals = geometry['throat.normal'] z_axis = [0, 0, 1] for i in range(Nt): logger.info("Processing throat " + str(i+1)+" of "+str(Nt)) # For boundaries some facets will already be aligned with the axis - if this # is the case a rotation is unnecessary and could also cause problems angle = tr.angle_between_vectors(normals[i], z_axis) if angle == 0.0 or angle == np.pi: # We are already aligned rotate_facet = False facet = vertices[i] else: rotate_facet = True M = tr.rotation_matrix(tr.angle_between_vectors(normals[i], z_axis), tr.vector_product(normals[i], z_axis)) facet = np.dot(vertices[i], M[:3, :3].T) x = facet[:, 0] y = facet[:, 1] z = facet[:, 2] # Get points in 2d for image analysis pts = np.column_stack((x, y)) # Translate points so min sits at the origin translation = [pts[:, 0].min(), pts[:, 1].min()] pts -= translation order = np.int(math.ceil(-np.log10(np.max(pts)))) # Normalise and scale the points so that largest span equals the resolution # to save on memory and create clear image" max_factor = np.max([pts[:, 0].max(), pts[:, 1].max()]) f = res/max_factor # Scale the offset and define a circular structuring element with radius r = f*offset # Only proceed if r is less than half the span of the image" if r <= res/2: pts *= f minp1 = pts[:, 0].min() minp2 = pts[:, 1].min() maxp1 = pts[:, 0].max() maxp2 = pts[:, 1].max() img = np.zeros([np.int(math.ceil(maxp1-minp1)+1), np.int(math.ceil(maxp2-minp2)+1)]) int_pts = np.around(pts, 0).astype(int) for pt in int_pts: img[pt[0]][pt[1]] = 1 # Pad with zeros all the way around the edges img_pad = np.zeros([np.shape(img)[0] + 2, np.shape(img)[1] + 2]) img_pad[1:np.shape(img)[0]+1, 1:np.shape(img)[1]+1] = img # All points should lie on this plane but could be some rounding errors # so use the order parameter z_plane = sp.unique(np.around(z, order+2)) if len(z_plane) > 1: print('Rotation for image analysis failed') temp_arr = np.ones(1) temp_arr.fill(np.mean(z_plane)) z_plane = temp_arr "Fill in the convex hull polygon" convhullimg = convex_hull_image(img_pad) # Perform a Distance Transform and black out points less than r to create # binary erosion. This is faster than performing an erosion and dt can # also be used later to find incircle" eroded = ndimage.distance_transform_edt(convhullimg) eroded[eroded <= r] = 0 eroded[eroded > r] = 1 # If we are left with less than 3 non-zero points then the throat is # fully occluded if np.sum(eroded) >= 3: # Do some image analysis to extract the key properties regions = regionprops(eroded[1:np.shape(img)[0]+1, 1:np.shape(img)[1]+1].astype(int)) # Change this to cope with genuine multi-region throats if len(regions) == 1: for props in regions: x0, y0 = props.centroid equiv_diameter[i] = props.equivalent_diameter area[i] = props.area perimeter[i] = props.perimeter coords = props.coords # Undo the translation, scaling and truncation on the centroid centroid2d = [x0, y0]/f centroid2d += (translation) centroid3d = np.concatenate((centroid2d, z_plane)) # Distance transform the eroded facet to find the incentre and # inradius dt = ndimage.distance_transform_edt(eroded) inx0, iny0 = \ np.asarray(np.unravel_index(dt.argmax(), dt.shape)) \ .astype(float) incentre2d = [inx0, iny0] # Undo the translation, scaling and truncation on the incentre incentre2d /= f incentre2d += (translation) incentre3d = np.concatenate((incentre2d, z_plane)) # The offset vertices will be those in the coords that are # closest to the originals" offset_verts = [] for pt in int_pts: vert = np.argmin(np.sum(np.square(coords-pt), axis=1)) if vert not in offset_verts: offset_verts.append(vert) # If we are left with less than 3 different vertices then the # throat is fully occluded as we can't make a shape with # non-zero area if len(offset_verts) >= 3: offset_coords = coords[offset_verts].astype(float) # Undo the translation, scaling and truncation on the # offset_verts offset_coords /= f offset_coords_3d = \ np.vstack((offset_coords[:, 0]+translation[0], offset_coords[:, 1]+translation[1], np.ones(len(offset_verts))*z_plane)).T # Get matrix to un-rotate the co-ordinates back to the # original orientation if we rotated in the first place if rotate_facet: MI = tr.inverse_matrix(M) # Unrotate the offset coordinates incentre[i] = np.dot(incentre3d, MI[:3, :3].T) centroid[i] = np.dot(centroid3d, MI[:3, :3].T) eroded_verts[i] = np.dot(offset_coords_3d, MI[:3, :3].T) else: incentre[i] = incentre3d centroid[i] = centroid3d eroded_verts[i] = offset_coords_3d inradius[i] = dt.max() # Undo scaling on other parameters area[i] /= f*f perimeter[i] /= f equiv_diameter[i] /= f inradius[i] /= f else: area[i] = 0 perimeter[i] = 0 equiv_diameter[i] = 0 if kwargs['set_dependent'] is True: geometry['throat.area'] = area geometry['throat.perimeter'] = perimeter geometry['throat.centroid'] = centroid geometry['throat.diameter'] = equiv_diameter geometry['throat.indiameter'] = inradius*2 geometry['throat.incentre'] = incentre return eroded_verts
def convex_image(self): return convex_hull_image(self.image)
.. image:: PLOT2RST.current_figure As the name suggests, this technique is used to thin the image to 1-pixel wide skeleton by applying thinning successively. Convex hull =========== The ``convex_hull_image`` is the *set of pixels included in the smallest convex polygon that surround all white pixels in the input image*. Again note that this is also performed on binary images. """ hull1 = convex_hull_image(horse) plot_comparison(horse, hull1, 'convex hull') """ .. image:: PLOT2RST.current_figure As the figure illustrates, ``convex_hull_image`` gives the smallest polygon which covers the white or True completely in the image. If we add a small grain to the image, we can see how the convex hull adapts to enclose that grain: """ import numpy as np horse2 = np.copy(horse)
def hull_percent_filled(filled_blob): edge = sobel(filled_blob) hull_img = convex_hull_image(edge) return float(len(np.where(filled_blob.astype("bool"))[0])) / len(np.where(hull_img.astype("bool"))[0])
def find_map(url, min_int=0.03, max_int=0.97, disk_sz=2, opt=None): """Find the map in an image (using morphological operations) and return it. Heuristic assumption the map is the largest object in the map. Parameters ---------- img: (M, N, 3) or (M, N, 4) An RGB or RGBA image. min_int : threshold value to eliminate ~black background. If min_int is not given, a default value of 0.03 is uded. max_int : threshold value to eliminate ~white background. If max_int is not given, a default value of 0.97 is uded. disk_sz : size of disk-shaped structuring element for opening. If disk_sz is not given, a default value of 2 is uded. opt : optional flag. Default is None; if set to not None, the convex hull of the largest detected object is returned. Returns ------- out : (M, N, 3) array An image with only the main map. """ # rgb from url rspns = requests.get(url) img = np.asarray(Image.open(StringIO(rspns.content)))[:, :, :3] # image must be RGB or RGB(A) if not len(img.shape) > 2: raise ValueError("Sorry, image has to be RGB (M, N, 3) or RGBA (M, N, 4)") # remove alpha channel img = img[:, :, :3] # stretch contrast p2, p98 = np.percentile(img, (2, 98)) rescale = exposure.rescale_intensity(img, in_range=(p2, p98)) # binary from rgb binary = np.logical_and(color.rgb2gray(rescale) > min_int, color.rgb2gray(rescale) < max_int) # apply very mild opening binary = opening(binary, disk(disk_sz)) # keep only largest white object label_objects, nb_labels = ndi.label(binary) sizes = np.bincount(label_objects.ravel()) sizes[0] = 0 if nb_labels < 2: # background not included in the count binary_objects = binary # in case the image already contained only the map else: binary_objects = remove_small_objects(binary, max(sizes)) # remove holes from it binary_holes = ndi.morphology.binary_fill_holes(binary_objects) # optional: get convex hull image (smallest convex polygon that surround all white pixels) if opt is not None: binary_holes = convex_hull_image(binary_holes) # use it to make 3D mask mask3 = np.zeros(img.shape) mask3[:, :, 0] = binary_holes mask3[:, :, 1] = binary_holes mask3[:, :, 2] = binary_holes # use mask to get only map in original image final = np.ma.masked_where(mask3 == 0, img) final = final.filled(0) # crop zero columns and zero rows # see http://stackoverflow.com/a/31402351/1034648 # plus a few columns and rows to counter the initial opening non_empty = np.where(final != 0) out = final[np.min(non_empty[0]) : np.max(non_empty[0]), np.min(non_empty[1]) : np.max(non_empty[1])][ disk_sz:-disk_sz, disk_sz:-disk_sz ] # output return out
tempcounter = 0 for ii in range(endpt.shape[0] - 1): for jj in np.arange(ii + 1, endpt.shape[0]): print(ii, jj) dicescore[tempcounter], imgregion[:, :, tempcounter], coverage[tempcounter], tempval = gaussianRectangle.compare(endpt[ii], endpt[jj], data) imgcoordinate.append(tempval) tempcounter += 1 # filtering the object parts for ii in range(tempcounter): labelimg, nums = label(imgregion[:,:,ii] > 0) imgarea[ii] = np.argwhere(imgregion[:,:,ii]>0).shape[0] if(nums > 1 or imgarea[ii] < 500): dicescore[ii] = 0 convarea = np.argwhere(skmorph.convex_hull_image(imgregion[:,:,ii]>0)).shape[0] areabyconvexarea[ii] = np.float64(imgarea[ii])/convarea #imgdatasegment = np.zeros((img.shape),np.uint8) #imgdatasegment = np.copy(data) #for ii in range(accsize): # imgdatasegment[imgcoordinate[ii][:,0], imgcoordinate[ii][:,1]] = imgdatasegment[imgcoordinate[ii][:,0], imgcoordinate[ii][:,1]] +1 #eigval, eigvec = principalComponents(np.argwhere(imgpart1)) #print(eigval[0:5]) #dt = cv2.distanceTransform(data, 2, 3) # #min0 = coord[:,0].min()