diff --git a/skimage/feature/_texture.pyx b/skimage/feature/_texture.pyx index b97c6861..44d6e2d6 100644 --- a/skimage/feature/_texture.pyx +++ b/skimage/feature/_texture.pyx @@ -1,10 +1,13 @@ +#cython: cdivison=True +#cython: boundscheck=False +#cython: nonecheck=False +#cython: wraparound=False import numpy as np cimport numpy as np -cimport cython -from libc.math cimport sin, cos, abs, ceil, floor +from libc.math cimport sin, cos, abs +from skimage.transform._project cimport bilinear_interpolation -@cython.boundscheck(False) def _glcm_loop(np.ndarray[dtype=np.uint8_t, ndim=2, negative_indices=False, mode='c'] image, np.ndarray[dtype=np.float64_t, ndim=1, @@ -62,42 +65,7 @@ def _glcm_loop(np.ndarray[dtype=np.uint8_t, ndim=2, out[i, j, d_idx, a_idx] += 1 -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.nonecheck(False) -@cython.cdivision(True) -cdef _bilinear_interpolation(np.ndarray[double, ndim=2] image, - np.ndarray[double, ndim=2] coords, - np.ndarray[double, ndim=1] output, - double r0=0, double c0=0, double cval=0): - cdef double r, c, dr, dc - cdef int i, minr, minc, maxr, maxc - - for i in range(coords.shape[0]): - r = r0 + coords[i, 0] - c = c0 + coords[i, 1] - minr = floor(r) - minc = floor(c) - maxr = ceil(r) - maxc = ceil(c) - dr = r - minr - dc = c - minc - if ( - minr < 0 or maxr >= image.shape[0] - or minc < 0 or maxc >= image.shape[1] - ): - output[i] = cval - else: - top = (1 - dc) * image[minr, minc] + dc * image[minr, maxc] - bottom = (1 - dc) * image[maxr, minc] + dc * image[maxr, maxc] - output[i] = (1 - dr) * top + dr * bottom - - -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.nonecheck(False) -@cython.cdivision(True) -cdef int _bit_rotate_right(int value, int length): +cdef inline int _bit_rotate_right(int value, int length): """Cyclic bit shift to the right. Parameters @@ -111,10 +79,6 @@ cdef int _bit_rotate_right(int value, int length): return (value >> 1) | ((value & 1) << (length - 1)) -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.nonecheck(False) -@cython.cdivision(True) def _local_binary_pattern(np.ndarray[double, ndim=2] image, int P, float R, int method=0): # texture weights @@ -132,11 +96,16 @@ def _local_binary_pattern(np.ndarray[double, ndim=2] image, output_shape = (image.shape[0], image.shape[1]) cdef np.ndarray[double, ndim=2] output = np.zeros(output_shape, 'double') + cdef int rows = image.shape[0] + cdef int cols = image.shape[1] + cdef double lbp cdef int r, c, changes, i for r in range(image.shape[0]): for c in range(image.shape[1]): - _bilinear_interpolation(image, coords, texture, r, c) + for i in range(P): + texture[i] = bilinear_interpolation(image.data, + rows, cols, r + coords[i, 0], c + coords[i, 1], 'C') # signed / thresholded texture for i in range(P): if texture[i] - image[r, c] >= 0: diff --git a/skimage/feature/setup.py b/skimage/feature/setup.py index dd765220..0b0b80bd 100644 --- a/skimage/feature/setup.py +++ b/skimage/feature/setup.py @@ -16,7 +16,8 @@ def configuration(parent_package='', top_path=None): cython(['_template.pyx'], working_path=base_path) config.add_extension('_texture', sources=['_texture.c'], - include_dirs=[get_numpy_include_dirs()]) + include_dirs=[get_numpy_include_dirs(), + '../transform']) config.add_extension('_template', sources=['_template.c'], include_dirs=[get_numpy_include_dirs()]) diff --git a/skimage/feature/tests/test_texture.py b/skimage/feature/tests/test_texture.py index feeffaa2..d48a14f7 100644 --- a/skimage/feature/tests/test_texture.py +++ b/skimage/feature/tests/test_texture.py @@ -154,49 +154,48 @@ class TestLBP(): def test_default(self): lbp = local_binary_pattern(self.image, 8, 1, 'default') - ref = np.array([[ 0., 241., 0., 255., 96., 255.], - [135., 0., 20., 153., 64., 56.], - [198., 255., 12., 191., 0., 124.], - [129., 64., 62., 159., 199., 0.], - [255., 4., 255., 175., 0., 124.], - [ 3., 5., 0., 255., 4., 24.]]) - print lbp + ref = np.array([[ 0, 251, 0, 255, 96, 255], + [143, 0, 20, 153, 64, 56], + [238, 255, 12, 191, 0, 252], + [129, 64., 62, 159, 199, 0], + [255, 4, 255, 175, 0, 254], + [ 3, 5, 0, 255, 4, 24]]) np.testing.assert_array_equal(lbp, ref) def test_ror(self): lbp = local_binary_pattern(self.image, 8, 1, 'ror') - ref = np.array([[ 0., 31., 0., 255., 3., 255.], - [ 15., 0., 5., 51., 1., 7.], - [ 27., 255., 3., 127., 0., 31.], - [ 3., 1., 31., 63., 31., 0.], - [255., 1., 255., 95., 0., 31.], - [ 3., 5., 0., 255., 1., 3.]]) + ref = np.array([[ 0, 127, 0, 255, 3, 255], + [ 31, 0, 5, 51, 1, 7], + [119, 255, 3, 127, 0, 63], + [ 3, 1, 31, 63, 31, 0], + [255, 1, 255, 95, 0, 127], + [ 3, 5, 0, 255, 1, 3]]) np.testing.assert_array_equal(lbp, ref) def test_uniform(self): lbp = local_binary_pattern(self.image, 8, 1, 'uniform') - ref = np.array([[0., 5., 0., 8., 2., 8.], - [4., 0., 9., 9., 1., 3.], - [9., 8., 2., 7., 0., 5.], - [2., 1., 5., 6., 5., 0.], - [8., 1., 8., 9., 0., 5.], - [2., 9., 0., 8., 1., 2.]]) + ref = np.array([[0, 7, 0, 8, 2, 8], + [5, 0, 9, 9, 1, 3], + [9, 8, 2, 7, 0, 6], + [2, 1, 5, 6, 5, 0], + [8, 1, 8, 9, 0, 7], + [2, 9, 0, 8, 1, 2]]) np.testing.assert_array_equal(lbp, ref) def test_var(self): lbp = local_binary_pattern(self.image, 8, 1, 'var') - ref = np.array([[0. , 0.00039254, 0. , 0.00089309, - 0.00030782, 0.00203232], - [0.00037561, 0. , 0.00263827, 0.00163246, - 0.00027414, 0.00039593], - [0.00170876, 0.00130368, 0.00042095, 0.00171893, - 0. , 0.00044912], - [0.00021898, 0.00019464, 0.00082291, 0.00225383, + ref = np.array([[0. , 0.00072786, 0. , 0.00115377, + 0.00032355, 0.00224467], + [0.00051758, 0. , 0.0026383 , 0.00163246, + 0.00027414, 0.00041124], + [0.00192834, 0.00130368, 0.00042095, 0.00171894, + 0. , 0.00063726], + [0.00023048, 0.00019464 , 0.00082291, 0.00225386, 0.00076696, 0. ], - [0.00079791, 0.00013236, 0.0009134 , 0.0014467 , - 0. , 0.00046857], - [0.00022553, 0.00089319, 0. , 0.00089274, - 0.00013659, 0.00031981]]) + [0.00097253, 0.00013236, 0.0009134 , 0.0014467 , + 0. , 0.00082472], + [0.00024701, 0.0012277 , 0. , 0.00109869, + 0.00015445, 0.00035881]]) np.testing.assert_array_almost_equal(lbp, ref)