def process_image(pil_image, values): img = np.array(pil_image) selected_channels = [ values["-OTSU RED CHANNEL-"], values["-OTSU GREEN CHANNEL-"], values["-OTSU BLUE CHANNEL-"] ] if np.where(selected_channels)[0].size == 1 and len(img.shape) == 2: if values["-APPLY LOCAL OTSU-"]: radius = values["-LOCAL OTSU SIZE-"] local_mask = disk( radius ) if values["-LOCAL OTSU SHAPE-"] == "Disk" else rectangle( int(radius), int(radius)) otsu_img = img >= rank.otsu(img, local_mask) else: otsu_img = img >= threshold_otsu(img) otsu_np_img = 255 * np.asarray(otsu_img, dtype=np.uint8) if values["-OTSU OVERLAY WITH IMAGE-"]: cnts = cv2.findContours(otsu_np_img, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)[0] cv2.drawContours(img, cnts, -1, 255, 1) otsu_np_img = img ret_img = Image.fromarray(otsu_np_img) elif np.where(selected_channels)[0].size == 1: if values["-APPLY LOCAL OTSU-"]: radius = values["-LOCAL OTSU SIZE-"] local_mask = disk( radius ) if values["-LOCAL OTSU SHAPE-"] == "Disk" else rectangle( int(radius), int(radius)) otsu_img = img[..., np.where(selected_channels)[0][0]] >= rank.otsu( img[..., np.where(selected_channels)[0][0]], local_mask) else: threshold_global_otsu = threshold_otsu( img[..., np.where(selected_channels)[0][0]]) otsu_img = img[..., np.where(selected_channels )[0][0]] >= threshold_global_otsu otsu_np_img = 255 * np.asarray(otsu_img, dtype=np.uint8) if values["-OTSU OVERLAY WITH IMAGE-"]: cnts = cv2.findContours(otsu_np_img, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)[0] cv2.drawContours(img, cnts, -1, 255, 1) otsu_np_img = img ret_img = Image.fromarray(otsu_np_img) else: ret_img = pil_image return ret_img
def robust_binarize(base_image, _dilation=0, heterogeity_size=10, feature_size=50): """ Robust binarization algorithm based off random walker clustering :param base_image: :param _dilation: if set to anything other than 0, would perform a morphological dilation using this parameter value as size :param heterogeity_size: size of the feature (px) that the method will try to eliminate by smoothing :param feature_size: size of the feature (px) that the method will try to segment out :return: binary_labels """ if np.percentile(base_image, 99) < 0.20: if np.percentile(base_image, 99) > 0: mult = 0.20 / np.percentile( base_image, 99) # poissonean background assumptions else: mult = 1000. / np.sum(base_image) base_image = base_image * mult base_image[base_image > 1] = 1 clustering_markers = np.zeros(base_image.shape, dtype=np.uint8) selem = disk(heterogeity_size) smooth = gaussian_filter(base_image, heterogeity_size, mode='constant') smooth_median = median(smooth, selem) uniform_median = median(base_image, selem) selem2 = disk(feature_size) local_otsu = rank.otsu(smooth_median, selem2) uniform_median_otsu = rank.otsu(uniform_median, selem2) clustering_markers[smooth_median < local_otsu * 0.9] = 1 clustering_markers[smooth_median > local_otsu * 1.1] = 2 # dbg.random_walker_debug(smooth_median, clustering_markers) # dbg.robust_binarize_debug(base_image, smooth_median, smooth_median, local_otsu, clustering_markers, # 0, uniform_median, uniform_median_otsu) binary_labels = random_walker( smooth_median, clustering_markers, beta=10, mode='bf') - 1 if _dilation: selem = disk(_dilation) binary_labels = dilation(binary_labels, selem) # dbg.robust_binarize_debug(binary_labels, base_image) # dbg.voronoi_debug(binary_labels, local_maxi, dist, segmented_cells_labels) # dbg.Kristen_robust_binarize(binary_labels, base_image) return binary_labels
def load_edge2(self, img, low_rate=False): radius = 15 selem = disk(radius) if (low_rate == False): img_blur = skimage.filters.gaussian(img, sigma=1) #thresh = threshold_yen(img_blur) #binary = img_blur > thresh binary = rank.otsu(img_blur, selem) else: #thresh = threshold_yen(img) #binary = img > thresh binary = rank.otsu(img, selem) canny_img = canny(img.astype(np.float), sigma=self.sigma) return np.bitwise_and(canny_img, binary).astype(np.float)
def get_local_otsu(img): radius = 5 selem = disk(radius) local_otsu = rank.otsu(img, selem) # blur = cv2.GaussianBlur(img, (5, 5), 0) # ret, th = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) return img > local_otsu
def binarize_image(base_image, _dilation=0, feature_size=2): ''' Binarizes an image using local otsu and random walker Borrowed from Andrei's Imagepipe :param base_image: [np.ndarray] input image :param _dilation: [float] amount of dilation to implement in Binarization :param feature_size: [float] size of the structuring disk for random Walker :return: [np.ndarray] binarized image ''' print "> Binarizing Image..." if np.percentile(base_image, 99) < 0.20: if np.percentile(base_image, 99) > 0: mult = 0.20 / np.percentile( base_image, 99) # poissonean background assumptions else: mult = 1000. / np.sum(base_image) base_image = base_image * mult base_image[base_image > 1] = 1 clustering_markers = np.zeros(base_image.shape, dtype=np.uint8) selem2 = disk(feature_size) print '> Performing Local Otsu' local_otsu = rank.otsu(base_image, selem2) # view_2d_img(local_otsu) clustering_markers[base_image < local_otsu * 0.9] = 1 clustering_markers[base_image > local_otsu * 1.1] = 2 print "> Performing Random Walker Binarization" binary_labels = random_walker( base_image, clustering_markers, beta=10, mode='bf') - 1 if _dilation: selem = disk(_dilation) binary_labels = dilation(binary_labels, selem) return binary_labels
def autoThresholding(image2d, method='triangle', radius=10, value=50): """Autothreshold an 2D intensity image which is calculated using: binary = image2d >= thresh :param image2d: input image for thresholding :type image2d: NumPy.Array :param method: choice of thresholding method, defaults to 'triangle' :type method: str, optional :param radius: radius of disk when using local Otsu threshold, defaults to 10 :type radius: int, optional :param value: manual threshold value, defaults to 50 :type value: int, optional :return: binary - binary mask from thresholding :rtype: NumPy.Array """ # calculate global Otsu threshold if method == 'global_otsu': thresh = threshold_otsu(image2d) # calculate local Otsu threshold if method == 'local_otsu': thresh = rank.otsu(image2d, disk(radius)) if method == 'value_based': thresh = value if method == 'triangle': thresh = threshold_triangle(image2d) binary = image2d >= thresh return binary
def threshold_img(img, method='global_otsu', radius=50): """ Given a gray scale image return a thresholded binary image using Otsu's thresholding method. img: A gray scale numpy array. method: - 'global_otsu' computes a global threshold value for the whole image and uses this to binarize the input image. (default) - 'local_otsu' computes a local threshols value for each pixel (threshold is computed within a neighborhood of a radius). radius: The 2D neighborhood to compute local thresholds in local_otsu method Returns: img_binary: A binary image (same size as input img). threshold: Threshold value used to binarize the image. """ if len(img.shape) > 2: img = rgb2gray(img) if method == 'global_otsu': threshold = threshold_otsu(img) img_binary = img >= threshold elif method == 'local_otsu': selem = disk(radius) threshold = rank.otsu(img, selem) img_binary = img >= threshold return np.uint8(img_binary), threshold
def threshold(im, binary=False, local=False): ''' im: array TODO: - noise filtering - use local otsu: rank.otsu ''' #im = histeq(im) #im = contrast(im) #imshow(im) minval, maxval = 0, 255 im_gray = im.copy() if is_colored(im): im_gray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY) #im_gray = cv2.normalize(im_gray, None, alpha=minval, beta=maxval, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8UC1) if binary: minval = 5 thresh_type = cv2.THRESH_BINARY retval, im_thresh = cv2.threshold(im_gray,minval,maxval,thresh_type) elif local == False: #thresh_type = cv2.THRESH_BINARY+cv2.THRESH_OTSU thresh = filters.threshold_otsu(im_gray) im_thresh = (im_gray > thresh).astype('uint8')*255 else: im_thresh = rank.otsu(im_gray, morphology.disk(5)) im_thresh = (im_gray >= im_thresh).astype('uint8')*255 return im_thresh
def binarize_2d(float_surface, cutoff_type='static', mcc_cutoff=None): """ Performs a 2d binarization based on several possible methods :param float_surface: :param cutoff_type: ['otsu', 'local_otsu', 'static', 'log-otsu"]. Local Otsu is done with 5px mask :param mcc_cutoff: is cutoff_type is 'static', this will be the cutoff threshold :return: binary labels """ if cutoff_type == 'otsu': mcc_cutoff = threshold_otsu(float_surface) elif cutoff_type == 'local otsu': selem = disk(5) mcc_cutoff = rank.otsu(float_surface, selem) elif cutoff_type == 'static': pass elif cutoff_type == 'log-otsu': mcc_cutoff = threshold_otsu( np.log(float_surface + np.min(float_surface[float_surface > 0]))) else: raise PipeArgError('unknown cutoff type') binary_stack = np.zeros_like(float_surface).astype(np.bool) binary_stack[float_surface > mcc_cutoff] = 1 return binary_stack
def __otsu_method( image: Union[np.ndarray, Iterable, np.uint8]) -> np.ndarray: selem = disk(20) t_otsu = otsu(image, selem=selem) print(t_otsu) imshow(t_otsu) # th_motsu = threshold_multiotsu(image, classes=2) # im = np.digitize(image, bins=th_motsu) # imshow(im) plt.show() test = (image * 255 + 15) <= t_otsu result = np.zeros(image.shape, dtype=np.uint8) for i, l in enumerate(test): for j, v in enumerate(l): if v: result[i, j] = 255 imshow(result) plt.show() # result = gaussian(gaussian(result, 7), 7) result = gaussian(result, 7) imshow(result) plt.show() result = minimum(maximum(result, disk(5)), disk(12)) imshow(result) plt.show() result = gaussian(result, 3) imshow(result) plt.show() # return self.__ending(gaussian(self.__ending(result), 7)) # return self.__ending(result) return result
def local_otsu(image, radius=15): # radius = 15 selem = disk(radius) local_otsu = rank.otsu(image, selem) return (image >= local_otsu) * 255
def getIntensityThresholdOtsu(s, params): logging.info( f"{s['filename']} - \tLightDarkModule.getIntensityThresholdOtsu") name = "otsu" local = strtobool(params.get("local", "False")) radius = float(params.get("radius", 15)) selem = disk(radius) img = s.getImgThumb(s["image_work_size"]) img = color.rgb2gray(img) if local: thresh = rank.otsu(img, selem) name += "local" else: thresh = threshold_otsu(img) map = img < thresh s.addToPrintList(name, str(map.mean())) io.imsave(s["outdir"] + os.sep + s["filename"] + "_" + name + ".png", map * 255) s["img_mask_" + name] = (map * 255) > 0 if strtobool(params.get("invert", "False")): s["img_mask_use"] = s["img_mask_use"] & ~s["img_mask_" + name] else: s["img_mask_use"] = s["img_mask_use"] & s["img_mask_" + name] return
def estimate_background(_img): *extrem, _img = gaussian_normalize(_img) local_otsu = rank.otsu(_img, disk(otsu_disk_radii)) ub_background = rank.mean(_img, disk(mean_disk_radii), mask=_img <= local_otsu) return anti_gaussian_normalize(ub_background / 256., *extrem)
def otsu_binarize(img): radius = 13 selem = disk(radius) local_otsu = rank.otsu(img, selem) threshold_global_otsu = threshold_otsu(img) global_otsu = img >= threshold_global_otsu # fig, ax = plt.subplots(2, 2, figsize=(8, 5)) # ax1, ax2, ax3, ax4 = ax.ravel() # # fig.colorbar(ax1.imshow(img, cmap=plt.cm.gray), # ax=ax1, orientation='horizontal') # ax1.set_title('Original') # ax1.axis('off') # # fig.colorbar(ax2.imshow(local_otsu, cmap=plt.cm.gray), # ax=ax2, orientation='horizontal') # ax2.set_title('Local Otsu (radius=%d)' % radius) # ax2.axis('off') # # ax3.imshow(img >= local_otsu, cmap=plt.cm.gray) # ax3.set_title('Original >= Local Otsu' % threshold_global_otsu) # ax3.axis('off') # # ax4.imshow(global_otsu, cmap=plt.cm.gray) # ax4.set_title('Global Otsu (threshold = %d)' % threshold_global_otsu) # ax4.axis('off') # # plt.show() return local_otsu
def threshold(data, process_param): if process_param["threshold"] == "otsu": thresh = threshold_otsu(data) if process_param["threshold"] == "mean": thresh = threshold_mean(data) if process_param["threshold"] == "minimum": thresh = threshold_minimum(data) if process_param["threshold"] == "yen": thresh = threshold_yen(data) if process_param["threshold"] == "isodata": thresh = threshold_isodata(data) if process_param["threshold"] == "li": thresh = threshold_li(data) if process_param["threshold"] == "local": thresh = threshold_local(data, process_param["local_size"]) if process_param["threshold"] == "local_otsu": selem = disk(process_param["local_size"]) data = data.astype(np.float64) data = data - np.min(data) data = np.uint8(255 * data / np.max(data)) thresh = rank.otsu(data, selem) if process_param["threshold"] == "lg_otsu": selem = disk(process_param["local_size"]) data = data.astype(np.float64) data = data - np.min(data) data = np.uint8(255 * data / np.max(data)) threshl = rank.otsu(data, selem) threshg = threshold_otsu(data) if process_param["threshold"] == "niblack": thresh = threshold_niblack(data, process_param["local_size"]) mask = data > thresh if process_param["threshold"] == "sauvola": thresh = threshold_sauvola(data, process_param["local_size"]) mask = data > thresh if process_param["threshold"] == "lg_otsu": mask1 = data >= threshl mask2 = data > threshg mask = mask1 * mask2 elif process_param["threshold"] == "local_otsu": mask = data >= thresh else: mask = data > thresh labels = label(mask) return (labels)
def test_otsu_edge_case(): # This is an edge case that causes OTSU to appear to misbehave # Pixel [1, 1] may take a value of of 41 or 81. Both should be considered # valid. The value will change depending on the particular implementation # of OTSU. # To better understand, see # https://mybinder.org/v2/gist/hmaarrfk/4afae1cfded1d78e44c9e4f58285d552/master selem = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]], dtype=np.uint8) img = np.array([[0, 41, 0], [30, 81, 106], [0, 147, 0]], dtype=np.uint8) result = rank.otsu(img, selem) assert result[1, 1] in [41, 81] img = np.array([[0, 214, 0], [229, 104, 141], [0, 172, 0]], dtype=np.uint8) result = rank.otsu(img, selem) assert result[1, 1] in [141, 172]
def _binarize_and_apply_background(image): """Performs plain Otsu binarization to get threshold, but only sets the background to 0, retains all the foreground intensities.""" selem = numpy.ones((80, 80), dtype='uint8') local_otsu = rank.otsu(image, selem) # thr = threshold_otsu(image, nbins=256) output = image * 1 output[output < local_otsu] = 0 return output
def robust_binarize(base_image, _dilation=0, heterogeity_size=10, feature_size=50): if np.percentile(base_image, 99) < 0.20: if np.percentile(base_image, 99) > 0: mult = 0.20 / np.percentile( base_image, 99) # poissonean background assumptions else: mult = 1000. / np.sum(base_image) base_image = base_image * mult base_image[base_image > 1] = 1 clustering_markers = np.zeros(base_image.shape, dtype=np.uint8) selem = disk(heterogeity_size) smooth = gaussian_filter(base_image, heterogeity_size, mode='constant') smooth_median = median(smooth, selem) uniform_median = median(base_image, selem) selem2 = disk(feature_size) local_otsu = rank.otsu(smooth_median, selem2) uniform_median_otsu = rank.otsu(uniform_median, selem2) clustering_markers[smooth_median < local_otsu * 0.9] = 1 clustering_markers[smooth_median > local_otsu * 1.1] = 2 # dbg.random_walker_debug(smooth_median, clustering_markers) # dbg.robust_binarize_debug(base_image, smooth_median, smooth_median, local_otsu, clustering_markers, # 0, uniform_median, uniform_median_otsu) binary_labels = random_walker( smooth_median, clustering_markers, beta=10, mode='bf') - 1 if _dilation: selem = disk(_dilation) binary_labels = dilation(binary_labels, selem) # dbg.robust_binarize_debug(binary_labels, base_image) # dbg.voronoi_debug(binary_labels, local_maxi, dist, segmented_cells_labels) # dbg.Kristen_robust_binarize(binary_labels, base_image) return binary_labels
def test_otsu(): # test the local Otsu segmentation on a synthetic image # (left to right ramp * sinus) test = np.tile([128, 145, 103, 127, 165, 83, 127, 185, 63, 127, 205, 43, 127, 225, 23, 127], (16, 1)) test = test.astype(np.uint8) res = np.tile([1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1], (16, 1)) selem = np.ones((6, 6), dtype=np.uint8) th = 1 * (test >= rank.otsu(test, selem)) assert_equal(th, res)
def test_otsu_edge_case(): # This is an edge case that causes OTSU to appear to misbehave # Pixel [1, 1] may take a value of of 41 or 81. Both should be considered # valid. The value will change depending on the particular implementation # of OTSU. It also may depend on how the compiler chooses to optimize # the order of the operations. img = np.array([[0, 41, 0], [30, 81, 106], [0, 147, 0]], dtype=np.uint8) selem = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]], dtype=np.uint8) otsu = rank.otsu(img, selem) assert otsu[1, 1] in [41, 81]
def check_all(): selem = morphology.disk(1) refs = np.load( os.path.join(skimage.data_dir, "rank_filter_tests.npz")) assert_equal(refs["autolevel"], rank.autolevel(self.image, selem)) assert_equal(refs["autolevel_percentile"], rank.autolevel_percentile(self.image, selem)) assert_equal(refs["bottomhat"], rank.bottomhat(self.image, selem)) assert_equal(refs["equalize"], rank.equalize(self.image, selem)) assert_equal(refs["gradient"], rank.gradient(self.image, selem)) assert_equal(refs["gradient_percentile"], rank.gradient_percentile(self.image, selem)) assert_equal(refs["maximum"], rank.maximum(self.image, selem)) assert_equal(refs["mean"], rank.mean(self.image, selem)) assert_equal(refs["geometric_mean"], rank.geometric_mean(self.image, selem)), assert_equal(refs["mean_percentile"], rank.mean_percentile(self.image, selem)) assert_equal(refs["mean_bilateral"], rank.mean_bilateral(self.image, selem)) assert_equal(refs["subtract_mean"], rank.subtract_mean(self.image, selem)) assert_equal(refs["subtract_mean_percentile"], rank.subtract_mean_percentile(self.image, selem)) assert_equal(refs["median"], rank.median(self.image, selem)) assert_equal(refs["minimum"], rank.minimum(self.image, selem)) assert_equal(refs["modal"], rank.modal(self.image, selem)) assert_equal(refs["enhance_contrast"], rank.enhance_contrast(self.image, selem)) assert_equal(refs["enhance_contrast_percentile"], rank.enhance_contrast_percentile(self.image, selem)) assert_equal(refs["pop"], rank.pop(self.image, selem)) assert_equal(refs["pop_percentile"], rank.pop_percentile(self.image, selem)) assert_equal(refs["pop_bilateral"], rank.pop_bilateral(self.image, selem)) assert_equal(refs["sum"], rank.sum(self.image, selem)) assert_equal(refs["sum_bilateral"], rank.sum_bilateral(self.image, selem)) assert_equal(refs["sum_percentile"], rank.sum_percentile(self.image, selem)) assert_equal(refs["threshold"], rank.threshold(self.image, selem)) assert_equal(refs["threshold_percentile"], rank.threshold_percentile(self.image, selem)) assert_equal(refs["tophat"], rank.tophat(self.image, selem)) assert_equal(refs["noise_filter"], rank.noise_filter(self.image, selem)) assert_equal(refs["entropy"], rank.entropy(self.image, selem)) assert_equal(refs["otsu"], rank.otsu(self.image, selem)) assert_equal(refs["percentile"], rank.percentile(self.image, selem)) assert_equal(refs["windowed_histogram"], rank.windowed_histogram(self.image, selem))
def test_otsu(self): # test the local Otsu segmentation on a synthetic image # (left to right ramp * sinus) test = np.tile([128, 145, 103, 127, 165, 83, 127, 185, 63, 127, 205, 43, 127, 225, 23, 127], (16, 1)) test = test.astype(np.uint8) res = np.tile([1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1], (16, 1)) selem = np.ones((6, 6), dtype=np.uint8) th = 1 * (test >= rank.otsu(test, selem)) assert_equal(th, res)
def img_tesseract_detect(c_rect, im): # 由于使用minAreaRect获得的图像有-90~0的角度,所以给出的坐标顺序也不一定是 # 转换时候给的,这里需要判断出图像的左上、左下、右上、右下的坐标,便于后面的变换 pts = c_rect.reshape(4, 2) rect = np.zeros((4, 2), dtype = "float32") # the top-left point has the smallest sum whereas the # bottom-right has the largest sum s = pts.sum(axis = 1) rect[0] = pts[np.argmin(s)] rect[3] = pts[np.argmax(s)] # compute the difference between the points -- the top-right # will have the minumum difference and the bottom-left will # have the maximum difference diff = np.diff(pts, axis = 1) rect[2] = pts[np.argmin(diff)] rect[1] = pts[np.argmax(diff)] width = rect[3][0] - rect[0][0] height = rect[3][1] - rect[0][1] width = (int)((50.0 / height) * width) height = 50 dst = np.float32([[0,0],[0,height],[width,0],[width,height]]) M = cv2.getPerspectiveTransform(rect, dst) warp = cv2.warpPerspective(im, M, (width, height)) img_show_hook("剪裁识别图像", warp) warp = np.array(warp, dtype=np.uint8) radius = 13 selem = disk(radius) # 使用局部自适应OTSU阈值处理 local_otsu = rank.otsu(warp, selem) l_otsu = np.uint8(warp >= local_otsu) l_otsu *= 255 kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(2,2)) l_otsu = cv2.morphologyEx(l_otsu, cv2.MORPH_CLOSE, kernel) img_show_hook("局部自适应OTSU图像", l_otsu) print("识别结果:") print(pytesseract.image_to_string(Image.fromarray(l_otsu), lang="chi-sim")) cv2.waitKey(0) return
def img_tesseract_detect(c_rect, im): # 由于使用minAreaRect获得的图像有-90~0的角度,所以给出的坐标顺序也不一定是 # 转换时候给的,这里需要判断出图像的左上、左下、右上、右下的坐标,便于后面的变换 pts = c_rect.reshape(4, 2) rect = np.zeros((4, 2), dtype="float32") # the top-left point has the smallest sum whereas the # bottom-right has the largest sum s = pts.sum(axis=1) rect[0] = pts[np.argmin(s)] rect[3] = pts[np.argmax(s)] # compute the difference between the points -- the top-right # will have the minumum difference and the bottom-left will # have the maximum difference diff = np.diff(pts, axis=1) rect[2] = pts[np.argmin(diff)] rect[1] = pts[np.argmax(diff)] width = rect[3][0] - rect[0][0] height = rect[3][1] - rect[0][1] width = (int)((50.0 / height) * width) height = 50 dst = np.float32([[0, 0], [0, height], [width, 0], [width, height]]) M = cv2.getPerspectiveTransform(rect, dst) warp = cv2.warpPerspective(im, M, (width, height)) img_show_hook("剪裁识别图像", warp) warp = np.array(warp, dtype=np.uint8) radius = 13 selem = disk(radius) # 使用局部自适应OTSU阈值处理 local_otsu = rank.otsu(warp, selem) l_otsu = np.uint8(warp >= local_otsu) l_otsu *= 255 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2)) l_otsu = cv2.morphologyEx(l_otsu, cv2.MORPH_CLOSE, kernel) img_show_hook("局部自适应OTSU图像", l_otsu) print("识别结果:") print(pytesseract.image_to_string(Image.fromarray(l_otsu), lang="chi-sim")) cv2.waitKey(0) return
def test_otsu_edge_case(): # This is an edge case that causes OTSU to appear to misbehave # Pixel [1, 1] may take a value of of 41 or 81. Both should be considered # valid. The value will change depending on the particular implementation # of OTSU. # To better understand, see # https://mybinder.org/v2/gist/hmaarrfk/4afae1cfded1d78e44c9e4f58285d552/master selem = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]], dtype=np.uint8) img = np.array([[ 0, 41, 0], [ 30, 81, 106], [ 0, 147, 0]], dtype=np.uint8) result = rank.otsu(img, selem) assert result[1, 1] in [41, 81] img = np.array([[ 0, 214, 0], [229, 104, 141], [ 0, 172, 0]], dtype=np.uint8) result = rank.otsu(img, selem) assert result[1, 1] in [141, 172]
def t2(): """ uses local/global thresholding, local doesn't seem to work well because the image is already pretty binary """ from skimage.morphology import disk from skimage.filters import threshold_otsu, rank from skimage.util import img_as_ubyte img = misc.imread('zones/0.png') radius = 15 selem = disk(radius) local_otsu = rank.otsu(img, selem) threshold_global_otsu = threshold_otsu(img) global_otsu = img >= threshold_global_otsu fig, axes = plt.subplots(2, 2, figsize=(8, 5), sharex=True, sharey=True, subplot_kw={'adjustable': 'box-forced'}) ax = axes.ravel() plt.tight_layout() fig.colorbar(ax[0].imshow(img, cmap=plt.cm.gray), ax=ax[0], orientation='horizontal') ax[0].set_title('Original') ax[0].axis('off') fig.colorbar(ax[1].imshow(local_otsu, cmap=plt.cm.gray), ax=ax[1], orientation='horizontal') ax[1].set_title('Local Otsu (radius=%d)' % radius) ax[1].axis('off') ax[2].imshow(img >= local_otsu, cmap=plt.cm.gray) ax[2].set_title('Original >= Local Otsu' % threshold_global_otsu) ax[2].axis('off') ax[3].imshow(global_otsu, cmap=plt.cm.gray) ax[3].set_title('Global Otsu (threshold = %d)' % threshold_global_otsu) ax[3].axis('off') plt.show()
def thr_conn(img,fname,stfolder,sfn,thrtyp,bs,mp,kv,rv,inv,ext,prev): ofs=-5 if thrtyp=='Gauss': tmp=cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, bs, ofs) thrconnimg=Image.fromarray(tmp,mode='L') if thrtyp=='Mean': tmp=cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, bs, ofs) thrconnimg=Image.fromarray(tmp,mode='L') if thrtyp=='Gauss Sk': ad_thr = threshold_local(img, bs,method='gaussian', offset=ofs) tmp = 255*(img > ad_thr).astype('uint8') thrconnimg=Image.fromarray(tmp,mode='L') if thrtyp=='Mean Sk': ad_thr = threshold_local(img, bs,method='mean', offset=ofs) tmp = 255*(img > ad_thr).astype('uint8') thrconnimg=Image.fromarray(tmp,mode='L') if thrtyp=='Median Sk': ad_thr = threshold_local(img, bs,method='median', offset=ofs) tmp = 255*(img > ad_thr).astype('uint8') thrconnimg=Image.fromarray(tmp,mode='L') if thrtyp=='Otsu': ret,tmp=cv2.threshold(img, 0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) thrconnimg=Image.fromarray(tmp,mode='L') if thrtyp=='Otsu Loc': radius = bs selem = disk(radius) local_otsu = rank.otsu(img, selem) tmp = 255*(img >= local_otsu).astype('uint8') thrconnimg=Image.fromarray(tmp,mode='L') if thrtyp=='Niblack': ad_thr = threshold_niblack(img, window_size=bs, k=kv) tmp = 255*(img > ad_thr).astype('uint8') thrconnimg=Image.fromarray(tmp,mode='L') if thrtyp=='Sauvola': ad_thr = threshold_sauvola(img, window_size=bs, k=kv, r=rv) tmp = 255*(img > ad_thr).astype('uint8') thrconnimg=Image.fromarray(tmp,mode='L') kernel1 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(4,4)) openimg = Image.fromarray(cv2.morphologyEx(tmp,cv2.MORPH_OPEN,kernel1),mode='L') # openimg2 = Image.fromarray(remove_small_objects((tmp/255).astype('uint8'),mp),mode='L') opimg=255*remove_small_objects((tmp/255).astype('uint8').astype('bool'),mp).astype('uint8') openimg2 = Image.fromarray(opimg,mode='L') # skel=255*skeletonize((opimg/255).astype('uint8')) # skelimg=Image.fromarray(skel,mode='L') if prev=='N': save_tif(stfolder,sfn,fname,openimg2,thrtyp,ext) return openimg2#thrconnimg
def getIntensityThresholdOtsu(s, params): logging.info( f"{s['filename']} - \tLightDarkModule.getIntensityThresholdOtsu") name = "otsu" local = strtobool(params.get("local", "False")) radius = float(params.get("radius", 15)) selem = disk(radius) img = s.getImgThumb(s["image_work_size"]) img = color.rgb2gray(img) if local: thresh = rank.otsu(img, selem) name += "local" else: thresh = threshold_otsu(img) map = img < thresh s["img_mask_" + name] = map > 0 if strtobool(params.get("invert", "False")): s["img_mask_" + name] = ~s["img_mask_" + name] io.imsave(s["outdir"] + os.sep + s["filename"] + "_" + name + ".png", img_as_ubyte(s["img_mask_" + name])) prev_mask = s["img_mask_use"] s["img_mask_use"] = s["img_mask_use"] & s["img_mask_" + name] s.addToPrintList( name, printMaskHelper(params.get("mask_statistics", s["mask_statistics"]), prev_mask, s["img_mask_use"])) if len(s["img_mask_use"].nonzero() [0]) == 0: # add warning in case the final tissue is empty logging.warning( f"{s['filename']} - After LightDarkModule.getIntensityThresholdOtsu:{name} NO tissue remains " f"detectable! Downstream modules likely to be incorrect/fail") s["warnings"].append( f"After LightDarkModule.getIntensityThresholdOtsu:{name} NO tissue remains detectable! " f"Downstream modules likely to be incorrect/fail") return
def transform(): files = [] with open('list.txt', r) as f: files = f.readlines() f.close() for file in files: print("Processing " + file + "...") # Import file data = tifffile.imread(file) # Convert 3-band RGB to 1-band grayscale grayscale = rgb2gray(data) # Calculate standard deviation mult_1 = np.multiply(grayscale, grayscale) blur_1 = gaussian(mult_1, sigma=(9, 9), truncate=3.5, multichannel=False) blur_2 = gaussian(grayscale, sigma=(9, 9), truncate=3.5, multichannel=False) mult_2 = np.multiply(blur_2, blur_2) std_hat = np.sqrt(blur_1 - mult_2) # Calculate entropy sigma_hat = entropy(std_hat, square(9)) # Phase symmetry psym = phasesym(sigma_hat) # Threshold selem = square(9) local_otsu = rank.otsu(psym, selem) threshold_global_otsu = threshold_otsu(psym) global_otsu = (psym >= threshold_global_otsu) # Skeletonize and invert colors skeleton = skeletonize(global_otsu, method='lee') skeleton[skeleton == 255] = 1 skeleton[skeleton == 0] = 255 skeleton[skeleton == 1] = 0 # Save intermediate files as png plt.imsave(alignedname, skeleton, cmap=plt.cm.gray, dpi=300) print("File " + file + " done!")
def nick_binarize(img_list): '''Binarize linecut images using two differently sized local threshold kernels Args: img_list: list of grayscale linecut images Returns: results: binarized images in the same order as the input''' results = [] for img in img_list: try: # img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) height = img.shape[0] width = img.shape[1] # Resize the images to 200 pixel height scaling_factor = 100/img.shape[0] new_w = int(scaling_factor*img.shape[1]) new_h = int(scaling_factor*img.shape[0]) # img = cv2.resize(img, (new_w, new_h)) img = np.array(Image.fromarray(img).resize((new_w, new_h), Image.ANTIALIAS)) # First pass thresholding th1 = threshold_niblack(img, 13, 0.00) # Second pass thresholding radius = 101 structured_elem = disk(radius) th2 = rank.otsu(img, structured_elem) # Masking img = (img > th1) | (img > th2) img = img.astype('uint8')*255 img = np.array(Image.fromarray(img).resize((width, height), Image.ANTIALIAS)) results.append(img) except Exception as e: continue return results
def local_otsu_denoising(img): N = img.shape[0] radius = np.arange(10, N/4, 10) stds = [] out_images = [] for radii in radius: selem = square(radii) out = img.copy() # Improve the contrast of the image local_otsu = rank.otsu(img, selem) stds.append(out[out <= local_otsu].std()) out[out >= local_otsu] = 255 out_images.append(out) stds = np.array(stds) arg = stds.argmin() out = out_images[arg] return out
def local_otsu_denoising(img): N = img.shape[0] radius = np.arange(10, N / 4, 10) stds = [] out_images = [] for radii in radius: selem = square(radii) out = img.copy() # Improve the contrast of the image local_otsu = rank.otsu(img, selem) stds.append(out[out <= local_otsu].std()) out[out >= local_otsu] = 255 out_images.append(out) stds = np.array(stds) arg = stds.argmin() out = out_images[arg] return out
def run_otsu(image_path): # img = color.rgb2gray(io.imread(image_path)) img = io.imread(image_path, as_grey=True) radius = 15 selem = disk(radius) local_otsu = rank.otsu(img, selem) threshold_global_otsu = threshold_otsu(img) global_otsu = img >= threshold_global_otsu x = global_otsu.shape[1] y = global_otsu.shape[0] global_otsu = global_otsu.tolist() for i in xrange(y): for j in xrange(x): if global_otsu[i][j] == False: global_otsu[i][j] = 1 else: global_otsu[i][j] = 0 global_otsu = np.array(global_otsu) return global_otsu
def __calc_SNR(self, img, gaus_sd=1, local_rad=15, offset=70, show_imgs=False): ''' This function calculates the Signal to noise ration for a single image. Signal to noise is usually measured by: (i0 - ib) / sqrt(i0) where i0 is signal intensity, and ib is background intensity. To approximate this, we use otsu threshholding to separate background and signal peaks. We then use the mean value of the signal mask as i0 and the mean signal of the background mask as ib. inputs img <np.array> : image to prefore SNR analysis on gaus_sd <int> : standard deviation in the gaussian filter applied before otsu threshold local_rad <int> : otsu neighborhood offset <int> : pixel intensity offset, higher value will decrease the area of the signal mask. show_imgs <boolean> : if true, will plot the mask images, for use in diagnostics and parameter tuning outputs SNR <float> : Signal to noise ratio; (i0-ib) / sqrt(i0) ''' img2 = gaussian_filter(img, gaus_sd) selem = disk(local_rad) local_otsu = rank.otsu(img2, selem) if (show_imgs): fig, axes = plt.subplots(2, 2) axes = axes.flatten() axes[0].imshow(img) axes[1].imshow(img2) axes[2].imshow(img2 >= local_otsu + offset) plt.show() i0 = np.average(img2[img2 >= (local_otsu + offset)]) ib = np.average(img2[img2 < (local_otsu + offset)]) SNR = (i0 - ib) / np.sqrt(i0) return SNR
def local_otsu(img): radius = 100 selem = disk(radius) local_otsu = rank.otsu(img, selem) threshold_global_otsu = threshold_otsu(img) global_otsu = img >= threshold_global_otsu fig, ax = plt.subplots(2, 2, figsize=(8, 5), sharex=True, sharey=True, subplot_kw={'adjustable':'box-forced'}) ax1, ax2, ax3, ax4 = ax.ravel() fig.colorbar(ax1.imshow(img, cmap=plt.cm.gray), ax=ax1, orientation='horizontal') ax1.set_title('Original') ax1.axis('off') fig.colorbar(ax2.imshow(local_otsu, cmap=plt.cm.gray), ax=ax2, orientation='horizontal') ax2.set_title('Local Otsu (radius=%d)' % radius) ax2.axis('off') ax3.imshow(img >= local_otsu, cmap=plt.cm.gray) ax3.set_title('Original >= Local Otsu' % threshold_global_otsu) ax3.axis('off') ax4.imshow(global_otsu, cmap=plt.cm.gray) ax4.set_title('Global Otsu (threshold = %d)' % threshold_global_otsu) ax4.axis('off') plt.show()
def check_all(): np.random.seed(0) image = np.random.rand(25, 25) selem = morphology.disk(1) refs = np.load(os.path.join(skimage.data_dir, "rank_filter_tests.npz")) assert_equal(refs["autolevel"], rank.autolevel(image, selem)) assert_equal(refs["autolevel_percentile"], rank.autolevel_percentile(image, selem)) assert_equal(refs["bottomhat"], rank.bottomhat(image, selem)) assert_equal(refs["equalize"], rank.equalize(image, selem)) assert_equal(refs["gradient"], rank.gradient(image, selem)) assert_equal(refs["gradient_percentile"], rank.gradient_percentile(image, selem)) assert_equal(refs["maximum"], rank.maximum(image, selem)) assert_equal(refs["mean"], rank.mean(image, selem)) assert_equal(refs["mean_percentile"], rank.mean_percentile(image, selem)) assert_equal(refs["mean_bilateral"], rank.mean_bilateral(image, selem)) assert_equal(refs["subtract_mean"], rank.subtract_mean(image, selem)) assert_equal(refs["subtract_mean_percentile"], rank.subtract_mean_percentile(image, selem)) assert_equal(refs["median"], rank.median(image, selem)) assert_equal(refs["minimum"], rank.minimum(image, selem)) assert_equal(refs["modal"], rank.modal(image, selem)) assert_equal(refs["enhance_contrast"], rank.enhance_contrast(image, selem)) assert_equal(refs["enhance_contrast_percentile"], rank.enhance_contrast_percentile(image, selem)) assert_equal(refs["pop"], rank.pop(image, selem)) assert_equal(refs["pop_percentile"], rank.pop_percentile(image, selem)) assert_equal(refs["pop_bilateral"], rank.pop_bilateral(image, selem)) assert_equal(refs["sum"], rank.sum(image, selem)) assert_equal(refs["sum_bilateral"], rank.sum_bilateral(image, selem)) assert_equal(refs["sum_percentile"], rank.sum_percentile(image, selem)) assert_equal(refs["threshold"], rank.threshold(image, selem)) assert_equal(refs["threshold_percentile"], rank.threshold_percentile(image, selem)) assert_equal(refs["tophat"], rank.tophat(image, selem)) assert_equal(refs["noise_filter"], rank.noise_filter(image, selem)) assert_equal(refs["entropy"], rank.entropy(image, selem)) assert_equal(refs["otsu"], rank.otsu(image, selem)) assert_equal(refs["percentile"], rank.percentile(image, selem)) assert_equal(refs["windowed_histogram"], rank.windowed_histogram(image, selem))
from skimage import data from skimage.morphology import disk from skimage.filters import threshold_otsu, rank from skimage.util import img_as_ubyte matplotlib.rcParams['font.size'] = 9 img = img_as_ubyte(data.page()) radius = 15 selem = disk(radius) local_otsu = rank.otsu(img, selem) threshold_global_otsu = threshold_otsu(img) global_otsu = img >= threshold_global_otsu fig, ax = plt.subplots(2, 2, figsize=(8, 5)) ax1, ax2, ax3, ax4 = ax.ravel() fig.colorbar(ax1.imshow(img, cmap=plt.cm.gray), ax=ax1, orientation='horizontal') ax1.set_title('Original') ax1.axis('off') fig.colorbar(ax2.imshow(local_otsu, cmap=plt.cm.gray), ax=ax2, orientation='horizontal') ax2.set_title('Local Otsu (radius=%d)' % radius)
def pp_lotsu_eqhist(image, otsu_rad=5): byte_img = img_as_ubyte(image) selem = disk(otsu_rad) local_otsu = rank.otsu(byte_img, selem) eq_hist_img = equalize_hist(local_otsu) return eq_hist_img
def otsuThresholdLocal(img, radius = 15): selem = disk(radius) local_otsu = rank.otsu(img, selem) local_otsu = img >= local_otsu return local_otsu.astype(int)
# # Local is much slower than global thresholding. A function for global # Otsu thresholding can be found in : `skimage.filters.threshold_otsu`. # # .. [4] http://en.wikipedia.org/wiki/Otsu's_method from skimage.filters.rank import otsu from skimage.filters import threshold_otsu p8 = data.page() radius = 10 selem = disk(radius) # t_loc_otsu is an image t_loc_otsu = otsu(p8, selem) loc_otsu = p8 >= t_loc_otsu # t_glob_otsu is a scalar t_glob_otsu = threshold_otsu(p8) glob_otsu = p8 >= t_glob_otsu fig, ax = plt.subplots(2, 2, sharex=True, sharey=True) ax1, ax2, ax3, ax4 = ax.ravel() fig.colorbar(ax1.imshow(p8, cmap=plt.cm.gray), ax=ax1) ax1.set_title('Original') fig.colorbar(ax2.imshow(t_loc_otsu, cmap=plt.cm.gray), ax=ax2) ax2.set_title('Local Otsu ($r=%d$)' % radius)
def local_otsu(image): radius = 12 s_elem = disk(radius) local = rank.otsu(image, s_elem) return local
def lotsu(image, otsu_rad=5): byte_img = img_as_ubyte(image) selem = disk(otsu_rad) return rank.otsu(byte_img, selem)
rect[2] = pts[np.argmin(diff)] rect[1] = pts[np.argmax(diff)] dst = np.float32([[0,0],[0,100],[200,0],[200,100]]) M = cv2.getPerspectiveTransform(rect, dst) warp = cv2.warpPerspective(img_org, M, (200, 100)) cv2.imshow("cropped image", warp) cv2.waitKey(0) warp = np.array(warp, dtype=np.uint8) radius = 10 selem = disk(radius) local_otsu = rank.otsu(warp, selem) l_otsu = np.uint8(warp >= local_otsu) l_otsu *= 255 kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(6,6)) l_otsu = cv2.morphologyEx(l_otsu, cv2.MORPH_CLOSE, kernel) cv2.imshow("binary image to be detected", l_otsu) cv2.waitKey(0) print("识别结果:") print(pytesseract.image_to_string(Image.fromarray(l_otsu))) cv2.waitKey(0) # http://www.pyimagesearch.com/2014/03/10/building-pokedex-python-getting-started-step-1-6/