diff --git a/doc/examples/plot_windowed_histogram.py b/doc/examples/plot_windowed_histogram.py index 2cc77139..1c57721b 100644 --- a/doc/examples/plot_windowed_histogram.py +++ b/doc/examples/plot_windowed_histogram.py @@ -57,7 +57,7 @@ def windowed_histogram_similarity(image, selem, reference_hist, n_bins): # Reshape coin histogram to (1,1,N) for broadcast when we want to use it in # arithmetic operations with the windowed histograms from the image - reference_hist = reference_hist.reshape((1,1) + reference_hist.shape) + reference_hist = reference_hist.reshape((1, 1) + reference_hist.shape) # Compute Chi squared distance metric: sum((X-Y)^2 / (X+Y)); # a measure of distance between histograms @@ -66,7 +66,7 @@ def windowed_histogram_similarity(image, selem, reference_hist, n_bins): num = (X-Y)*(X-Y) denom = X+Y frac = num / denom - frac[denom==0] = 0 + frac[denom == 0] = 0 chi_sqr = np.sum(frac, axis=2) * 0.5 # Generate a similarity measure. It needs to be low when distance is high @@ -80,17 +80,18 @@ def windowed_histogram_similarity(image, selem, reference_hist, n_bins): # Load the `skimage.data.coins` image img = img_as_ubyte(data.coins()) -# Quantize to 16 levels of grayscale; this way the output image will have a +# Quantize to 16 levels of greyscale; this way the output image will have a # 16-dimensional feature vector per pixel quantized_img = img//16 # Select the coin from the 4th column, second row. # Co-ordinate ordering: [x1,y1,x2,y2] -coin_coords = [184,100,228,148] # 44 x 44 region -coin = quantized_img[coin_coords[1]:coin_coords[3], coin_coords[0]:coin_coords[2]] +coin_coords = [184, 100, 228, 148] # 44 x 44 region +coin = quantized_img[coin_coords[1]:coin_coords[3], + coin_coords[0]:coin_coords[2]] # Compute coin histogram and normalize -coin_hist, _ = np.histogram(coin.flatten(), bins=16, range=(0,16)) +coin_hist, _ = np.histogram(coin.flatten(), bins=16, range=(0, 16)) coin_hist = coin_hist.astype(float) / np.sum(coin_hist) @@ -114,7 +115,6 @@ rotated_similarity = windowed_histogram_similarity(quantized_rotated_image, coin_hist.shape[0]) - # Plot it all fig, axes = plt.subplots(nrows=5, figsize=(6, 18)) ax0, ax1, ax2, ax3, ax4 = axes diff --git a/skimage/filter/rank/bilateral.py b/skimage/filter/rank/bilateral.py index 73147c7f..aeb318d1 100644 --- a/skimage/filter/rank/bilateral.py +++ b/skimage/filter/rank/bilateral.py @@ -158,8 +158,9 @@ def pop_bilateral(image, selem, out=None, mask=None, shift_x=False, return _apply(bilateral_cy._pop, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, s0=s0, s1=s1) + def sum_bilateral(image, selem, out=None, mask=None, shift_x=False, - shift_y=False, s0=10, s1=10): + shift_y=False, s0=10, s1=10): """Apply a flat kernel bilateral filter. This is an edge-preserving and noise reducing denoising filter. It averages diff --git a/skimage/filter/rank/bilateral_cy.pyx b/skimage/filter/rank/bilateral_cy.pyx index 20a97788..b4e22d3f 100644 --- a/skimage/filter/rank/bilateral_cy.pyx +++ b/skimage/filter/rank/bilateral_cy.pyx @@ -51,6 +51,7 @@ cdef inline void _kernel_pop(dtype_t_out* out, Py_ssize_t odepth, else: out[0] = 0 + cdef inline void _kernel_sum(dtype_t_out* out, Py_ssize_t odepth, Py_ssize_t* histo, double pop, dtype_t g, @@ -96,6 +97,7 @@ def _pop(dtype_t[:, ::1] image, _core(_kernel_pop[dtype_t_out, dtype_t], image, selem, mask, out, shift_x, shift_y, 0, 0, s0, s1, max_bin) + def _sum(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, diff --git a/skimage/filter/rank/core_cy.pyx b/skimage/filter/rank/core_cy.pyx index c1216c0d..4bd21df0 100644 --- a/skimage/filter/rank/core_cy.pyx +++ b/skimage/filter/rank/core_cy.pyx @@ -42,8 +42,8 @@ cdef inline char is_in_mask(Py_ssize_t rows, Py_ssize_t cols, return 0 -cdef void _core(void kernel(dtype_t_out*, Py_ssize_t, Py_ssize_t*, double, dtype_t, - Py_ssize_t, Py_ssize_t, double, +cdef void _core(void kernel(dtype_t_out*, Py_ssize_t, Py_ssize_t*, double, + dtype_t, Py_ssize_t, Py_ssize_t, double, double, Py_ssize_t, Py_ssize_t), dtype_t[:, ::1] image, char[:, ::1] selem, @@ -173,8 +173,8 @@ cdef void _core(void kernel(dtype_t_out*, Py_ssize_t, Py_ssize_t*, double, dtype if is_in_mask(rows, cols, rr, cc, mask_data): histogram_decrement(histo, &pop, image[rr, cc]) - kernel(&out[r, c, 0], odepth, histo, pop, image[r, c], max_bin, mid_bin, - p0, p1, s0, s1) + kernel(&out[r, c, 0], odepth, histo, pop, image[r, c], max_bin, + mid_bin, p0, p1, s0, s1) r += 1 # pass to the next row if r >= rows: @@ -193,8 +193,8 @@ cdef void _core(void kernel(dtype_t_out*, Py_ssize_t, Py_ssize_t*, double, dtype if is_in_mask(rows, cols, rr, cc, mask_data): histogram_decrement(histo, &pop, image[rr, cc]) - kernel(&out[r, c, 0], odepth, histo, pop, image[r, c], max_bin, mid_bin, - p0, p1, s0, s1) + kernel(&out[r, c, 0], odepth, histo, pop, image[r, c], max_bin, + mid_bin, p0, p1, s0, s1) # ---> east to west for c in range(cols - 2, -1, -1): @@ -210,8 +210,8 @@ cdef void _core(void kernel(dtype_t_out*, Py_ssize_t, Py_ssize_t*, double, dtype if is_in_mask(rows, cols, rr, cc, mask_data): histogram_decrement(histo, &pop, image[rr, cc]) - kernel(&out[r, c, 0], odepth, histo, pop, image[r, c], max_bin, mid_bin, - p0, p1, s0, s1) + kernel(&out[r, c, 0], odepth, histo, pop, image[r, c], max_bin, + mid_bin, p0, p1, s0, s1) r += 1 # pass to the next row if r >= rows: diff --git a/skimage/filter/rank/generic.py b/skimage/filter/rank/generic.py index 018d7c0b..f2e75051 100644 --- a/skimage/filter/rank/generic.py +++ b/skimage/filter/rank/generic.py @@ -68,7 +68,8 @@ def _handle_input(image, selem, out, mask, out_dtype=None, pixel_size=1): return image, selem, out, mask, max_bin -def _apply_scalar_per_pixel(func, image, selem, out, mask, shift_x, shift_y, out_dtype=None): +def _apply_scalar_per_pixel(func, image, selem, out, mask, shift_x, shift_y, + out_dtype=None): image, selem, out, mask, max_bin = _handle_input(image, selem, out, mask, out_dtype) @@ -79,10 +80,12 @@ def _apply_scalar_per_pixel(func, image, selem, out, mask, shift_x, shift_y, out return out.reshape(out.shape[:2]) -def _apply_vector_per_pixel(func, image, selem, out, mask, shift_x, shift_y, out_dtype=None, pixel_size=1): +def _apply_vector_per_pixel(func, image, selem, out, mask, shift_x, shift_y, + out_dtype=None, pixel_size=1): image, selem, out, mask, max_bin = _handle_input(image, selem, out, mask, - out_dtype, pixel_size=pixel_size) + out_dtype, + pixel_size=pixel_size) func(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, out=out, max_bin=max_bin) @@ -128,7 +131,8 @@ def autolevel(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ return _apply_scalar_per_pixel(generic_cy._autolevel, image, selem, - out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + out=out, mask=mask, + shift_x=shift_x, shift_y=shift_y) def bottomhat(image, selem, out=None, mask=None, shift_x=False, shift_y=False): @@ -169,7 +173,8 @@ def bottomhat(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ return _apply_scalar_per_pixel(generic_cy._bottomhat, image, selem, - out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + out=out, mask=mask, + shift_x=shift_x, shift_y=shift_y) def equalize(image, selem, out=None, mask=None, shift_x=False, shift_y=False): @@ -207,7 +212,8 @@ def equalize(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ return _apply_scalar_per_pixel(generic_cy._equalize, image, selem, - out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + out=out, mask=mask, + shift_x=shift_x, shift_y=shift_y) def gradient(image, selem, out=None, mask=None, shift_x=False, shift_y=False): @@ -245,7 +251,8 @@ def gradient(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ return _apply_scalar_per_pixel(generic_cy._gradient, image, selem, - out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + out=out, mask=mask, + shift_x=shift_x, shift_y=shift_y) def maximum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): @@ -292,7 +299,8 @@ def maximum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ return _apply_scalar_per_pixel(generic_cy._maximum, image, selem, - out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + out=out, mask=mask, + shift_x=shift_x, shift_y=shift_y) def mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False): @@ -330,7 +338,8 @@ def mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ return _apply_scalar_per_pixel(generic_cy._mean, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) + out=out, mask=mask, + shift_x=shift_x, shift_y=shift_y) def subtract_mean(image, selem, out=None, mask=None, shift_x=False, @@ -369,7 +378,8 @@ def subtract_mean(image, selem, out=None, mask=None, shift_x=False, """ return _apply_scalar_per_pixel(generic_cy._subtract_mean, image, selem, - out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + out=out, mask=mask, + shift_x=shift_x, shift_y=shift_y) def median(image, selem, out=None, mask=None, shift_x=False, shift_y=False): @@ -407,7 +417,8 @@ def median(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ return _apply_scalar_per_pixel(generic_cy._median, image, selem, - out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + out=out, mask=mask, + shift_x=shift_x, shift_y=shift_y) def minimum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): @@ -454,7 +465,8 @@ def minimum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ return _apply_scalar_per_pixel(generic_cy._minimum, image, selem, - out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + out=out, mask=mask, + shift_x=shift_x, shift_y=shift_y) def modal(image, selem, out=None, mask=None, shift_x=False, shift_y=False): @@ -494,7 +506,8 @@ def modal(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ return _apply_scalar_per_pixel(generic_cy._modal, image, selem, - out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + out=out, mask=mask, + shift_x=shift_x, shift_y=shift_y) def enhance_contrast(image, selem, out=None, mask=None, shift_x=False, @@ -537,7 +550,8 @@ def enhance_contrast(image, selem, out=None, mask=None, shift_x=False, """ return _apply_scalar_per_pixel(generic_cy._enhance_contrast, image, selem, - out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + out=out, mask=mask, + shift_x=shift_x, shift_y=shift_y) def pop(image, selem, out=None, mask=None, shift_x=False, shift_y=False): @@ -586,7 +600,8 @@ def pop(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ return _apply_scalar_per_pixel(generic_cy._pop, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) + mask=mask, shift_x=shift_x, + shift_y=shift_y) def sum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): @@ -635,7 +650,8 @@ def sum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ return _apply_scalar_per_pixel(generic_cy._sum, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) + mask=mask, shift_x=shift_x, + shift_y=shift_y) def threshold(image, selem, out=None, mask=None, shift_x=False, shift_y=False): @@ -684,7 +700,8 @@ def threshold(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ return _apply_scalar_per_pixel(generic_cy._threshold, image, selem, - out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + out=out, mask=mask, + shift_x=shift_x, shift_y=shift_y) def tophat(image, selem, out=None, mask=None, shift_x=False, shift_y=False): @@ -725,7 +742,8 @@ def tophat(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ return _apply_scalar_per_pixel(generic_cy._tophat, image, selem, - out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + out=out, mask=mask, + shift_x=shift_x, shift_y=shift_y) def noise_filter(image, selem, out=None, mask=None, shift_x=False, @@ -775,8 +793,9 @@ def noise_filter(image, selem, out=None, mask=None, shift_x=False, selem_cpy = selem.copy() selem_cpy[centre_r, centre_c] = 0 - return _apply_scalar_per_pixel(generic_cy._noise_filter, image, selem_cpy, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) + return _apply_scalar_per_pixel(generic_cy._noise_filter, image, selem_cpy, + out=out, mask=mask, + shift_x=shift_x, shift_y=shift_y) def entropy(image, selem, out=None, mask=None, shift_x=False, shift_y=False): @@ -821,8 +840,9 @@ def entropy(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ return _apply_scalar_per_pixel(generic_cy._entropy, image, selem, - out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, - out_dtype=np.double) + out=out, mask=mask, + shift_x=shift_x, shift_y=shift_y, + out_dtype=np.double) def otsu(image, selem, out=None, mask=None, shift_x=False, shift_y=False): @@ -865,10 +885,12 @@ def otsu(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ return _apply_scalar_per_pixel(generic_cy._otsu, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) + mask=mask, shift_x=shift_x, + shift_y=shift_y) -def windowed_histogram(image, selem, out=None, mask=None, shift_x=False, shift_y=False, n_bins=None): +def windowed_histogram(image, selem, out=None, mask=None, + shift_x=False, shift_y=False, n_bins=None): """Normalized sliding window histogram Parameters @@ -887,18 +909,18 @@ def windowed_histogram(image, selem, out=None, mask=None, shift_x=False, shift_y to the structuring element sizes (center must be inside the given structuring element). n_bins : int or None - The number of histogram bins. Will default to `image.max() + 1` + The number of histogram bins. Will default to ``image.max() + 1`` if None is passed. Returns ------- out : 3-D array with float dtype of dimensions (H,W,N), where (H,W) are - the dimensions of the input image and N is n_bins or image.max()+1 - if no value is provided as a parameter. Effectively, each pixel - is a N-D feature vector that is the histogram. The sum of the - elements in the feature vector will be 1, unless no pixels in the - window were covered by both selem and mask, in which case all - elements will be 0. + the dimensions of the input image and N is n_bins or + ``image.max() + 1`` if no value is provided as a parameter. + Effectively, each pixel is a N-D feature vector that is the histogram. + The sum of the elements in the feature vector will be 1, unless no + pixels in the window were covered by both selem and mask, in which + case all elements will be 0. Examples -------- diff --git a/skimage/filter/rank/generic_cy.pyx b/skimage/filter/rank/generic_cy.pyx index bc54855f..98c8cd8a 100644 --- a/skimage/filter/rank/generic_cy.pyx +++ b/skimage/filter/rank/generic_cy.pyx @@ -407,7 +407,6 @@ cdef inline void _kernel_win_hist(dtype_t_out* out, Py_ssize_t odepth, out[i] = 0 - def _autolevel(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, @@ -527,6 +526,7 @@ def _pop(dtype_t[:, ::1] image, _core(_kernel_pop[dtype_t_out, dtype_t], image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0, max_bin) + def _sum(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, diff --git a/skimage/filter/rank/percentile_cy.pyx b/skimage/filter/rank/percentile_cy.pyx index 6d54999f..5ff584d3 100644 --- a/skimage/filter/rank/percentile_cy.pyx +++ b/skimage/filter/rank/percentile_cy.pyx @@ -285,6 +285,7 @@ def _mean(dtype_t[:, ::1] image, _core(_kernel_mean[dtype_t_out, dtype_t], image, selem, mask, out, shift_x, shift_y, p0, p1, 0, 0, max_bin) + def _sum(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, @@ -295,6 +296,7 @@ def _sum(dtype_t[:, ::1] image, _core(_kernel_sum[dtype_t_out, dtype_t], image, selem, mask, out, shift_x, shift_y, p0, p1, 0, 0, max_bin) + def _subtract_mean(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask,