Merge branch 'master' of git://github.com/scikit-image/scikit-image into int_idx_patch

This commit is contained in:
Josh Warner (Mac)
2014-05-08 19:57:06 -05:00
13 changed files with 157 additions and 27 deletions
+15 -2
View File
@@ -32,7 +32,18 @@ let's see an example of how a pre-defined plugin is added to the viewer:
viewer = ImageViewer(image)
viewer += LineProfile(viewer)
viewer.show()
overlay, data = viewer.show()[0]
The viewer's ``show()`` method returns a list of tuples, one for each attached
plugin. Each tuple contains two elements: an overlay of the same shape as the
input image, and a data field (which may be ``None``). A plugin class documents
its return value in its ``output`` method.
In this example, only one plugin is attached, so the list returned by ``show``
will have length 1. We extract the single tuple and bind its ``overlay`` and
``data`` elements to individual variables. Here, ``overlay`` contains an image
of the line drawn on the viewer, and ``data`` contains the 1-dimensional
intensity profile along that line.
At the moment, there are not many plugins pre-defined, but there is a really
simple interface for creating your own plugin. First, let us create a plugin to
@@ -74,8 +85,10 @@ All that's left is to create an image viewer and add the plugin to that viewer.
viewer = ImageViewer(image)
viewer += denoise_plugin
viewer.show()
denoised = viewer.show()[0][0]
Here, we access only the overlay returned by the plugin, which contains the
filtered image for the last used setting of ``weight``.
.. image:: data/denoise_viewer_window.png
.. image:: data/denoise_plugin_window.png
+36
View File
@@ -0,0 +1,36 @@
import numpy as np
from skimage._shared.utils import safe_as_int
def test_int_cast_not_possible():
np.testing.assert_raises(ValueError, safe_as_int, 7.1)
np.testing.assert_raises(ValueError, safe_as_int, [7.1, 0.9])
np.testing.assert_raises(ValueError, safe_as_int, np.r_[7.1, 0.9])
np.testing.assert_raises(ValueError, safe_as_int, (7.1, 0.9))
np.testing.assert_raises(ValueError, safe_as_int, ((3, 4, 1),
(2, 7.6, 289)))
np.testing.assert_raises(ValueError, safe_as_int, 7.1, 0.09)
np.testing.assert_raises(ValueError, safe_as_int, [7.1, 0.9], 0.09)
np.testing.assert_raises(ValueError, safe_as_int, np.r_[7.1, 0.9], 0.09)
np.testing.assert_raises(ValueError, safe_as_int, (7.1, 0.9), 0.09)
np.testing.assert_raises(ValueError, safe_as_int, ((3, 4, 1),
(2, 7.6, 289)), 0.25)
def test_int_cast_possible():
np.testing.assert_equal(safe_as_int(7.1, atol=0.11), 7)
np.testing.assert_equal(safe_as_int(-7.1, atol=0.11), -7)
np.testing.assert_equal(safe_as_int(41.9, atol=0.11), 42)
np.testing.assert_array_equal(safe_as_int([2, 42, 5789234.0, 87, 4]),
np.r_[2, 42, 5789234, 87, 4])
np.testing.assert_array_equal(safe_as_int(np.r_[[[3, 4, 1.000000001],
[7, 2, -8.999999999],
[6, 9, -4234918347.]]]),
np.r_[[[3, 4, 1],
[7, 2, -9],
[6, 9, -4234918347]]])
if __name__ == '__main__':
np.testing.run_module_suite()
+70 -1
View File
@@ -1,12 +1,14 @@
import warnings
import functools
import sys
import numpy as np
import six
from ._warnings import all_warnings
__all__ = ['deprecated', 'get_bound_method_class', 'all_warnings']
__all__ = ['deprecated', 'get_bound_method_class', 'all_warnings',
'safe_as_int']
class skimage_deprecation(Warning):
@@ -72,3 +74,70 @@ def get_bound_method_class(m):
"""
return m.im_class if sys.version < '3' else m.__self__.__class__
def safe_as_int(val, atol=1e-3):
"""
Attempt to safely cast values to integer format.
Parameters
----------
val : scalar or iterable of scalars
Number or container of numbers which are intended to be interpreted as
integers, e.g., for indexing purposes, but which may not carry integer
type.
atol : float
Absolute tolerance away from nearest integer to consider values in
``val`` functionally integers.
Returns
-------
val_int : NumPy scalar or ndarray of dtype `np.int64`
Returns the input value(s) coerced to dtype `np.int64` assuming all
were within ``atol`` of the nearest integer.
Notes
-----
This operation calculates ``val`` modulo 1, which returns the mantissa of
all values. Then all mantissas greater than 0.5 are subtracted from one.
Finally, the absolute tolerance from zero is calculated. If it is less
than ``atol`` for all value(s) in ``val``, they are rounded and returned
in an integer array. Or, if ``val`` was a scalar, a NumPy scalar type is
returned.
If any value(s) are outside the specified tolerance, an informative error
is raised.
Examples
--------
>>> _safe_as_int(7.0)
7
>>> _safe_as_int([9, 4, 2.9999999999])
array([9, 4, 3], dtype=int32)
>>> _safe_as_int(53.01)
Traceback (most recent call last):
...
ValueError: Integer argument required but received 53.1, check inputs.
>>> _safe_as_int(53.01, atol=0.01)
53
"""
mod = np.asarray(val) % 1 # Extract mantissa
# Check for and subtract any mod values > 0.5 from 1
if mod.ndim == 0: # Scalar input, cannot be indexed
if mod > 0.5:
mod = 1 - mod
else: # Iterable input, now ndarray
mod[mod > 0.5] = 1 - mod[mod > 0.5] # Test on each side of nearest int
try:
np.testing.assert_allclose(mod, 0, atol=atol)
except AssertionError:
raise ValueError("Integer argument required but received "
"{0}, check inputs.".format(val))
return np.round(val).astype(np.int64)
+3 -3
View File
@@ -344,9 +344,9 @@ def regionprops(label_image, intensity_image=None, cache=True):
Returns
-------
properties : list
List containing a properties for each region. The properties of each
region can be accessed as attributes and keys.
properties : list of RegionProperties
Each item describes one labeled region, and can be accessed using the
attributes listed below.
Notes
-----
+5 -5
View File
@@ -154,7 +154,7 @@ class TestWatershed(unittest.TestCase):
[-1, -1, 1, 1, 1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1]], out)
self.failUnless(error < eps)
self.assertTrue(error < eps)
def test_watershed03(self):
"watershed 3"
@@ -189,7 +189,7 @@ class TestWatershed(unittest.TestCase):
[-1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1]], out)
self.failUnless(error < eps)
self.assertTrue(error < eps)
def test_watershed04(self):
"watershed 4"
@@ -224,7 +224,7 @@ class TestWatershed(unittest.TestCase):
[-1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1]], out)
self.failUnless(error < eps)
self.assertTrue(error < eps)
def test_watershed05(self):
"watershed 5"
@@ -259,7 +259,7 @@ class TestWatershed(unittest.TestCase):
[-1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1]], out)
self.failUnless(error < eps)
self.assertTrue(error < eps)
def test_watershed06(self):
"watershed 6"
@@ -291,7 +291,7 @@ class TestWatershed(unittest.TestCase):
[-1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1]], out)
self.failUnless(error < eps)
self.assertTrue(error < eps)
def test_watershed07(self):
"A regression test of a competitive case that failed"
@@ -389,7 +389,7 @@ def random_walker(data, labels, beta=130, mode='bf', tol=1.e-3, copy=True,
dims = data[..., 0].shape # To reshape final labeled result
data = img_as_float(data)
if data.ndim == 3: # 2D multispectral, needs singleton in 3rd axis
data = data[:, :, np.newaxis, :].transpose((0, 1, 3, 2))
data = data[:, :, np.newaxis, :]
# Spacing kwarg checks
if spacing is None:
+11 -8
View File
@@ -4,7 +4,7 @@ import warnings
import numpy as np
from scipy import ndimage, spatial
from skimage._shared.utils import get_bound_method_class
from skimage._shared.utils import get_bound_method_class, safe_as_int
from skimage.util import img_as_float
from ._warps_cy import _warp_fast
from .._shared.utils import safe_as_int
@@ -1006,7 +1006,8 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1,
Keyword arguments passed to `inverse_map`.
output_shape : tuple (rows, cols), optional
Shape of the output image generated. By default the shape of the input
image is preserved.
image is preserved. Note that, even for multi-band images, only rows
and columns need to be specified.
order : int, optional
The order of interpolation. The order has to be in the range 0-5:
* 0: Nearest-neighbor
@@ -1077,6 +1078,12 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1,
ishape = np.array(image.shape)
bands = ishape[2]
if output_shape is None:
output_shape = ishape
else:
output_shape = safe_as_int(output_shape)
out = None
# use fast Cython version for specific interpolation orders and input
@@ -1105,17 +1112,13 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1,
dims = []
for dim in range(image.shape[2]):
dims.append(_warp_fast(image[..., dim], matrix,
output_shape=output_shape,
order=order, mode=mode, cval=cval))
output_shape=output_shape,
order=order, mode=mode, cval=cval))
out = np.dstack(dims)
if orig_ndim == 2:
out = out[..., 0]
if out is None: # use ndimage.map_coordinates
if output_shape is None:
output_shape = ishape
rows, cols = output_shape[:2]
# inverse_map is a transformation matrix as numpy array
+9
View File
@@ -248,5 +248,14 @@ def test_inverse():
assert_array_equal(warp(image, inverse_tform), warp(image, tform.inverse))
def test_slow_warp_nonint_oshape():
image = np.random.random((5, 5))
assert_raises(ValueError, warp, image, lambda xy: xy,
output_shape=(13.1, 19.5))
warp(image, lambda xy: xy, output_shape=(13.0001, 19.9999))
if __name__ == "__main__":
run_module_suite()
+3 -3
View File
@@ -63,9 +63,9 @@ class Plugin(QtGui.QDialog):
>>> plugin += Slider('threshold', 0, 255) # doctest: +SKIP
>>>
>>> image = data.coins()
>>> viewer = ImageViewer(image) # doctest: +SKIP
>>> viewer += plugin # doctest: +SKIP
>>> viewer.show() # doctest: +SKIP
>>> viewer = ImageViewer(image) # doctest: +SKIP
>>> viewer += plugin # doctest: +SKIP
>>> thresholded = viewer.show()[0][0] # doctest: +SKIP
The plugin will automatically delegate parameters to `image_filter` based
on its parameter type, i.e., `ptype` (widgets for required arguments must
+1 -1
View File
@@ -6,4 +6,4 @@ from skimage.viewer.plugins.canny import CannyPlugin
image = data.camera()
viewer = ImageViewer(image)
viewer += CannyPlugin()
viewer.show()
canny_edges = viewer.show()[0][0]
+1 -1
View File
@@ -21,4 +21,4 @@ plugin += SaveButtons(name='Save overlay to:')
# Finally, attach the plugin to an image viewer.
viewer = ImageViewer(image)
viewer += plugin
viewer.show()
canny_edges = viewer.show()[0][0]
+1 -1
View File
@@ -6,4 +6,4 @@ from skimage.viewer.plugins.lineprofile import LineProfile
image = data.camera()
viewer = ImageViewer(image)
viewer += LineProfile()
viewer.show()
line, profile = viewer.show()[0]
+1 -1
View File
@@ -6,4 +6,4 @@ from skimage.viewer.plugins.lineprofile import LineProfile
image = data.chelsea()
viewer = ImageViewer(image)
viewer += LineProfile()
viewer.show()
line, rgb_profiles = viewer.show()[0]