def get_kapur_threshold(image, mask=None): """The Kapur, Sahoo, & Wong method of thresholding, adapted to log-space.""" cropped_image = np.array(image.flat) if mask is None else image[mask] if np.product(cropped_image.shape) < 3: return 0 if np.min(cropped_image) == np.max(cropped_image): return cropped_image[0] log_image = np.log2(smooth_with_noise(cropped_image, 8)) min_log_image = np.min(log_image) max_log_image = np.max(log_image) histogram = scipy.ndimage.histogram(log_image, min_log_image, max_log_image, 256) histogram_values = min_log_image + (max_log_image - min_log_image) * np.array(range(256), float) / 255 # drop any zero bins keep = histogram != 0 histogram = histogram[keep] histogram_values = histogram_values[keep] # check for corner cases if np.product(histogram_values) == 1: return 2 ** histogram_values[0] # Normalize to probabilities p = histogram.astype(float) / float(np.sum(histogram)) # Find the probabilities totals up to and above each possible threshold. lo_sum = np.cumsum(p) hi_sum = lo_sum[-1] - lo_sum lo_e = np.cumsum(p * np.log2(p)) hi_e = lo_e[-1] - lo_e # compute the entropies lo_entropy = lo_e / lo_sum - np.log2(lo_sum) hi_entropy = hi_e / hi_sum - np.log2(hi_sum) sum_entropy = lo_entropy[:-1] + hi_entropy[:-1] sum_entropy[np.logical_not(np.isfinite(sum_entropy))] = np.Inf entry = np.argmin(sum_entropy) return 2 ** ((histogram_values[entry] + histogram_values[entry + 1]) / 2)
def test_02_smooth_half(self): out = cpms.smooth_with_noise(np.ones((100,100))*.5, 5) # Roughly 1/2 (5000) should be above .5 and half below # Over 1/2 should be within 1/32 of .5 self.assertTrue(out.ndim == 2) self.assertTrue(out.shape[0] == 100) self.assertTrue(out.shape[1] == 100) self.assertTrue(abs(np.sum(out > .5)-5000) < 300) # unless we are 3sd unlucky self.assertTrue(np.sum(np.abs(out-.5)< 1.0 / 32.0) > 4700) # unless we are > 3sd unlucky
def test_03_img_1201(self): '''Regression test of img-1201''' # # Using internal knowledge: smooth_with_noise always seeds with 0 # np.random.seed(0) r = np.random.normal(size=(10, 20)) img = np.random.uniform(size=(10, 20)) for bits in range(8, 17): result = cpms.smooth_with_noise(img, bits) im = img.copy() delta = 1.0 / float(2**bits) im[im < delta] = delta expected = np.exp2( np.log2(im) + (np.log2(im + 2.0**-bits) - np.log2(im)) * r) expected = np.clip(expected, 0, 1) np.testing.assert_almost_equal(result, expected)
def test_03_img_1201(self): '''Regression test of img-1201''' # # Using internal knowledge: smooth_with_noise always seeds with 0 # np.random.seed(0) r = np.random.normal(size=(10,20)) img = np.random.uniform(size=(10,20)) for bits in range(8,17): result = cpms.smooth_with_noise(img, bits) im = img.copy() delta = 1.0 / float(2**bits) im[im < delta] = delta expected = np.exp2(np.log2(im) + (np.log2(im + 2.0 ** -bits) - np.log2(im)) * r) expected = np.clip(expected, 0, 1) np.testing.assert_almost_equal(result, expected)
def get_kapur_threshold(image, mask=None): """The Kapur, Sahoo, & Wong method of thresholding, adapted to log-space.""" cropped_image = np.array(image.flat) if mask is None else image[mask] if np.product(cropped_image.shape)<3: return 0 if np.min(cropped_image) == np.max(cropped_image): return cropped_image[0] log_image = np.log2(smooth_with_noise(cropped_image, 8)) min_log_image = np.min(log_image) max_log_image = np.max(log_image) histogram = scipy.ndimage.histogram(log_image, min_log_image, max_log_image, 256) histogram_values = (min_log_image + (max_log_image - min_log_image)* np.array(range(256),float) / 255) # drop any zero bins keep = histogram != 0 histogram = histogram[keep] histogram_values = histogram_values[keep] # check for corner cases if np.product(histogram_values)==1: return 2**histogram_values[0] # Normalize to probabilities p = histogram.astype(float) / float(np.sum(histogram)) # Find the probabilities totals up to and above each possible threshold. lo_sum = np.cumsum(p); hi_sum = lo_sum[-1] - lo_sum; lo_e = np.cumsum(p * np.log2(p)); hi_e = lo_e[-1] - lo_e; # compute the entropies lo_entropy = lo_e / lo_sum - np.log2(lo_sum); hi_entropy = hi_e / hi_sum - np.log2(hi_sum); sum_entropy = lo_entropy[:-1] + hi_entropy[:-1]; sum_entropy[np.logical_not(np.isfinite(sum_entropy))] = np.Inf entry = np.argmin(sum_entropy); return 2**((histogram_values[entry] + histogram_values[entry+1]) / 2);
def sum_of_entropies(image, mask, binary_image): """Bin the foreground and background pixels and compute the entropy of the distribution of points among the bins """ mask = mask.copy() mask[np.isnan(image)] = False if not np.any(mask): return 0 # # Clamp the dynamic range of the foreground # minval = np.max(image[mask]) / 256 if minval == 0: return 0 clamped_image = image.copy() clamped_image[clamped_image < minval] = minval # # Smooth image with -8 bits of noise # image = smooth_with_noise(clamped_image, 8) im_min = np.min(image) im_max = np.max(image) # # Figure out the bounds for the histogram # upper = np.log2(im_max) lower = np.log2(im_min) if upper == lower: # All values are the same, answer is log2 of # of pixels return math.log(np.sum(mask), 2) # # Create log-transformed lists of points in the foreground and background # fg = image[binary_image & mask] bg = image[(~binary_image) & mask] if len(fg) == 0 or len(bg) == 0: return 0 log_fg = np.log2(fg) log_bg = np.log2(bg) # # Make these into histograms hfg = numpy_histogram(log_fg, 256, range=(lower, upper))[0] hbg = numpy_histogram(log_bg, 256, range=(lower, upper))[0] #hfg = scipy.ndimage.histogram(log_fg,lower,upper,256) #hbg = scipy.ndimage.histogram(log_bg,lower,upper,256) # # Drop empty bins # hfg = hfg[hfg > 0] hbg = hbg[hbg > 0] if np.product(hfg.shape) == 0: hfg = np.ones((1, ), int) if np.product(hbg.shape) == 0: hbg = np.ones((1, ), int) # # Normalize # hfg = hfg.astype(float) / float(np.sum(hfg)) hbg = hbg.astype(float) / float(np.sum(hbg)) # # Compute sum of entropies # return np.sum(hfg * np.log2(hfg)) + np.sum(hbg * np.log2(hbg))
def test_01_smooth_zero(self): """Make sure smooth doesn't crash on all zeros""" out = cpms.smooth_with_noise(np.zeros((3, 3)), 5) self.assertTrue(np.all(out >= 0)) self.assertTrue(np.all(out <= 1))
def sum_of_entropies(image, mask, threshold): """Bin the foreground and background pixels and compute the entropy of the distribution of points among the bins """ mask=mask.copy() mask[np.isnan(image)] = False if not np.any(mask): return 0 # # Clamp the dynamic range of the foreground # minval = np.max(image[mask])/256 if minval == 0: return 0 clamped_image = image.copy() clamped_image[clamped_image < minval] = minval # # Smooth image with -8 bits of noise # image = smooth_with_noise(clamped_image, 8) im_min = np.min(image) im_max = np.max(image) # # Figure out the bounds for the histogram # upper = np.log2(im_max) lower = np.log2(im_min) if upper == lower: # All values are the same, answer is log2 of # of pixels return math.log(np.sum(mask),2) # # Create log-transformed lists of points in the foreground and background # fg = image[np.logical_and(mask, image >= threshold)] bg = image[np.logical_and(mask, image < threshold)] if len(fg) == 0 or len(bg) == 0: return 0 log_fg = np.log2(fg) log_bg = np.log2(bg) # # Make these into histograms hfg = numpy_histogram(log_fg, 256, range=(lower,upper))[0] hbg = numpy_histogram(log_bg, 256, range=(lower,upper))[0] #hfg = scipy.ndimage.histogram(log_fg,lower,upper,256) #hbg = scipy.ndimage.histogram(log_bg,lower,upper,256) # # Drop empty bins # hfg = hfg[hfg>0] hbg = hbg[hbg>0] if np.product(hfg.shape) == 0: hfg = np.ones((1,),int) if np.product(hbg.shape) == 0: hbg = np.ones((1,),int) # # Normalize # hfg = hfg.astype(float) / float(np.sum(hfg)) hbg = hbg.astype(float) / float(np.sum(hbg)) # # Compute sum of entropies # return np.sum(hfg * np.log2(hfg)) + np.sum(hbg*np.log2(hbg))
def test_01_smooth_zero(self): """Make sure smooth doesn't crash on all zeros""" out = cpms.smooth_with_noise(np.zeros((3,3)), 5) self.assertTrue(np.all(out >=0)) self.assertTrue(np.all(out <=1))