From 95a5a98c937a1f8d9cdb5e09de90620704e6cc0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Mon, 7 Oct 2013 22:56:56 +0200 Subject: [PATCH] Fix overflow error --- skimage/morphology/binary.py | 45 +++++++++++++++++++------ skimage/morphology/tests/test_binary.py | 21 ++++++++++++ 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/skimage/morphology/binary.py b/skimage/morphology/binary.py index eaea6773..70fcd6b4 100644 --- a/skimage/morphology/binary.py +++ b/skimage/morphology/binary.py @@ -1,7 +1,38 @@ import numpy as np +import warnings from scipy import ndimage +def _convolve(image, selem, out, cval): + + # determine the smallest integer dtype which does not overflow + selem = selem != 0 + selem_sum = np.sum(selem) + if selem_sum < 2 ** 8: + out_dtype = np.uint8 + elif selem_sum < 2 ** 16: + out_dtype = np.uint16 + else: + out_dtype = np.uint32 + + if out is None: + out = np.zeros_like(image, dtype=out_dtype) + else: + iinfo = np.iinfo(out.dtype) + if iinfo.max - iinfo.min < selem_sum: + raise ValueError('Sum of structuring (=%d) element results in ' + 'overflow for dtype of `out`. You must raise the ' + 'bit-depth.') + + conv = ndimage.convolve(image > 0, selem, output=out, + mode='constant', cval=cval) + + if conv is not None: + out = conv + + return out, selem_sum + + def binary_erosion(image, selem, out=None): """Return fast binary morphological erosion of an image. @@ -29,11 +60,8 @@ def binary_erosion(image, selem, out=None): """ - conv = ndimage.convolve((image > 0).view(np.uint8), selem, output=out, - mode='constant', cval=1) - if conv is not None: - out = conv - return np.equal(out, np.sum(selem), out=out) + out, selem_sum = _convolve(image, selem, out, 1) + return np.equal(out, selem_sum, out=out).astype(np.bool, copy=False) def binary_dilation(image, selem, out=None): @@ -64,11 +92,8 @@ def binary_dilation(image, selem, out=None): """ - conv = ndimage.convolve((image > 0).view(np.uint8), selem, output=out, - mode='constant', cval=0) - if conv is not None: - out = conv - return np.not_equal(out, 0, out=out) + out, _ = _convolve(image, selem, out, 0) + return np.not_equal(out, 0, out=out).astype(np.bool, copy=False) def binary_opening(image, selem, out=None): diff --git a/skimage/morphology/tests/test_binary.py b/skimage/morphology/tests/test_binary.py index 2f47c917..5f831669 100644 --- a/skimage/morphology/tests/test_binary.py +++ b/skimage/morphology/tests/test_binary.py @@ -17,6 +17,27 @@ def test_non_square_image(): testing.assert_array_equal(binary_res, grey_res) +def test_selem_overflow(): + strel = np.ones((17, 17), dtype=np.uint8) + img = np.zeros((20, 20)) + img[2:19, 2:19] = 1 + binary_res = binary.binary_erosion(img, strel) + grey_res = img_as_bool(grey.erosion(img, strel)) + testing.assert_array_equal(binary_res, grey_res) + + +def test_selem_overflow_exception(): + strel = np.ones((17, 17), dtype=np.uint8) + img = np.zeros((20, 20)) + img[2:19, 2:19] = 1 + out = np.zeros((20, 20), dtype=np.uint8) + testing.assert_raises(ValueError, binary.binary_erosion, img, strel, out) + out = np.zeros((20, 20), dtype=np.uint16) + binary_res = binary.binary_erosion(img, strel, out=out) + grey_res = img_as_bool(grey.erosion(img, strel)) + testing.assert_array_equal(binary_res, grey_res) + + def test_binary_erosion(): strel = selem.square(3) binary_res = binary.binary_erosion(bw_lena, strel)