From 6378bc1c39228848a9114bcaac3fea25228d623d Mon Sep 17 00:00:00 2001 From: walter Date: Fri, 20 May 2016 16:08:04 +0200 Subject: [PATCH 1/9] co-occurrence matrix can be calculated for 16 bit images --- skimage/feature/_texture.pyx | 9 ++++++--- skimage/feature/texture.py | 24 ++++++++++++++++++------ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/skimage/feature/_texture.pyx b/skimage/feature/_texture.pyx index 57d8ec81..3859ef21 100644 --- a/skimage/feature/_texture.pyx +++ b/skimage/feature/_texture.pyx @@ -13,7 +13,7 @@ cdef extern from "numpy/npy_math.h": double NAN "NPY_NAN" -def _glcm_loop(cnp.uint8_t[:, ::1] image, double[:] distances, +def _glcm_loop(cnp.uint16_t[:, ::1] image, double[:] distances, double[:] angles, Py_ssize_t levels, cnp.uint32_t[:, :, :, ::1] out): """Perform co-occurrence matrix accumulation. @@ -29,7 +29,10 @@ def _glcm_loop(cnp.uint8_t[:, ::1] image, double[:] distances, levels : int The input image should contain integers in [0, levels-1], where levels indicate the number of grey-levels counted - (typically 256 for an 8-bit image) + (typically 256 for an 8-bit image). Be aware that the co-occurrence + matrix for every angle and every distance is of size levels x levels. + Choosing a too large level might result in exceedingly large matrix. + If you have 16 bit or 32 bit images, consider binning. out : ndarray On input a 4D array of zeros, and on output it contains the results of the GLCM computation. @@ -38,7 +41,7 @@ def _glcm_loop(cnp.uint8_t[:, ::1] image, double[:] distances, cdef: Py_ssize_t a_idx, d_idx, r, c, rows, cols, row, col - cnp.uint8_t i, j + cnp.uint16_t i, j cnp.float64_t angle, distance with nogil: diff --git a/skimage/feature/texture.py b/skimage/feature/texture.py index 4be6c749..a9adc76b 100644 --- a/skimage/feature/texture.py +++ b/skimage/feature/texture.py @@ -11,7 +11,7 @@ from ._texture import (_glcm_loop, _multiblock_lbp) -def greycomatrix(image, distances, angles, levels=256, symmetric=False, +def greycomatrix(image, distances, angles, levels=None, symmetric=False, normed=False): """Calculate the grey-level co-occurrence matrix. @@ -30,8 +30,10 @@ def greycomatrix(image, distances, angles, levels=256, symmetric=False, levels : int, optional The input image should contain integers in [0, levels-1], where levels indicate the number of grey-levels counted - (typically 256 for an 8-bit image). The maximum value is - 256. + (typically 256 for an 8-bit image). Be aware that the co-occurrence + matrix for every angle and every distance is of size levels x levels. + Choosing a too large level might result in exceedingly large matrix. + If you have 16 bit or 32 bit images, consider binning. symmetric : bool, optional If True, the output matrix `P[:, :, d, theta]` is symmetric. This is accomplished by ignoring the order of value pairs, so both @@ -97,11 +99,21 @@ def greycomatrix(image, distances, angles, levels=256, symmetric=False, assert_nD(distances, 1, 'distances') assert_nD(angles, 1, 'angles') - assert levels <= 256 image = np.ascontiguousarray(image) assert image.min() >= 0 - assert image.max() < levels - image = image.astype(np.uint8) + + image_max = image.max() + if levels is None: + # if levels is not given, we assume that there are [0, image_max -1] levels to + # be considered. There would be only zeros for all other rows and columns. + levels = image_max + 1 + + assert image_max < levels + + # we cast to uint16 (because of fixed typing in cython) + # this has no impact on the size of the co-occurrence matrix. + image = image.astype(np.uint16) + distances = np.ascontiguousarray(distances, dtype=np.float64) angles = np.ascontiguousarray(angles, dtype=np.float64) From 02b21fdfe3a25a66c311fb42430998c7421563bd Mon Sep 17 00:00:00 2001 From: walter Date: Mon, 6 Jun 2016 17:12:57 +0200 Subject: [PATCH 2/9] behaviour for 16 bit images matches behaviour for 8 bit images. --- skimage/feature/texture.py | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/skimage/feature/texture.py b/skimage/feature/texture.py index a9adc76b..e577ab19 100644 --- a/skimage/feature/texture.py +++ b/skimage/feature/texture.py @@ -13,16 +13,15 @@ from ._texture import (_glcm_loop, def greycomatrix(image, distances, angles, levels=None, symmetric=False, normed=False): - """Calculate the grey-level co-occurrence matrix. + """ *** YOYO *** Calculate the grey-level co-occurrence matrix. A grey level co-occurrence matrix is a histogram of co-occurring greyscale values at a given offset over an image. Parameters ---------- - image : array_like of uint8 - Integer typed input image. The image will be cast to uint8, so - the maximum value must be less than 256. + image : array_like of uint8 or uint16. + Integer typed input image. The image will be cast to uint16. distances : array_like List of pixel pair distance offsets. angles : array_like @@ -30,10 +29,8 @@ def greycomatrix(image, distances, angles, levels=None, symmetric=False, levels : int, optional The input image should contain integers in [0, levels-1], where levels indicate the number of grey-levels counted - (typically 256 for an 8-bit image). Be aware that the co-occurrence - matrix for every angle and every distance is of size levels x levels. - Choosing a too large level might result in exceedingly large matrix. - If you have 16 bit or 32 bit images, consider binning. + (typically 256 for an 8-bit image). This argument is required for + 16-bit images and is typically the maximum of the image. symmetric : bool, optional If True, the output matrix `P[:, :, d, theta]` is symmetric. This is accomplished by ignoring the order of value pairs, so both @@ -52,7 +49,8 @@ def greycomatrix(image, distances, angles, levels=None, symmetric=False, `P[i,j,d,theta]` is the number of times that grey-level `j` occurs at a distance `d` and at an angle `theta` from grey-level `i`. If `normed` is `False`, the output is of - type uint32, otherwise it is float64. + type uint32, otherwise it is float64. The dimensions are: + levels x levels x number of distances x number of angles. References ---------- @@ -103,15 +101,25 @@ def greycomatrix(image, distances, angles, levels=None, symmetric=False, assert image.min() >= 0 image_max = image.max() - if levels is None: - # if levels is not given, we assume that there are [0, image_max -1] levels to - # be considered. There would be only zeros for all other rows and columns. - levels = image_max + 1 + + #if image.dtype in [np.float, np.float16, np.float32, np.float] + if image.dtype == np.float: + raise ValueError("Float images are not supported by greycomatrix." + "The image needs to be casted to uint8 or uint16.") + + # for 16 bit images, levels must be set. + if image.dtype != np.uint8: + if levels is None: + raise ValueError("For images other than 8 bit images, argument levels must be set to a user defined value." + "A large value will produce a large output matrix, potentially causing memory problems." + "In this case, one might consider binning the image prior to calling greycomatrix.") + if levels is None: + levels = 256 + assert image_max < levels - # we cast to uint16 (because of fixed typing in cython) - # this has no impact on the size of the co-occurrence matrix. + # image is cast to uint16 (because of fixed typing in cython) image = image.astype(np.uint16) distances = np.ascontiguousarray(distances, dtype=np.float64) From e18e572f358fcac6fd3ce15c22a8b8685677cc7f Mon Sep 17 00:00:00 2001 From: walter Date: Mon, 6 Jun 2016 17:16:38 +0200 Subject: [PATCH 3/9] fixed doc strings and commentaries --- skimage/feature/_texture.pyx | 8 +++----- skimage/feature/texture.py | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/skimage/feature/_texture.pyx b/skimage/feature/_texture.pyx index 3859ef21..9c5ccc34 100644 --- a/skimage/feature/_texture.pyx +++ b/skimage/feature/_texture.pyx @@ -21,7 +21,7 @@ def _glcm_loop(cnp.uint16_t[:, ::1] image, double[:] distances, Parameters ---------- image : ndarray - Input image, which is converted to the uint8 data type. + Input image. The image will be cast to uint16. distances : ndarray List of pixel pair distance offsets. angles : ndarray @@ -29,10 +29,8 @@ def _glcm_loop(cnp.uint16_t[:, ::1] image, double[:] distances, levels : int The input image should contain integers in [0, levels-1], where levels indicate the number of grey-levels counted - (typically 256 for an 8-bit image). Be aware that the co-occurrence - matrix for every angle and every distance is of size levels x levels. - Choosing a too large level might result in exceedingly large matrix. - If you have 16 bit or 32 bit images, consider binning. + (typically 256 for an 8-bit image). This argument is required for + 16-bit images and is typically the maximum of the image. out : ndarray On input a 4D array of zeros, and on output it contains the results of the GLCM computation. diff --git a/skimage/feature/texture.py b/skimage/feature/texture.py index e577ab19..df3ace48 100644 --- a/skimage/feature/texture.py +++ b/skimage/feature/texture.py @@ -105,7 +105,7 @@ def greycomatrix(image, distances, angles, levels=None, symmetric=False, #if image.dtype in [np.float, np.float16, np.float32, np.float] if image.dtype == np.float: raise ValueError("Float images are not supported by greycomatrix." - "The image needs to be casted to uint8 or uint16.") + "The image needs to be casted to an unsigned integer type.") # for 16 bit images, levels must be set. if image.dtype != np.uint8: From cece5e005cdf2d5ade0594a4a262bca708e743e9 Mon Sep 17 00:00:00 2001 From: walter Date: Fri, 10 Jun 2016 12:04:52 +0200 Subject: [PATCH 4/9] small modifications --- skimage/feature/_texture.pyx | 24 ++++++++++++++++++++++-- skimage/feature/texture.py | 25 +++++++++++++++---------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/skimage/feature/_texture.pyx b/skimage/feature/_texture.pyx index 9c5ccc34..5b2371b9 100644 --- a/skimage/feature/_texture.pyx +++ b/skimage/feature/_texture.pyx @@ -13,6 +13,22 @@ cdef extern from "numpy/npy_math.h": double NAN "NPY_NAN" +#ctypedef fused uint_8_16: +# cython.uint8_t +# cython.uint16_t + + +#cpdef char_or_float plus_one(char_or_float var): +# return var + 1 + + +#def show_me(): +# cdef: +# cython.char a = 127 +# cython.float b = 127 +# print 'char', plus_one(a) +# print 'float', plus_one(b) + def _glcm_loop(cnp.uint16_t[:, ::1] image, double[:] distances, double[:] angles, Py_ssize_t levels, cnp.uint32_t[:, :, :, ::1] out): @@ -21,16 +37,20 @@ def _glcm_loop(cnp.uint16_t[:, ::1] image, double[:] distances, Parameters ---------- image : ndarray - Input image. The image will be cast to uint16. + Integer typed input image. Only positive valued images are supported. + If type is uint16, the argument `levels` needs to be set. distances : ndarray List of pixel pair distance offsets. angles : ndarray List of pixel pair angles in radians. levels : int - The input image should contain integers in [0, levels-1], + The input image should contain integers in [0, `levels`-1], where levels indicate the number of grey-levels counted (typically 256 for an 8-bit image). This argument is required for 16-bit images and is typically the maximum of the image. + As the output matrix is at least `levels` x `levels`, it might + be preferable to use binning of the input image rather than + large values for `levels`. out : ndarray On input a 4D array of zeros, and on output it contains the results of the GLCM computation. diff --git a/skimage/feature/texture.py b/skimage/feature/texture.py index df3ace48..c4cdae95 100644 --- a/skimage/feature/texture.py +++ b/skimage/feature/texture.py @@ -13,7 +13,7 @@ from ._texture import (_glcm_loop, def greycomatrix(image, distances, angles, levels=None, symmetric=False, normed=False): - """ *** YOYO *** Calculate the grey-level co-occurrence matrix. + """Calculate the grey-level co-occurrence matrix. A grey level co-occurrence matrix is a histogram of co-occurring greyscale values at a given offset over an image. @@ -21,16 +21,20 @@ def greycomatrix(image, distances, angles, levels=None, symmetric=False, Parameters ---------- image : array_like of uint8 or uint16. - Integer typed input image. The image will be cast to uint16. + Integer typed input image. Only positive valued images are supported. + If type is uint16, the argument `levels` needs to be set. distances : array_like List of pixel pair distance offsets. angles : array_like List of pixel pair angles in radians. levels : int, optional - The input image should contain integers in [0, levels-1], + The input image should contain integers in [0, `levels`-1], where levels indicate the number of grey-levels counted (typically 256 for an 8-bit image). This argument is required for 16-bit images and is typically the maximum of the image. + As the output matrix is at least `levels` x `levels`, it might + be preferable to use binning of the input image rather than + large values for `levels`. symmetric : bool, optional If True, the output matrix `P[:, :, d, theta]` is symmetric. This is accomplished by ignoring the order of value pairs, so both @@ -103,21 +107,22 @@ def greycomatrix(image, distances, angles, levels=None, symmetric=False, image_max = image.max() #if image.dtype in [np.float, np.float16, np.float32, np.float] - if image.dtype == np.float: - raise ValueError("Float images are not supported by greycomatrix." - "The image needs to be casted to an unsigned integer type.") + #if image.dtype == np.float: + if np.issubdtype(image.dtype, np.float): + raise ValueError("Float images are not supported by greycomatrix. " + "The image needs to be cast to an unsigned integer type.") # for 16 bit images, levels must be set. if image.dtype != np.uint8: if levels is None: - raise ValueError("For images other than 8 bit images, argument levels must be set to a user defined value." - "A large value will produce a large output matrix, potentially causing memory problems." - "In this case, one might consider binning the image prior to calling greycomatrix.") + raise ValueError("The levels argument is required for data types other than uint8. " + "The resulting matrix will be at least levels ** 2 in size.") + if levels is None: levels = 256 - assert image_max < levels + assert image_max < levels, "The image maximum needs to be smaller than `levels`." # image is cast to uint16 (because of fixed typing in cython) image = image.astype(np.uint16) From 3b8be94d740a9c16af528f737d9e212f35e0d503 Mon Sep 17 00:00:00 2001 From: walter Date: Fri, 10 Jun 2016 13:11:30 +0200 Subject: [PATCH 5/9] fused types --- skimage/feature/_texture.pyx | 30 ++++++++++++------------------ skimage/feature/texture.py | 4 ++-- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/skimage/feature/_texture.pyx b/skimage/feature/_texture.pyx index 5b2371b9..0988a544 100644 --- a/skimage/feature/_texture.pyx +++ b/skimage/feature/_texture.pyx @@ -13,23 +13,17 @@ cdef extern from "numpy/npy_math.h": double NAN "NPY_NAN" -#ctypedef fused uint_8_16: -# cython.uint8_t -# cython.uint16_t - - -#cpdef char_or_float plus_one(char_or_float var): -# return var + 1 - - -#def show_me(): -# cdef: -# cython.char a = 127 -# cython.float b = 127 -# print 'char', plus_one(a) -# print 'float', plus_one(b) - -def _glcm_loop(cnp.uint16_t[:, ::1] image, double[:] distances, +ctypedef fused uint_8_16: + cnp.uint8_t + cnp.uint16_t + cnp.uint32_t + cnp.uint64_t + cnp.int8_t + cnp.int16_t + cnp.int32_t + cnp.int64_t + +def _glcm_loop(uint_8_16[:, ::1] image, double[:] distances, double[:] angles, Py_ssize_t levels, cnp.uint32_t[:, :, :, ::1] out): """Perform co-occurrence matrix accumulation. @@ -59,7 +53,7 @@ def _glcm_loop(cnp.uint16_t[:, ::1] image, double[:] distances, cdef: Py_ssize_t a_idx, d_idx, r, c, rows, cols, row, col - cnp.uint16_t i, j + uint_8_16 i, j cnp.float64_t angle, distance with nogil: diff --git a/skimage/feature/texture.py b/skimage/feature/texture.py index c4cdae95..c3e19810 100644 --- a/skimage/feature/texture.py +++ b/skimage/feature/texture.py @@ -112,7 +112,7 @@ def greycomatrix(image, distances, angles, levels=None, symmetric=False, raise ValueError("Float images are not supported by greycomatrix. " "The image needs to be cast to an unsigned integer type.") - # for 16 bit images, levels must be set. + # for 16 bit images (or larger), levels must be set. if image.dtype != np.uint8: if levels is None: raise ValueError("The levels argument is required for data types other than uint8. " @@ -125,7 +125,7 @@ def greycomatrix(image, distances, angles, levels=None, symmetric=False, assert image_max < levels, "The image maximum needs to be smaller than `levels`." # image is cast to uint16 (because of fixed typing in cython) - image = image.astype(np.uint16) + #image = image.astype(np.uint16) distances = np.ascontiguousarray(distances, dtype=np.float64) angles = np.ascontiguousarray(angles, dtype=np.float64) From 6a059867ba084124002d6a4bcd46e71724ae6c7c Mon Sep 17 00:00:00 2001 From: walter Date: Fri, 10 Jun 2016 13:13:48 +0200 Subject: [PATCH 6/9] removed commented code lines; fused types work now. --- skimage/feature/_texture.pyx | 1 - skimage/feature/texture.py | 5 ----- 2 files changed, 6 deletions(-) diff --git a/skimage/feature/_texture.pyx b/skimage/feature/_texture.pyx index 0988a544..132e19b8 100644 --- a/skimage/feature/_texture.pyx +++ b/skimage/feature/_texture.pyx @@ -12,7 +12,6 @@ from .._shared.transform cimport integrate cdef extern from "numpy/npy_math.h": double NAN "NPY_NAN" - ctypedef fused uint_8_16: cnp.uint8_t cnp.uint16_t diff --git a/skimage/feature/texture.py b/skimage/feature/texture.py index c3e19810..49763433 100644 --- a/skimage/feature/texture.py +++ b/skimage/feature/texture.py @@ -106,8 +106,6 @@ def greycomatrix(image, distances, angles, levels=None, symmetric=False, image_max = image.max() - #if image.dtype in [np.float, np.float16, np.float32, np.float] - #if image.dtype == np.float: if np.issubdtype(image.dtype, np.float): raise ValueError("Float images are not supported by greycomatrix. " "The image needs to be cast to an unsigned integer type.") @@ -124,9 +122,6 @@ def greycomatrix(image, distances, angles, levels=None, symmetric=False, assert image_max < levels, "The image maximum needs to be smaller than `levels`." - # image is cast to uint16 (because of fixed typing in cython) - #image = image.astype(np.uint16) - distances = np.ascontiguousarray(distances, dtype=np.float64) angles = np.ascontiguousarray(angles, dtype=np.float64) From 2147812ab479b09797355aa8fdebc3c558ee1f08 Mon Sep 17 00:00:00 2001 From: walter Date: Tue, 14 Jun 2016 16:40:21 +0200 Subject: [PATCH 7/9] small corrections on the doc string --- skimage/feature/_texture.pyx | 10 +++++----- skimage/feature/texture.py | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/skimage/feature/_texture.pyx b/skimage/feature/_texture.pyx index 132e19b8..ff77e0a7 100644 --- a/skimage/feature/_texture.pyx +++ b/skimage/feature/_texture.pyx @@ -12,7 +12,7 @@ from .._shared.transform cimport integrate cdef extern from "numpy/npy_math.h": double NAN "NPY_NAN" -ctypedef fused uint_8_16: +ctypedef fused any_int: cnp.uint8_t cnp.uint16_t cnp.uint32_t @@ -22,7 +22,7 @@ ctypedef fused uint_8_16: cnp.int32_t cnp.int64_t -def _glcm_loop(uint_8_16[:, ::1] image, double[:] distances, +def _glcm_loop(any_int[:, ::1] image, double[:] distances, double[:] angles, Py_ssize_t levels, cnp.uint32_t[:, :, :, ::1] out): """Perform co-occurrence matrix accumulation. @@ -31,7 +31,7 @@ def _glcm_loop(uint_8_16[:, ::1] image, double[:] distances, ---------- image : ndarray Integer typed input image. Only positive valued images are supported. - If type is uint16, the argument `levels` needs to be set. + If type is other than uint8, the argument `levels` needs to be set. distances : ndarray List of pixel pair distance offsets. angles : ndarray @@ -40,7 +40,7 @@ def _glcm_loop(uint_8_16[:, ::1] image, double[:] distances, The input image should contain integers in [0, `levels`-1], where levels indicate the number of grey-levels counted (typically 256 for an 8-bit image). This argument is required for - 16-bit images and is typically the maximum of the image. + 16-bit images or higher and is typically the maximum of the image. As the output matrix is at least `levels` x `levels`, it might be preferable to use binning of the input image rather than large values for `levels`. @@ -52,7 +52,7 @@ def _glcm_loop(uint_8_16[:, ::1] image, double[:] distances, cdef: Py_ssize_t a_idx, d_idx, r, c, rows, cols, row, col - uint_8_16 i, j + any_int i, j cnp.float64_t angle, distance with nogil: diff --git a/skimage/feature/texture.py b/skimage/feature/texture.py index 49763433..5317964d 100644 --- a/skimage/feature/texture.py +++ b/skimage/feature/texture.py @@ -20,9 +20,9 @@ def greycomatrix(image, distances, angles, levels=None, symmetric=False, Parameters ---------- - image : array_like of uint8 or uint16. + image : array_like Integer typed input image. Only positive valued images are supported. - If type is uint16, the argument `levels` needs to be set. + If type is other than uint8, the argument `levels` needs to be set. distances : array_like List of pixel pair distance offsets. angles : array_like @@ -31,7 +31,7 @@ def greycomatrix(image, distances, angles, levels=None, symmetric=False, The input image should contain integers in [0, `levels`-1], where levels indicate the number of grey-levels counted (typically 256 for an 8-bit image). This argument is required for - 16-bit images and is typically the maximum of the image. + 16-bit images or higher and is typically the maximum of the image. As the output matrix is at least `levels` x `levels`, it might be preferable to use binning of the input image rather than large values for `levels`. From ed34d9f014cf6c92b51a20a657e4d6cda9190fcd Mon Sep 17 00:00:00 2001 From: walter Date: Wed, 15 Jun 2016 12:57:55 +0200 Subject: [PATCH 8/9] added a test for different data types --- skimage/feature/_texture.pyx | 5 +++-- skimage/feature/tests/test_texture.py | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/skimage/feature/_texture.pyx b/skimage/feature/_texture.pyx index ff77e0a7..fb4189c8 100644 --- a/skimage/feature/_texture.pyx +++ b/skimage/feature/_texture.pyx @@ -7,7 +7,7 @@ cimport numpy as cnp from libc.math cimport sin, cos, abs from .._shared.interpolation cimport bilinear_interpolation, round from .._shared.transform cimport integrate - +import cython cdef extern from "numpy/npy_math.h": double NAN "NPY_NAN" @@ -21,7 +21,8 @@ ctypedef fused any_int: cnp.int16_t cnp.int32_t cnp.int64_t - + + def _glcm_loop(any_int[:, ::1] image, double[:] distances, double[:] angles, Py_ssize_t levels, cnp.uint32_t[:, :, :, ::1] out): diff --git a/skimage/feature/tests/test_texture.py b/skimage/feature/tests/test_texture.py index ae54a6bb..4b88667a 100644 --- a/skimage/feature/tests/test_texture.py +++ b/skimage/feature/tests/test_texture.py @@ -15,6 +15,7 @@ class TestGLCM(): [0, 2, 2, 2], [2, 2, 3, 3]], dtype=np.uint8) + @test_parallel() def test_output_angles(self): result = greycomatrix(self.image, [1], [0, np.pi / 4, np.pi / 2, 3 * np.pi / 4], 4) @@ -50,6 +51,20 @@ class TestGLCM(): [0, 0, 2, 0]], dtype=np.uint32) np.testing.assert_array_equal(result[:, :, 0, 0], expected) + def test_image_data_types(self): + for dtype in [np.uint16, np.uint32, np.uint64, np.int16, np.int32, np.int64]: + img = self.image.astype(dtype) + result = greycomatrix(img, [1], [np.pi / 2], 4, + symmetric=True) + assert result.shape == (4, 4, 1, 1) + expected = np.array([[6, 0, 2, 0], + [0, 4, 2, 0], + [2, 2, 2, 2], + [0, 0, 2, 0]], dtype=np.uint32) + np.testing.assert_array_equal(result[:, :, 0, 0], expected) + + return + def test_output_distance(self): im = np.array([[0, 0, 0, 0], [1, 0, 0, 1], From 6c47bd49ddb90e5196333224a4e6b211fb24d089 Mon Sep 17 00:00:00 2001 From: walter Date: Thu, 16 Jun 2016 10:33:11 +0200 Subject: [PATCH 9/9] tests for image types added --- skimage/feature/tests/test_texture.py | 14 ++++++++++++++ skimage/feature/texture.py | 17 +++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/skimage/feature/tests/test_texture.py b/skimage/feature/tests/test_texture.py index 4b88667a..bfa377e6 100644 --- a/skimage/feature/tests/test_texture.py +++ b/skimage/feature/tests/test_texture.py @@ -51,6 +51,20 @@ class TestGLCM(): [0, 0, 2, 0]], dtype=np.uint32) np.testing.assert_array_equal(result[:, :, 0, 0], expected) + def test_error_raise_float(self): + for dtype in [np.float, np.double, np.float16, np.float32, np.float64]: + np.testing.assert_raises(ValueError, greycomatrix, self.image.astype(dtype), [1], [np.pi], 4) + + def test_error_raise_int_types(self): + for dtype in [np.int16, np.int32, np.int64, np.uint16, np.uint32, np.uint64]: + np.testing.assert_raises(ValueError, greycomatrix, self.image.astype(dtype), [1], [np.pi]) + + def test_error_raise_negative(self): + np.testing.assert_raises(ValueError, greycomatrix, self.image.astype(np.int16) - 1, [1], [np.pi], 4) + + def test_error_raise_levels_smaller_max(self): + np.testing.assert_raises(ValueError, greycomatrix, self.image - 1, [1], [np.pi], 3) + def test_image_data_types(self): for dtype in [np.uint16, np.uint32, np.uint64, np.int16, np.int32, np.int64]: img = self.image.astype(dtype) diff --git a/skimage/feature/texture.py b/skimage/feature/texture.py index 5317964d..4de65c76 100644 --- a/skimage/feature/texture.py +++ b/skimage/feature/texture.py @@ -102,7 +102,6 @@ def greycomatrix(image, distances, angles, levels=None, symmetric=False, assert_nD(angles, 1, 'angles') image = np.ascontiguousarray(image) - assert image.min() >= 0 image_max = image.max() @@ -110,17 +109,19 @@ def greycomatrix(image, distances, angles, levels=None, symmetric=False, raise ValueError("Float images are not supported by greycomatrix. " "The image needs to be cast to an unsigned integer type.") - # for 16 bit images (or larger), levels must be set. - if image.dtype != np.uint8: - if levels is None: - raise ValueError("The levels argument is required for data types other than uint8. " - "The resulting matrix will be at least levels ** 2 in size.") + # for image type > 8bit, levels must be set. + if image.dtype not in (np.uint8, np.int8) and levels is None: + raise ValueError("The levels argument is required for data types other than uint8. " + "The resulting matrix will be at least levels ** 2 in size.") - + if image.dtype in (np.int8, np.int16, np.int32, np.int64) and np.any(image < 0): + raise ValueError("Negative valued images are not supported.") + if levels is None: levels = 256 - assert image_max < levels, "The image maximum needs to be smaller than `levels`." + if image_max >= levels: + raise ValueError("The image maximum needs to be smaller than `levels`.") distances = np.ascontiguousarray(distances, dtype=np.float64) angles = np.ascontiguousarray(angles, dtype=np.float64)