def test_02_01_median(self): '''A median filter larger than the image = median of image''' np.random.seed(0) img = np.random.uniform(size=(9, 9)) result = F.median_filter(img, np.ones((9, 9), bool), 20) self.assertEqual(result[0, 0], np.median(img)) self.assertTrue(np.all(result == np.median(img)))
def run(self, workspace): image = workspace.image_set.get_image(self.image_name.value, must_be_grayscale=True) pixel_data = image.pixel_data if self.wants_automatic_object_size.value: object_size = min(30, max(1, np.mean(pixel_data.shape) / 40)) else: object_size = float(self.object_size.value) sigma = object_size / 2.35 if self.smoothing_method.value == GAUSSIAN_FILTER: def fn(image): return scind.gaussian_filter(image, sigma, mode="constant", cval=0) output_pixels = smooth_with_function_and_mask(pixel_data, fn, image.mask) elif self.smoothing_method.value == MEDIAN_FILTER: output_pixels = median_filter(pixel_data, image.mask, object_size / 2 + 1) elif self.smoothing_method.value == SMOOTH_KEEPING_EDGES: sigma_range = float(self.sigma_range.value) output_pixels = bilateral_filter(pixel_data, image.mask, sigma, sigma_range) elif self.smoothing_method.value == FIT_POLYNOMIAL: output_pixels = fit_polynomial(pixel_data, image.mask, self.clip.value) elif self.smoothing_method.value == CIRCULAR_AVERAGE_FILTER: output_pixels = circular_average_filter(pixel_data, object_size / 2 + 1, image.mask) elif self.smoothing_method.value == SM_TO_AVERAGE: if image.has_mask: mean = np.mean(pixel_data[image.mask]) else: mean = np.mean(pixel_data) output_pixels = np.ones(pixel_data.shape, pixel_data.dtype) * mean else: raise ValueError("Unsupported smoothing method: %s" % self.smoothing_method.value) output_image = cpi.Image(output_pixels, parent_image=image) workspace.image_set.add(self.filtered_image_name.value, output_image) workspace.display_data.pixel_data = pixel_data workspace.display_data.output_pixels = output_pixels
def test_00_01_all_masked(self): '''Test a completely masked image Regression test of IMG-1029''' result = F.median_filter(np.zeros((10, 10)), np.zeros((10, 10), bool), 3) self.assertTrue(np.all(result == 0))
def test_03_01_shape(self): '''Make sure the median filter is the expected octagonal shape''' radius = 5 a_2 = int(radius / 2.414213) i, j = np.mgrid[-10:11, -10:11] octagon = np.ones((21, 21), bool) # # constrain the octagon mask to be the points that are on # the correct side of the 8 edges # octagon[i < -radius] = False octagon[i > radius] = False octagon[j < -radius] = False octagon[j > radius] = False octagon[i + j < -radius - a_2] = False octagon[j - i > radius + a_2] = False octagon[i + j > radius + a_2] = False octagon[i - j > radius + a_2] = False np.random.seed(0) img = np.random.uniform(size=(21, 21)) result = F.median_filter(img, np.ones((21, 21), bool), radius) sorted = img[octagon] sorted.sort() min_acceptable = sorted[len(sorted) // 2 - 1] max_acceptable = sorted[len(sorted) // 2 + 1] self.assertTrue(result[10, 10] >= min_acceptable) self.assertTrue(result[10, 10] <= max_acceptable)
def test_01_01_mask(self): '''The median filter, masking a single value''' img = np.zeros((10, 10)) img[5, 5] = 1 mask = np.ones((10, 10), bool) mask[5, 5] = False result = F.median_filter(img, mask, 3) self.assertTrue(np.all(result[mask] == 0))
def test_02_02_median_bigger(self): '''Use an image of more than 255 values to test approximation''' np.random.seed(0) img = np.random.uniform(size=(20, 20)) result = F.median_filter(img, np.ones((20, 20), bool), 40) sorted = np.ravel(img) sorted.sort() min_acceptable = sorted[198] max_acceptable = sorted[202] self.assertTrue(np.all(result >= min_acceptable)) self.assertTrue(np.all(result <= max_acceptable))
def test_04_01_half_masked(self): '''Make sure that the median filter can handle large masked areas.''' img = np.ones((20, 20)) mask = np.ones((20, 20), bool) mask[10:, :] = False img[~mask] = 2 img[1, 1] = 0 # to prevent short circuit for uniform data. result = F.median_filter(img, mask, 5) # in partial coverage areas, the result should be only from the masked pixels self.assertTrue(np.all(result[:14, :] == 1)) # in zero coverage areas, the result should be the lowest valud in the valid area self.assertTrue(np.all(result[15:, :] == np.min(img[mask])))
def run(self, workspace): image = workspace.image_set.get_image(self.image_name.value, must_be_grayscale=True) pixel_data = image.pixel_data if self.wants_automatic_object_size.value: object_size = min(30, max(1, np.mean(pixel_data.shape) / 40)) else: object_size = float(self.object_size.value) sigma = object_size / 2.35 if self.smoothing_method.value == GAUSSIAN_FILTER: def fn(image): return scind.gaussian_filter(image, sigma, mode="constant", cval=0) output_pixels = smooth_with_function_and_mask( pixel_data, fn, image.mask) elif self.smoothing_method.value == MEDIAN_FILTER: output_pixels = median_filter(pixel_data, image.mask, object_size / 2 + 1) elif self.smoothing_method.value == SMOOTH_KEEPING_EDGES: sigma_range = np.float(self.sigma_range.value) output_pixels = skimage.restoration.denoise_bilateral( image=pixel_data.astype(np.float), multichannel=image.multichannel, sigma_color=sigma_range, sigma_spatial=sigma, ) elif self.smoothing_method.value == FIT_POLYNOMIAL: output_pixels = fit_polynomial(pixel_data, image.mask, self.clip.value) elif self.smoothing_method.value == CIRCULAR_AVERAGE_FILTER: output_pixels = circular_average_filter(pixel_data, object_size / 2 + 1, image.mask) elif self.smoothing_method.value == SM_TO_AVERAGE: if image.has_mask: mean = np.mean(pixel_data[image.mask]) else: mean = np.mean(pixel_data) output_pixels = np.ones(pixel_data.shape, pixel_data.dtype) * mean else: raise ValueError("Unsupported smoothing method: %s" % self.smoothing_method.value) output_image = cellprofiler_core.image.Image(output_pixels, parent_image=image) workspace.image_set.add(self.filtered_image_name.value, output_image) workspace.display_data.pixel_data = pixel_data workspace.display_data.output_pixels = output_pixels
def run_per_layer(self, image, channel): if channel >= 0: pixel_data = image.pixel_data[:,:,channel].squeeze() else: pixel_data = image.pixel_data mask = image.mask if self.wants_automatic_object_size.value: object_size = min(30, max(1, np.mean(pixel_data.shape) / 40)) else: object_size = float(self.object_size.value) sigma = object_size / 2.35 if self.smoothing_method.value == GAUSSIAN_FILTER: def fn(image): return scind.gaussian_filter(image, sigma, mode='constant', cval=0) output_pixels = smooth_with_function_and_mask(pixel_data, fn, mask) elif self.smoothing_method.value == MEDIAN_FILTER: output_pixels = median_filter(pixel_data, mask, object_size / 2 + 1) elif self.smoothing_method.value == SMOOTH_KEEPING_EDGES: sigma_range = float(self.sigma_range.value) output_pixels = bilateral_filter(pixel_data, mask, sigma, sigma_range) elif self.smoothing_method.value == FIT_POLYNOMIAL: output_pixels = fit_polynomial(pixel_data, mask, self.clip.value) elif self.smoothing_method.value == CIRCULAR_AVERAGE_FILTER: output_pixels = circular_average_filter(pixel_data, object_size / 2 + 1, mask) elif self.smoothing_method.value == SM_TO_AVERAGE: if image.has_mask: mean = np.mean(pixel_data[mask]) else: mean = np.mean(pixel_data) output_pixels = np.ones(pixel_data.shape, pixel_data.dtype) * mean elif self.smoothing_method.value == REMOVE_OUTLIER: # TODO: implement how this deals with masks. nbhood = self.outlierneighbourhood.value output_pixels = self.remove_outlier_pixels(pixel_data, threshold=self.treshold.value, radius=nbhood, mode='max') else: raise ValueError("Unsupported smoothing method: %s" % self.smoothing_method.value) return output_pixels
def test_04_01_median(): """test the smooth module with median filtering""" object_size = 100.0 / 40.0 np.random.seed(0) image = np.random.uniform(size=(100, 100)).astype(np.float32) mask = np.ones(image.shape, bool) mask[40:60, 45:65] = False expected = median_filter(image, mask, object_size / 2 + 1) workspace, module = make_workspace(image, mask) module.smoothing_method.value = S.MEDIAN_FILTER module.run(workspace) result = workspace.image_set.get_image(OUTPUT_IMAGE_NAME) assert result is not None np.testing.assert_almost_equal(result.pixel_data, expected)
def test_04_01_median(self): '''test the smooth module with median filtering''' object_size = 100.0/ 40.0 np.random.seed(0) image = np.random.uniform(size=(100,100)).astype(np.float32) mask = np.ones(image.shape,bool) mask[40:60,45:65] = False expected = median_filter(image, mask, object_size / 2 + 1) workspace, module = self.make_workspace(image, mask) module.smoothing_method.value = S.MEDIAN_FILTER module.run(workspace) result = workspace.image_set.get_image(OUTPUT_IMAGE_NAME) self.assertFalse(result is None) np.testing.assert_almost_equal(result.pixel_data, expected)
def test_04_02_median_multichannel(self): '''test the smooth module with median filtering''' object_size = 100.0 / 40.0 np.random.seed(0) image_plane = np.random.uniform(size=(100, 100)).astype(np.float32) image = np.repeat(image_plane[:,:,np.newaxis], 3, axis=2) mask = np.ones(image.shape[:2], bool) mask[40:60, 45:65] = False expected_plane = median_filter(image_plane, mask, object_size / 2 + 1) expected = np.repeat(expected_plane[:,:,np.newaxis], 3, axis=2) workspace, module = self.make_workspace(image, mask) module.smoothing_method.value = S.MEDIAN_FILTER module.run(workspace) result = workspace.image_set.get_image(OUTPUT_IMAGE_NAME) self.assertFalse(result is None) np.testing.assert_almost_equal(result.pixel_data, expected)
def run_grayscale(self, pixel_data, image): if self.wants_automatic_object_size.value: object_size = min(30, max(1, np.mean(pixel_data.shape) / 40)) else: object_size = float(self.object_size.value) sigma = object_size / 2.35 if self.smoothing_method.value == GAUSSIAN_FILTER: def fn(image): return scind.gaussian_filter(image, sigma, mode='constant', cval=0) output_pixels = smooth_with_function_and_mask( pixel_data, fn, image.mask) elif self.smoothing_method.value == MEDIAN_FILTER: output_pixels = median_filter(pixel_data, image.mask, object_size / 2 + 1) elif self.smoothing_method.value == SMOOTH_KEEPING_EDGES: sigma_range = float(self.sigma_range.value) output_pixels = skimage.restoration.denoise_bilateral( image=pixel_data, multichannel=image.multichannel, sigma_color=sigma_range, sigma_spatial=sigma) elif self.smoothing_method.value == FIT_POLYNOMIAL: output_pixels = fit_polynomial(pixel_data, image.mask, self.clip.value) elif self.smoothing_method.value == CIRCULAR_AVERAGE_FILTER: output_pixels = circular_average_filter(pixel_data, object_size / 2 + 1, image.mask) elif self.smoothing_method.value == SM_TO_AVERAGE: if image.has_mask: mean = np.mean(pixel_data[image.mask]) else: mean = np.mean(pixel_data) output_pixels = np.ones(pixel_data.shape, pixel_data.dtype) * mean else: raise ValueError("Unsupported smoothing method: %s" % self.smoothing_method.value) return output_pixels
def test_00_02_all_but_one_masked(self): mask = np.zeros((10, 10), bool) mask[5, 5] = True result = F.median_filter(np.zeros((10, 10)), mask, 3)
def test_00_00_zeros(self): '''The median filter on an array of all zeros should be zero''' result = F.median_filter(np.zeros((10, 10)), np.ones((10, 10), bool), 3) self.assertTrue(np.all(result == 0))
def run(self, workspace): image = workspace.image_set.get_image(self.image_name.value, must_be_grayscale = True) # # Match against Matlab's strel('disk') operation. # radius = (float(self.object_size.value)-1.0) / 2.0 mask = image.mask if image.has_mask else None pixel_data = image.pixel_data if self.method == ENHANCE: if self.enhance_method == E_SPECKLES: if self.speckle_accuracy == S_SLOW: result = white_tophat(pixel_data, radius, mask) else: # # white_tophat = img - opening # = img - dilate(erode) # = img - median_filter(median_filter(0%) 100%) result = pixel_data - median_filter( median_filter(pixel_data, mask, radius, percent = 0), mask, radius, percent = 100) if mask is not None: result[~mask] = pixel_data[~mask] elif self.enhance_method == E_NEURITES: if self.neurite_choice == N_GRADIENT: # # white_tophat = img - opening # black_tophat = closing - img # desired effect = img + white_tophat - black_tophat # = img + img - opening - closing + img # = 3*img - opening - closing result = (3 * pixel_data - opening(pixel_data, radius, mask) - closing(pixel_data, radius, mask)) result[result > 1] = 1 result[result < 0] = 0 else: sigma = self.smoothing.value smoothed = gaussian_filter(pixel_data, sigma) L = hessian(smoothed, return_hessian = False, return_eigenvectors = False) # # The positive values are darker pixels with lighter # neighbors. The original ImageJ code scales the result # by sigma squared - I have a feeling this might be # a first-order correction for e**(-2*sigma), possibly # because the hessian is taken from one pixel away # and the gradient is less as sigma gets larger. # result = -L[:, :, 0] * (L[:, :, 0] < 0) * sigma * sigma if image.has_mask: result[~mask] = pixel_data[~mask] elif self.enhance_method == E_DARK_HOLES: min_radius = max(1,int(self.hole_size.min / 2)) max_radius = int((self.hole_size.max+1)/2) result = enhance_dark_holes(pixel_data, min_radius, max_radius, mask) elif self.enhance_method == E_CIRCLES: result = circular_hough(pixel_data, radius + .5, mask=mask) elif self.enhance_method == E_TEXTURE: result = variance_transform(pixel_data, self.smoothing.value, mask = mask) elif self.enhance_method == E_DIC: result = line_integration(pixel_data, self.angle.value, self.decay.value, self.smoothing.value) else: raise NotImplementedError("Unimplemented enhance method: %s"% self.enhance_method.value) elif self.method == SUPPRESS: if image.has_mask: result = opening(image.pixel_data, radius, image.mask) else: result = opening(image.pixel_data, radius) else: raise ValueError("Unknown filtering method: %s"%self.method) result_image = cpi.Image(result, parent_image=image) workspace.image_set.add(self.filtered_image_name.value, result_image) if self.show_window: workspace.display_data.image = image.pixel_data workspace.display_data.result = result
def run(self, workspace): image = workspace.image_set.get_image(self.image_name.value, must_be_grayscale=True) # # Match against Matlab's strel('disk') operation. # radius = (float(self.object_size.value) - 1.0) / 2.0 mask = image.mask if image.has_mask else None pixel_data = image.pixel_data if self.method == ENHANCE: if self.enhance_method == E_SPECKLES: if self.speckle_accuracy == S_SLOW: result = white_tophat(pixel_data, radius, mask) else: # # white_tophat = img - opening # = img - dilate(erode) # = img - median_filter(median_filter(0%) 100%) result = pixel_data - median_filter(median_filter( pixel_data, mask, radius, percent=0), mask, radius, percent=100) if mask is not None: result[~mask] = pixel_data[~mask] elif self.enhance_method == E_NEURITES: if self.neurite_choice == N_GRADIENT: # # white_tophat = img - opening # black_tophat = closing - img # desired effect = img + white_tophat - black_tophat # = img + img - opening - closing + img # = 3*img - opening - closing result = (3 * pixel_data - opening(pixel_data, radius, mask) - closing(pixel_data, radius, mask)) result[result > 1] = 1 result[result < 0] = 0 else: sigma = self.smoothing.value smoothed = gaussian_filter(pixel_data, sigma) L = hessian(smoothed, return_hessian=False, return_eigenvectors=False) # # The positive values are darker pixels with lighter # neighbors. The original ImageJ code scales the result # by sigma squared - I have a feeling this might be # a first-order correction for e**(-2*sigma), possibly # because the hessian is taken from one pixel away # and the gradient is less as sigma gets larger. # result = -L[:, :, 0] * (L[:, :, 0] < 0) * sigma * sigma if image.has_mask: result[~mask] = pixel_data[~mask] elif self.enhance_method == E_DARK_HOLES: min_radius = max(1, int(self.hole_size.min / 2)) max_radius = int((self.hole_size.max + 1) / 2) result = enhance_dark_holes(pixel_data, min_radius, max_radius, mask) elif self.enhance_method == E_CIRCLES: result = circular_hough(pixel_data, radius + .5, mask=mask) elif self.enhance_method == E_TEXTURE: result = variance_transform(pixel_data, self.smoothing.value, mask=mask) elif self.enhance_method == E_DIC: result = line_integration(pixel_data, self.angle.value, self.decay.value, self.smoothing.value) else: raise NotImplementedError("Unimplemented enhance method: %s" % self.enhance_method.value) elif self.method == SUPPRESS: if image.has_mask: result = opening(image.pixel_data, radius, image.mask) else: result = opening(image.pixel_data, radius) else: raise ValueError("Unknown filtering method: %s" % self.method) result_image = cpi.Image(result, parent_image=image) workspace.image_set.add(self.filtered_image_name.value, result_image) if self.show_window: workspace.display_data.image = image.pixel_data workspace.display_data.result = result