From 61442e040e57188ac2a384a67a94984b8c70a908 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 10 Jun 2015 11:38:20 +0200 Subject: [PATCH] Switched to using integrate Cython function from skimage._shared. All changes were made to make it fit. --- .../plot_multiblock_local_binary_pattern.py | 48 ++++---- skimage/feature/_texture.pyx | 103 +++++------------- skimage/feature/tests/test_texture.py | 4 - skimage/feature/texture.py | 14 +-- 4 files changed, 56 insertions(+), 113 deletions(-) diff --git a/doc/examples/plot_multiblock_local_binary_pattern.py b/doc/examples/plot_multiblock_local_binary_pattern.py index bb354b94..17102fe3 100644 --- a/doc/examples/plot_multiblock_local_binary_pattern.py +++ b/doc/examples/plot_multiblock_local_binary_pattern.py @@ -3,36 +3,33 @@ Multi-Block Local Binary Pattern for texture classification =========================================================== -In this example, we will see how to compute the multi-block -local binary pattern at a specified image and how to visualize it. +This example shows how to compute multi-block local binary +pattern (MB-LBP) features as well as how to visualize them. -The features are calculated in a way similar to local binary -patterns, except that summed up pixel values -rather than pixel values are used. +The features are calculated similarly to local binary patterns (LBPs), +except that summed blocks are used instead of individual pixel values. -`MB-LBP` is an extension of LBP that can be computed on any -scale in a constant time using integral image. It consists of -`9` equal-sized rectangles. They are used to compute a feature. -Sum of pixels' intensity values in each of them are compared -to the central rectangle and depending on comparison result, -the feature descriptor is computed. +MB-LBP is an extension of LBP that can be computed on multiple scales +in constant time using the integral image. +9 equally-sized rectangles are used to compute a feature. +For each rectangle, the sum of the pixel intensities is computed. +Comparisons of these sums to that of the central rectangle determine +the feature, similarly to LBP (See `LBP `_). -We will start with a simple image that we will generate -to show how the `MB-LBP` works. We will create a `(9, 9)` -rectangle with and divide it into `9` blocks. After this -we will apply `MB-LBP` on it. +First, we generate an image to illustrate the functioning of MB-LBP: +we take a (9, 9) rectangle and divide it into (3, 3) block, +upon which we then apply MB-LBP. """ from __future__ import print_function from skimage.feature import multiblock_local_binary_pattern import numpy as np -from skimage.util import img_as_float from skimage.transform import integral_image -# Create dummy matrix where first and fifth -# rectangles have greater value than the central one -# Therefore, the following bits should be 1. +# Create test matrix where first and fifth +# rectangles starting from top left clockwise +# have greater value than the central one. test_img = np.zeros((9, 9), dtype='uint8') test_img[3:6, 3:6] = 1 test_img[:3, :3] = 50 @@ -43,14 +40,12 @@ test_img[6:, 6:] = 50 # be filled. correct_answer = 0b10001000 -# The function accepts the float images. -# Also it has to be C-contiguous. -test_img = img_as_float(test_img) int_img = integral_image(test_img) lbp_code = multiblock_local_binary_pattern(int_img, 0, 0, 3, 3) -print(lbp_code == correct_answer) +print(correct_answer) +print(lbp_code) """ Now let's apply the operator to a real image and see how the visualization works. @@ -61,7 +56,6 @@ from skimage.feature import draw_multiblock_lbp test_img = data.coins() -test_img = img_as_float(test_img) int_img = integral_image(test_img) lbp_code = multiblock_local_binary_pattern(int_img, 0, 0, 90, 90) @@ -75,8 +69,8 @@ plt.imshow(img, interpolation='nearest') """ .. image:: PLOT2RST.current_figure -On the above plot we see the result of computing a `MB-LBP` and visualization +On the above plot we see the result of computing a MB-LBP and visualization of the computed feature. The rectangles that have less intensity than the central -rectangle are marked with cyan color. The ones that have bigger intensity values -are marked with white color. The central rectangle is left untouched. +rectangle are marked in cyan. The ones that have bigger intensity values +are marked in white. The central rectangle is left untouched. """ diff --git a/skimage/feature/_texture.pyx b/skimage/feature/_texture.pyx index b1b90e8a..f41e8363 100644 --- a/skimage/feature/_texture.pyx +++ b/skimage/feature/_texture.pyx @@ -6,6 +6,7 @@ import numpy as np cimport numpy as cnp from libc.math cimport sin, cos, abs from .._shared.interpolation cimport bilinear_interpolation, round +from .._shared.transform cimport integrate cdef extern from "numpy/npy_math.h": @@ -266,47 +267,6 @@ def _local_binary_pattern(double[:, ::1] image, return np.asarray(output) -cdef inline cnp.double_t _integ(cnp.double_t[:, ::1] img, - Py_ssize_t r0, Py_ssize_t c0, - Py_ssize_t r1, Py_ssize_t c1) nogil: - """Integrate over the integral image in the given window - - This method was created so that `multiblock_local_binary_pattern` - does not have to make a Python call. - - Parameters - ---------- - img : array - The integral image over which to integrate. - r0 : int - The row number of the top left corner. - c0 : int - The column number of the top left corner. - r1 : int - The row number of the bottom right corner. - c1 : int - The column number of the bottom right corner. - - Returns - ------- - ans : double - The integral over the given window. - """ - - cdef cnp.double_t ans = img[r1, c1] - - if (r0 >= 1) and (c0 >= 1): - ans += img[r0 - 1, c0 - 1] - - if (r0 >= 1): - ans -= img[r0 - 1, c1] - - if (c0 >= 1): - ans -= img[r1, c0 - 1] - - return ans - - # Constant values that are used by `multiblock_local_binary_pattern` function. # Values represent offsets of neighbour rectangles relative to central one. # It has order starting from top left and going clockwise. @@ -314,18 +274,16 @@ cdef: Py_ssize_t[::1] mlbp_x_offsets = np.asarray([-1, 0, 1, 1, 1, 0, -1, -1]) Py_ssize_t[::1] mlbp_y_offsets = np.asarray([-1, -1, -1, 0, 1, 1, 1, 0]) -cdef _multiblock_local_binary_pattern(cnp.double_t[:, ::1] int_image, - Py_ssize_t x, - Py_ssize_t y, - Py_ssize_t width, - Py_ssize_t height): +cdef int _multiblock_local_binary_pattern(float[:, ::1] int_image, + Py_ssize_t x, + Py_ssize_t y, + Py_ssize_t width, + Py_ssize_t height): """Multi-block local binary pattern. - Effcient implementation in Cython. - Parameters ---------- - int_image : (N, M) double array + int_image : (N, M) float array Integral image. x : int X-coordinate of top left corner of a rectangle containing feature. @@ -341,7 +299,7 @@ cdef _multiblock_local_binary_pattern(cnp.double_t[:, ::1] int_image, Returns ------- output : int - 8bit MB-LBP feature descriptor. + 8-bit MB-LBP feature descriptor. References ---------- @@ -357,11 +315,11 @@ cdef _multiblock_local_binary_pattern(cnp.double_t[:, ::1] int_image, Py_ssize_t central_rect_y = y + height # Sum of intensity values of central rectangle - cdef double central_rect_val = _integ(int_image, - central_rect_y, - central_rect_x, - central_rect_y + height - 1, - central_rect_x + width - 1) + cdef float central_rect_val = integrate(int_image, + central_rect_y, + central_rect_x, + central_rect_y + height - 1, + central_rect_x + width - 1) cdef: Py_ssize_t element_num, offset_x, offset_y @@ -380,11 +338,11 @@ cdef _multiblock_local_binary_pattern(cnp.double_t[:, ::1] int_image, current_rect_y = central_rect_y + offset_y * height - current_rect_val = _integ(int_image, - current_rect_y, - current_rect_x, - current_rect_y + height - 1, - current_rect_x + width - 1) + current_rect_val = integrate(int_image, + current_rect_y, + current_rect_x, + current_rect_y + height - 1, + current_rect_x + width - 1) has_greater_value = current_rect_val >= central_rect_val @@ -396,23 +354,18 @@ cdef _multiblock_local_binary_pattern(cnp.double_t[:, ::1] int_image, return lbp_code -def multiblock_local_binary_pattern(int_image, - x, - y, - width, - height): +def multiblock_local_binary_pattern(int_image, x, y, width, height): """Multi-block local binary pattern. - The features are calculated in a way similar to local binary - patterns, except that summed up pixel values - rather than pixel values are used. + The features are calculated similarly to local binary patterns (LBPs), + except that summed blocks are used instead of individual pixel values. - MB-LBP is an extension of LBP that can be computed on any - scale in a constant time using integral image. It consists of - 9 equal-sized rectangles. They are used to compute a feature. - Sum of pixels' intensity values in each of them are compared - to the central rectangle and depending on comparison result, - the feature descriptor is computed. + MB-LBP is an extension of LBP that can be computed on multiple scales + in constant time using the integral image. + 9 equally-sized rectangles are used to compute a feature. + For each rectangle, the sum of the pixel intensities is computed. + Comparisons of these sums to that of the central rectangle determine + the feature, similarly to LBP. Parameters ---------- @@ -442,7 +395,7 @@ def multiblock_local_binary_pattern(int_image, http://www.cbsr.ia.ac.cn/users/scliao/papers/Zhang-ICB07-MBLBP.pdf """ - int_image = np.ascontiguousarray(int_image, dtype=np.double) + int_image = np.ascontiguousarray(int_image, dtype=np.float32) lbp_code = _multiblock_local_binary_pattern(int_image, x, y, width, height) return lbp_code diff --git a/skimage/feature/tests/test_texture.py b/skimage/feature/tests/test_texture.py index c9e2c7d5..1647f881 100644 --- a/skimage/feature/tests/test_texture.py +++ b/skimage/feature/tests/test_texture.py @@ -8,7 +8,6 @@ from skimage.feature import ( from skimage._shared.testing import test_parallel from skimage.transform import integral_image -from skimage.util import img_as_float class TestGLCM(): @@ -253,9 +252,6 @@ class TestMBLBP(): # be filled. correct_answer = 0b10001000 - # The function accepts the float images. - # Also it has to be C-contiguous. - test_img = img_as_float(test_img) int_img = integral_image(test_img) lbp_code = multiblock_local_binary_pattern(int_img, 0, 0, 3, 3) diff --git a/skimage/feature/texture.py b/skimage/feature/texture.py index dbadac94..efa119eb 100644 --- a/skimage/feature/texture.py +++ b/skimage/feature/texture.py @@ -306,11 +306,11 @@ def draw_multiblock_lbp(img, ): """Multi-block local binary pattern visualization. - The blocks visualized in the following manner: the center block - is left untouched. The blocks that have higher are covered with - transparent white rectangles. The blocks that have less intensity - are covered with cyan rectangles. The colors can also be specified. - Opacity of visualization is controlled with `alpha` argument. + Blocks with higher sums are colored with transparent white rectangles, + whereas blocks with lower sums are colored cyan. + The blocks that have less intensity are covered with + cyan rectangles. The colors can also be specified. + Opacity of visualization is controlled with `alpha` parameter. Parameters ---------- @@ -359,8 +359,8 @@ def draw_multiblock_lbp(img, # Default colors for regions. # White is for the blocks that are brighter. # Cyan is for the blocks that has less intensity. - color_greater_block = np.asarray(color_greater_block, dtype='float64') - color_less_block = np.asarray(color_less_block, dtype='float64') + color_greater_block = np.asarray(color_greater_block, dtype=np.double) + color_less_block = np.asarray(color_less_block, dtype=np.double) # Copy array to avoid the changes to the original one. output = np.copy(img)