diff --git a/.travis.yml b/.travis.yml index aa1d1341..3c627c85 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,42 +1,68 @@ # vim ft=yaml -# travis-ci.org definition for skimage build -# -# We pretend to be erlang because we can't use the python support in -# travis-ci; it uses virtualenvs, they do not have numpy, scipy, matplotlib, -# and it is impractical to build them -language: erlang -env: - - PYTHON=python PYSUF='' PYVER=2.7 - - PYTHON=python3 PYSUF='3' PYVER=3.2 -install: - - sudo apt-get update # needed for python3-numpy - - sudo apt-get install $PYTHON-dev +# After changing this file, check it on: +# http://lint.travis-ci.org/ + + +language: python + +python: + - 2.6 + +matrix: + include: + - python: 2.7 + env: + - PYTHON=python + - PYVER=2.x + - python: 3.2 + env: + - PYTHON=python3 + - PYVER=3.x + exclude: + - python: 2.6 + +virtualenv: + system_site_packages: true + +before_install: + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start + + - sudo apt-get update - sudo apt-get install $PYTHON-numpy - sudo apt-get install $PYTHON-scipy - - sudo apt-get install $PYTHON-setuptools - - sudo apt-get install $PYTHON-nose - - sudo easy_install$PYSUF pip - - sudo pip-$PYVER install cython - sudo apt-get install libfreeimage3 - - if [[ $PYVER == '2.7' ]]; then sudo apt-get install $PYTHON-matplotlib; fi - - if [[ $PYVER == '3.2' ]]; then sudo pip-$PYVER install git+git://github.com/matplotlib/matplotlib.git@v1.2.x; fi - - sudo pip-$PYVER install flake8 - - sudo pip-$PYVER install six - - $PYTHON setup.py build - - sudo $PYTHON setup.py install + + - if [[ $PYVER == '2.x' ]]; then + - sudo apt-get install $PYTHON-qt4; + - sudo apt-get install $PYTHON-matplotlib; + - fi + - if [[ $PYVER == '3.x' ]]; then + - sudo apt-get install $PYTHON-pyqt4; + - pip install matplotlib; + - fi + + - pip install cython + - pip install flake8 + - pip install six + + - python check_bento_build.py + +install: + - python setup.py build_ext --inplace + script: - # Check if setup.py's match bento.info - - $PYTHON check_bento_build.py - # Change into an innocuous directory and find tests from installation + # Setup matplotlib settings - mkdir $HOME/.matplotlib + - touch $HOME/.matplotlib/matplotlibrc - "echo 'backend : Agg' > $HOME/.matplotlib/matplotlibrc" - "echo 'backend.qt4 : PyQt4' >> $HOME/.matplotlib/matplotlibrc" - - mkdir for_test - - cd for_test - - nosetests-$PYVER --exe -v --cover-package=skimage skimage - # Change back to repository root directory and run all doc examples - - cd .. + # Run all tests + - python -c "import skimage, sys, io; sys.exit(skimage.test_verbose())" + - python -c "import skimage, sys, io; sys.exit(skimage.doctest_verbose())" + # Run all doc examples + - export PYTHONPATH=$(pwd):$PYTHONPATH - for f in doc/examples/*.py; do $PYTHON "$f"; if [ $? -ne 0 ]; then exit 1; fi done - for f in doc/examples/applications/*.py; do $PYTHON "$f"; if [ $? -ne 0 ]; then exit 1; fi done # Run pep8 and flake tests diff --git a/Makefile b/Makefile index a0ca9745..2ace534e 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,10 @@ clean: find . -name "*.so" -o -name "*.pyc" -o -name "*.pyx.md5" | xargs rm -f test: - nosetests skimage + python -c "import skimage, sys, io; sys.exit(skimage.test_verbose())" + +doctest: + python -c "import skimage, sys, io; sys.exit(skimage.doctest_verbose())" coverage: nosetests skimage --with-coverage --cover-package=skimage diff --git a/TODO.txt b/TODO.txt index 3cbf4b53..b867bc73 100644 --- a/TODO.txt +++ b/TODO.txt @@ -4,6 +4,7 @@ Version 0.10 * Remove deprecated parameter `epsilon` of `skimage.viewer.LineProfile` * Remove backwards-compatability of `skimage.measure.regionprops` * Remove {`ratio`, `sigma`} deprecation warnings of `skimage.segmentation.slic` + and also remove explicit `sigma` parameter from doc-string example * Change default mode of random_walker segmentation to 'cg_mg' > 'cg' > 'bf', depending on which optional dependencies are available. * Remove deprecated `out` parameter of `skimage.morphology.binary_*` @@ -12,4 +13,4 @@ Version 0.10 * Remove deprecated function `filter.median_filter` * Remove deprecated `skimage.color.is_gray` and `skimage.color.is_rgb` functions - +* Enable doctests of experimental `skimage.feature.brief` diff --git a/bento.info b/bento.info index fc2fdcf9..84ddf4a8 100644 --- a/bento.info +++ b/bento.info @@ -45,9 +45,9 @@ Library: Extension: skimage.io._plugins._colormixer Sources: skimage/io/_plugins/_colormixer.pyx - Extension: skimage.measure._find_contours + Extension: skimage.measure._find_contours_cy Sources: - skimage/measure/_find_contours.pyx + skimage/measure/_find_contours_cy.pyx Extension: skimage.measure._moments Sources: skimage/measure/_moments.pyx diff --git a/skimage/__init__.py b/skimage/__init__.py index c73a79b7..caec81fe 100644 --- a/skimage/__init__.py +++ b/skimage/__init__.py @@ -52,6 +52,7 @@ img_as_ubyte import os.path as _osp import imp as _imp import functools as _functools +import warnings as _warnings from skimage._shared.utils import deprecated as _deprecated pkg_dir = _osp.abspath(_osp.dirname(__file__)) @@ -68,24 +69,48 @@ try: _imp.find_module('nose') except ImportError: def _test(verbose=False): - """This would invoke the skimage test suite, but nose couldn't be + """This would run all unit tests, but nose couldn't be imported so the test suite can not run. """ raise ImportError("Could not load nose. Unit tests not available.") + + def _doctest(verbose=False): + """This would run all doc tests, but nose couldn't be + imported so the test suite can not run. + """ + raise ImportError("Could not load nose. Doctests not available.") else: - def _test(verbose=False): - """Invoke the skimage test suite.""" + def _test(doctest=False, verbose=False): + """Run all unit tests.""" import nose - args = ['', pkg_dir, '--exe'] + args = ['', pkg_dir, '--exe', '--ignore-files=^_test'] if verbose: args.extend(['-v', '-s']) - nose.run('skimage', argv=args) + if doctest: + args.extend(['--with-doctest', '--ignore-files=^\.', + '--ignore-files=^setup\.py$$', '--ignore-files=test']) + # Make sure warnings do not break the doc tests + with _warnings.catch_warnings(): + _warnings.simplefilter("ignore") + success = nose.run('skimage', argv=args) + else: + success = nose.run('skimage', argv=args) + # Return sys.exit code + if success: + return 0 + else: + return 1 + # do not use `test` as function name as this leads to a recursion problem with # the nose test suite test = _test test_verbose = _functools.partial(test, verbose=True) test_verbose.__doc__ = test.__doc__ +doctest = _functools.partial(test, doctest=True) +doctest.__doc__ = doctest.__doc__ +doctest_verbose = _functools.partial(test, doctest=True, verbose=True) +doctest_verbose.__doc__ = doctest.__doc__ class _Log(Warning): @@ -105,10 +130,9 @@ class _FakeLog(object): """ self._name = name - import warnings warnings.simplefilter("always", _Log) - self._warnings = warnings + self._warnings = _warnings def _warn(self, msg, wtype): self._warnings.warn('%s: %s' % (wtype, msg), _Log) diff --git a/skimage/color/colorlabel.py b/skimage/color/colorlabel.py index 222c50c8..ed74f3a8 100644 --- a/skimage/color/colorlabel.py +++ b/skimage/color/colorlabel.py @@ -112,7 +112,7 @@ def label2rgb(label, image=None, colors=None, alpha=0.3, label = label - offset # Make sure you don't modify the input array. bg_label -= offset - new_type = np.min_scalar_type(label.max()) + new_type = np.min_scalar_type(int(label.max())) if new_type == np.bool: new_type = np.uint8 label = label.astype(new_type) diff --git a/skimage/exposure/exposure.py b/skimage/exposure/exposure.py index fd5d53dd..f703f846 100644 --- a/skimage/exposure/exposure.py +++ b/skimage/exposure/exposure.py @@ -14,7 +14,6 @@ __all__ = ['histogram', 'cumulative_distribution', 'equalize', def histogram(image, nbins=256): """Return histogram of image. - Unlike `numpy.histogram`, this function returns the centers of bins and does not rebin integer arrays. For integer arrays, each integer value has its own bin, which improves speed and intensity-resolution. @@ -40,11 +39,12 @@ def histogram(image, nbins=256): Examples -------- - >>> from skimage import data - >>> hist = histogram(data.camera()) - >>> import matplotlib.pyplot as plt - >>> plt.plot(hist[1], hist[0]) # doctest: +ELLIPSIS - [...] + >>> from skimage import data, exposure, util + >>> image = util.img_as_float(data.camera()) + >>> np.histogram(image, bins=2) + (array([107432, 154712]), array([ 0. , 0.5, 1. ])) + >>> exposure.histogram(image, nbins=2) + (array([107432, 154712]), array([ 0.25, 0.75])) """ sh = image.shape if len(sh) == 3 and sh[-1] < 4: @@ -339,7 +339,8 @@ def adjust_sigmoid(image, cutoff=0.5, gain=10, inv=False): References ---------- .. [1] Gustav J. Braun, "Image Lightness Rescaling Using Sigmoidal Contrast - Enhancement Functions" http://www.cis.rit.edu/fairchild/PDFs/PAP07.pdf + Enhancement Functions", + http://www.cis.rit.edu/fairchild/PDFs/PAP07.pdf """ _assert_non_negative(image) diff --git a/skimage/feature/_brief.py b/skimage/feature/_brief.py index ecc2ec11..8a8d78db 100644 --- a/skimage/feature/_brief.py +++ b/skimage/feature/_brief.py @@ -57,12 +57,11 @@ def brief(image, keypoints, descriptor_size=256, mode='normal', patch_size=49, Examples -------- - >>> import numpy as np - >>> from skimage.feature.corner import corner_peaks, corner_harris - >>> from skimage.feature import pairwise_hamming_distance, brief, match_keypoints_brief - >>> square1 = np.zeros([8, 8], dtype=np.int32) - >>> square1[2:6, 2:6] = 1 - >>> square1 + >> from skimage.feature import corner_peaks, corner_harris, \\ + .. pairwise_hamming_distance, brief, match_keypoints_brief + >> square1 = np.zeros([8, 8], dtype=np.int32) + >> square1[2:6, 2:6] = 1 + >> square1 array([[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0], @@ -71,21 +70,21 @@ def brief(image, keypoints, descriptor_size=256, mode='normal', patch_size=49, [0, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]], dtype=int32) - >>> keypoints1 = corner_peaks(corner_harris(square1), min_distance=1) - >>> keypoints1 + >> keypoints1 = corner_peaks(corner_harris(square1), min_distance=1) + >> keypoints1 array([[2, 2], [2, 5], [5, 2], [5, 5]]) - >>> descriptors1, keypoints1 = brief(square1, keypoints1, patch_size=5) - >>> keypoints1 + >> descriptors1, keypoints1 = brief(square1, keypoints1, patch_size=5) + >> keypoints1 array([[2, 2], [2, 5], [5, 2], [5, 5]]) - >>> square2 = np.zeros([9, 9], dtype=np.int32) - >>> square2[2:7, 2:7] = 1 - >>> square2 + >> square2 = np.zeros([9, 9], dtype=np.int32) + >> square2[2:7, 2:7] = 1 + >> square2 array([[0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 0, 0], @@ -95,24 +94,25 @@ def brief(image, keypoints, descriptor_size=256, mode='normal', patch_size=49, [0, 0, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=int32) - >>> keypoints2 = corner_peaks(corner_harris(square2), min_distance=1) - >>> keypoints2 + >> keypoints2 = corner_peaks(corner_harris(square2), min_distance=1) + >> keypoints2 array([[2, 2], [2, 6], [6, 2], [6, 6]]) - >>> descriptors2, keypoints2 = brief(square2, keypoints2, patch_size=5) - >>> keypoints2 + >> descriptors2, keypoints2 = brief(square2, keypoints2, patch_size=5) + >> keypoints2 array([[2, 2], [2, 6], [6, 2], [6, 6]]) - >>> pairwise_hamming_distance(descriptors1, descriptors2) + >> pairwise_hamming_distance(descriptors1, descriptors2) array([[ 0.03125 , 0.3203125, 0.3671875, 0.6171875], [ 0.3203125, 0.03125 , 0.640625 , 0.375 ], [ 0.375 , 0.6328125, 0.0390625, 0.328125 ], [ 0.625 , 0.3671875, 0.34375 , 0.0234375]]) - >>> match_keypoints_brief(keypoints1, descriptors1, keypoints2, descriptors2) + >> match_keypoints_brief(keypoints1, descriptors1, + .. keypoints2, descriptors2) array([[[ 2, 2], [ 2, 2]], @@ -126,6 +126,7 @@ def brief(image, keypoints, descriptor_size=256, mode='normal', patch_size=49, [ 6, 6]]]) """ + np.random.seed(sample_seed) image = np.squeeze(image) diff --git a/skimage/feature/corner.py b/skimage/feature/corner.py index 53b2241e..a025a7e4 100644 --- a/skimage/feature/corner.py +++ b/skimage/feature/corner.py @@ -2,7 +2,7 @@ import numpy as np from scipy import ndimage from scipy import stats from skimage.color import rgb2grey -from skimage.util import img_as_float +from skimage.util import img_as_float, pad from skimage.feature import peak_local_max @@ -70,10 +70,10 @@ def corner_kitchen_rosenfeld(image): The corner measure is calculated as follows:: (imxx * imy**2 + imyy * imx**2 - 2 * imxy * imx * imy) - ------------------------------------------------------ - (imx**2 + imy**2) + / (imx**2 + imy**2) - Where imx and imy are the first and imxx, imxy, imyy the second derivatives. + Where imx and imy are the first and imxx, imxy, imyy the second + derivatives. Parameters ---------- @@ -147,19 +147,19 @@ def corner_harris(image, method='k', k=0.05, eps=1e-6, sigma=1): Examples -------- >>> from skimage.feature import corner_harris, corner_peaks - >>> square = np.zeros([10, 10]) + >>> square = np.zeros([10, 10], dtype=int) >>> square[2:8, 2:8] = 1 >>> square - array([[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) + array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) >>> corner_peaks(corner_harris(square), min_distance=1) array([[2, 2], [2, 7], @@ -217,19 +217,19 @@ def corner_shi_tomasi(image, sigma=1): Examples -------- >>> from skimage.feature import corner_shi_tomasi, corner_peaks - >>> square = np.zeros([10, 10]) + >>> square = np.zeros([10, 10], dtype=int) >>> square[2:8, 2:8] = 1 >>> square - array([[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) + array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) >>> corner_peaks(corner_shi_tomasi(square), min_distance=1) array([[2, 2], [2, 7], @@ -285,17 +285,17 @@ def corner_foerstner(image, sigma=1): >>> from skimage.feature import corner_foerstner, corner_peaks >>> square = np.zeros([10, 10]) >>> square[2:8, 2:8] = 1 - >>> square - array([[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) + >>> square.astype(int) + array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) >>> w, q = corner_foerstner(square) >>> accuracy_thresh = 0.5 >>> roundness_thresh = 0.3 @@ -351,10 +351,37 @@ def corner_subpix(image, corners, window_size=11, alpha=0.99): foerstner87.fast.pdf .. [2] http://en.wikipedia.org/wiki/Corner_detection + Examples + -------- + >>> from skimage.feature import corner_harris, corner_peaks, corner_subpix + >>> img = np.zeros((10, 10), dtype=int) + >>> img[:5, :5] = 1 + >>> img[5:, 5:] = 1 + >>> img + array([[1, 1, 1, 1, 1, 0, 0, 0, 0, 0], + [1, 1, 1, 1, 1, 0, 0, 0, 0, 0], + [1, 1, 1, 1, 1, 0, 0, 0, 0, 0], + [1, 1, 1, 1, 1, 0, 0, 0, 0, 0], + [1, 1, 1, 1, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 1, 1, 1, 1], + [0, 0, 0, 0, 0, 1, 1, 1, 1, 1], + [0, 0, 0, 0, 0, 1, 1, 1, 1, 1], + [0, 0, 0, 0, 0, 1, 1, 1, 1, 1], + [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]]) + >>> coords = corner_peaks(corner_harris(img), min_distance=2) + >>> coords_subpix = corner_subpix(img, coords, window_size=7) + >>> coords_subpix + array([[ 4.5, 4.5]]) + """ # window extent in one direction - wext = (window_size - 1) / 2 + wext = (window_size - 1) // 2 + + image = pad(image, pad_width=wext, mode='constant', constant_values=0) + + # add pad width, make sure to not modify the input values in-place + corners = corners + wext # normal equation arrays N_dot = np.zeros((2, 2), dtype=np.double) @@ -449,6 +476,9 @@ def corner_subpix(image, corners, window_size=11, alpha=0.99): elif corner_class == 1: corners_subpix[i, :] = y0 + est_edge[0], x0 + est_edge[1] + # subtract pad width + corners_subpix -= wext + return corners_subpix @@ -470,7 +500,7 @@ def corner_peaks(image, min_distance=10, threshold_abs=0, threshold_rel=0.1, Examples -------- - >>> from skimage.feature import peak_local_max, corner_peaks + >>> from skimage.feature import peak_local_max >>> response = np.zeros((5, 5)) >>> response[2:4, 2:4] = 1 >>> response diff --git a/skimage/feature/corner_cy.pyx b/skimage/feature/corner_cy.pyx index 7d558e52..c459ee92 100644 --- a/skimage/feature/corner_cy.pyx +++ b/skimage/feature/corner_cy.pyx @@ -35,7 +35,7 @@ def corner_moravec(image, Py_ssize_t window_size=1): Examples -------- - >>> from skimage.feature import moravec, peak_local_max + >>> from skimage.feature import corner_moravec, peak_local_max >>> square = np.zeros([7, 7]) >>> square[3, 3] = 1 >>> square @@ -46,7 +46,7 @@ def corner_moravec(image, Py_ssize_t window_size=1): [ 0., 0., 0., 0., 0., 0., 0.], [ 0., 0., 0., 0., 0., 0., 0.], [ 0., 0., 0., 0., 0., 0., 0.]]) - >>> moravec(square) + >>> corner_moravec(square) array([[ 0., 0., 0., 0., 0., 0., 0.], [ 0., 0., 0., 0., 0., 0., 0.], [ 0., 0., 1., 1., 1., 0., 0.], diff --git a/skimage/feature/tests/test_corner.py b/skimage/feature/tests/test_corner.py index 66ef41c6..9c07c006 100644 --- a/skimage/feature/tests/test_corner.py +++ b/skimage/feature/tests/test_corner.py @@ -1,5 +1,5 @@ import numpy as np -from numpy.testing import assert_array_equal +from numpy.testing import assert_array_equal, assert_almost_equal from skimage import data from skimage import img_as_float @@ -101,6 +101,22 @@ def test_subpix(): assert_array_equal(subpix[0], (24.5, 24.5)) +def test_subpix_border(): + img = np.zeros((50, 50)) + img[1:25,1:25] = 255 + img[25:-1,25:-1] = 255 + corner = corner_peaks(corner_harris(img), min_distance=1) + subpix = corner_subpix(img, corner, window_size=11) + ref = np.array([[ 0.52040816, 0.52040816], + [ 0.52040816, 24.47959184], + [24.47959184, 0.52040816], + [24.5 , 24.5 ], + [24.52040816, 48.47959184], + [48.47959184, 24.52040816], + [48.47959184, 48.47959184]]) + assert_almost_equal(subpix, ref) + + def test_num_peaks(): """For a bunch of different values of num_peaks, check that peak_local_max returns exactly the right amount of peaks. Test diff --git a/skimage/feature/tests/test_daisy.py b/skimage/feature/tests/test_daisy.py index 40781a64..7f4e85d7 100644 --- a/skimage/feature/tests/test_daisy.py +++ b/skimage/feature/tests/test_daisy.py @@ -86,9 +86,10 @@ def test_daisy_normalization(): def test_daisy_visualization(): - img = img_as_float(data.lena()[:128, :128].mean(axis=2)) + img = img_as_float(data.lena()[:32, :32].mean(axis=2)) descs, descs_img = daisy(img, visualize=True) - assert(descs_img.shape == (128, 128, 3)) + assert(descs_img.shape == (32, 32, 3)) + if __name__ == '__main__': from numpy import testing diff --git a/skimage/filter/_denoise.py b/skimage/filter/_denoise.py index 043399e0..c0aed443 100644 --- a/skimage/filter/_denoise.py +++ b/skimage/filter/_denoise.py @@ -30,14 +30,6 @@ def _denoise_tv_chambolle_3d(im, weight=100, eps=2.e-4, n_iter_max=200): ----- Rudin, Osher and Fatemi algorithm. - Examples - -------- - >>> x, y, z = np.ogrid[0:40, 0:40, 0:40] - >>> mask = (x - 22)**2 + (y - 20)**2 + (z - 17)**2 < 8**2 - >>> mask = mask.astype(np.float) - >>> mask += 0.2 * np.random.randn(*mask.shape) - >>> res = denoise_tv_chambolle(mask, weight=100) - """ px = np.zeros_like(im) @@ -121,13 +113,6 @@ def _denoise_tv_chambolle_2d(im, weight=50, eps=2.e-4, n_iter_max=200): applications, Journal of Mathematical Imaging and Vision, Springer, 2004, 20, 89-97. - Examples - -------- - >>> from skimage import color, data - >>> lena = color.rgb2gray(data.lena()) - >>> lena += 0.5 * lena.std() * np.random.randn(*lena.shape) - >>> denoised_lena = denoise_tv_chambolle(lena, weight=60) - """ px = np.zeros_like(im) @@ -224,13 +209,13 @@ def denoise_tv_chambolle(im, weight=50, eps=2.e-4, n_iter_max=200, 2D example on Lena image: >>> from skimage import color, data - >>> lena = color.rgb2gray(data.lena()) + >>> lena = color.rgb2gray(data.lena())[:50, :50] >>> lena += 0.5 * lena.std() * np.random.randn(*lena.shape) >>> denoised_lena = denoise_tv_chambolle(lena, weight=60) 3D example on synthetic data: - >>> x, y, z = np.ogrid[0:40, 0:40, 0:40] + >>> x, y, z = np.ogrid[0:20, 0:20, 0:20] >>> mask = (x - 22)**2 + (y - 20)**2 + (z - 17)**2 < 8**2 >>> mask = mask.astype(np.float) >>> mask += 0.2*np.random.randn(*mask.shape) diff --git a/skimage/filter/_rank_order.py b/skimage/filter/_rank_order.py index cdd992ff..c7a5ce60 100644 --- a/skimage/filter/_rank_order.py +++ b/skimage/filter/_rank_order.py @@ -36,12 +36,12 @@ def rank_order(image): >>> a = np.array([[1, 4, 5], [4, 4, 1], [5, 1, 1]]) >>> a array([[1, 4, 5], - [4, 4, 1], - [5, 1, 1]]) + [4, 4, 1], + [5, 1, 1]]) >>> rank_order(a) (array([[0, 1, 2], - [1, 1, 0], - [2, 0, 0]], dtype=uint32), array([1, 4, 5])) + [1, 1, 0], + [2, 0, 0]], dtype=uint32), array([1, 4, 5])) >>> b = np.array([-1., 2.5, 3.1, 2.5]) >>> rank_order(b) (array([0, 1, 2, 1], dtype=uint32), array([-1. , 2.5, 3.1])) diff --git a/skimage/filter/lpi_filter.py b/skimage/filter/lpi_filter.py index 5b5705f2..f8d08f34 100644 --- a/skimage/filter/lpi_filter.py +++ b/skimage/filter/lpi_filter.py @@ -62,12 +62,12 @@ class LPIFilter2D(object): >>> filter_params = {'kw1': 1, 'kw2': 2, 'kw3': 3} >>> impulse_response(r, c, **filter_params) + Examples -------- - Gaussian filter: - Use a 1-D gaussian in each direction without normalization - coefficients. + Gaussian filter: Use a 1-D gaussian in each direction without + normalization coefficients. >>> def filt_func(r, c, sigma = 1): ... return np.exp(-np.hypot(r, c)/sigma) >>> filter = LPIFilter2D(filt_func) diff --git a/skimage/filter/rank/__init__.py b/skimage/filter/rank/__init__.py index cfd034f1..04a4b854 100644 --- a/skimage/filter/rank/__init__.py +++ b/skimage/filter/rank/__init__.py @@ -1,10 +1,10 @@ from .generic import (autolevel, bottomhat, equalize, gradient, maximum, mean, subtract_mean, median, minimum, modal, enhance_contrast, pop, threshold, tophat, noise_filter, entropy, otsu) -from .percentile import (autolevel_percentile, gradient_percentile, - mean_percentile, subtract_mean_percentile, - enhance_contrast_percentile, percentile, - pop_percentile, threshold_percentile) +from ._percentile import (autolevel_percentile, gradient_percentile, + mean_percentile, subtract_mean_percentile, + enhance_contrast_percentile, percentile, + pop_percentile, threshold_percentile) from .bilateral import mean_bilateral, pop_bilateral from skimage._shared.utils import deprecated diff --git a/skimage/filter/rank/percentile.py b/skimage/filter/rank/_percentile.py similarity index 100% rename from skimage/filter/rank/percentile.py rename to skimage/filter/rank/_percentile.py diff --git a/skimage/filter/rank/generic.py b/skimage/filter/rank/generic.py index 50c9a370..34c0787b 100644 --- a/skimage/filter/rank/generic.py +++ b/skimage/filter/rank/generic.py @@ -247,8 +247,8 @@ def maximum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): -------- skimage.morphology.dilation - Note - ---- + Notes + ----- * the lower algorithm complexity makes the rank.maximum() more efficient for larger images and structuring elements @@ -397,8 +397,8 @@ def minimum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): -------- skimage.morphology.erosion - Note - ---- + Notes + ----- * the lower algorithm complexity makes the rank.minimum() more efficient for larger images and structuring elements diff --git a/skimage/filter/thresholding.py b/skimage/filter/thresholding.py index 7f980387..2ce8a3e1 100644 --- a/skimage/filter/thresholding.py +++ b/skimage/filter/thresholding.py @@ -57,7 +57,7 @@ def threshold_adaptive(image, block_size, method='gaussian', offset=0, Examples -------- >>> from skimage.data import camera - >>> image = camera() + >>> image = camera()[:50, :50] >>> binary_image1 = threshold_adaptive(image, 15, 'mean') >>> func = lambda arr: arr.mean() >>> binary_image2 = threshold_adaptive(image, 15, 'generic', param=func) diff --git a/skimage/io/_io.py b/skimage/io/_io.py index 54769edc..eb704a6f 100644 --- a/skimage/io/_io.py +++ b/skimage/io/_io.py @@ -248,7 +248,7 @@ def show(): >>> for i in range(4): ... io.imshow(np.random.random((50, 50))) - >>> io.show() + >>> io.show() # doctest: +SKIP ''' return call_plugin('_app_show') diff --git a/skimage/io/collection.py b/skimage/io/collection.py index 175d3b34..5708983a 100644 --- a/skimage/io/collection.py +++ b/skimage/io/collection.py @@ -96,18 +96,14 @@ class MultiImage(object): -------- >>> from skimage import data_dir - >>> img = MultiImage(data_dir + '/multipage.tif') - >>> len(img) + >>> img = MultiImage(data_dir + '/multipage.tif') # doctest: +SKIP + >>> len(img) # doctest: +SKIP 2 - >>> for frame in img: - ... print(frame.shape) + >>> for frame in img: # doctest: +SKIP + ... print(frame.shape) # doctest: +SKIP (15, 10) (15, 10) - The two frames in this image can be shown with matplotlib: - - .. plot:: show_collection.py - """ def __init__(self, filename, conserve_memory=True, dtype=None): """Load a multi-img.""" diff --git a/skimage/measure/__init__.py b/skimage/measure/__init__.py index 108cd7d9..7bcb166a 100755 --- a/skimage/measure/__init__.py +++ b/skimage/measure/__init__.py @@ -1,4 +1,4 @@ -from .find_contours import find_contours +from ._find_contours import find_contours from ._marching_cubes import marching_cubes, mesh_surface_area from ._regionprops import regionprops, perimeter from ._structural_similarity import structural_similarity @@ -23,6 +23,5 @@ __all__ = ['find_contours', 'moments_central', 'moments_normalized', 'moments_hu', - 'sum_blocks', 'marching_cubes', 'mesh_surface_area'] diff --git a/skimage/measure/find_contours.py b/skimage/measure/_find_contours.py similarity index 98% rename from skimage/measure/find_contours.py rename to skimage/measure/_find_contours.py index d36c2110..0eea9126 100755 --- a/skimage/measure/find_contours.py +++ b/skimage/measure/_find_contours.py @@ -1,5 +1,5 @@ import numpy as np -from . import _find_contours +from . import _find_contours_cy from collections import deque @@ -115,8 +115,8 @@ def find_contours(array, level, positive_orientation not in _param_options): raise ValueError('Parameters "fully_connected" and' ' "positive_orientation" must be either "high" or "low".') - point_list = _find_contours.iterate_and_store(array, level, - fully_connected == 'high') + point_list = _find_contours_cy.iterate_and_store(array, level, + fully_connected == 'high') contours = _assemble_contours(_take_2(point_list)) if positive_orientation == 'high': contours = [c[::-1] for c in contours] diff --git a/skimage/measure/_find_contours.pyx b/skimage/measure/_find_contours_cy.pyx similarity index 100% rename from skimage/measure/_find_contours.pyx rename to skimage/measure/_find_contours_cy.pyx diff --git a/skimage/measure/_marching_cubes.py b/skimage/measure/_marching_cubes.py index c3ec9070..7ea0667e 100644 --- a/skimage/measure/_marching_cubes.py +++ b/skimage/measure/_marching_cubes.py @@ -74,13 +74,13 @@ def marching_cubes(volume, level, spacing=(1., 1., 1.)): Regarding visualization of algorithm output, the ``mayavi`` package is recommended. To contour a volume named `myvolume` about the level 0.0:: - >>> from mayavi import mlab - >>> verts, tris = marching_cubes(myvolume, 0.0, (1., 1., 2.)) + >>> from mayavi import mlab # doctest: +SKIP + >>> verts, tris = marching_cubes(myvolume, 0.0, (1., 1., 2.)) # doctest: +SKIP >>> mlab.triangular_mesh([vert[0] for vert in verts], ... [vert[1] for vert in verts], ... [vert[2] for vert in verts], - ... tris) - >>> mlab.show() + ... tris) # doctest: +SKIP + >>> mlab.show() # doctest: +SKIP References ---------- diff --git a/skimage/measure/_regionprops.py b/skimage/measure/_regionprops.py index dfb7eb8c..ef1086da 100644 --- a/skimage/measure/_regionprops.py +++ b/skimage/measure/_regionprops.py @@ -479,13 +479,16 @@ def regionprops(label_image, properties=None, Examples -------- - >>> from skimage.data import coins + >>> from skimage import data, util >>> from skimage.morphology import label - >>> img = coins() > 110 + >>> img = util.img_as_ubyte(data.coins()) > 110 >>> label_img = label(img) >>> props = regionprops(label_img) >>> props[0].centroid # centroid of first labelled object + (22.729879860483141, 81.912285234465827) >>> props[0]['centroid'] # centroid of first labelled object + (22.729879860483141, 81.912285234465827) + """ label_image = np.squeeze(label_image) @@ -505,7 +508,7 @@ def regionprops(label_image, properties=None, for i, sl in enumerate(objects): if sl is None: continue - + label = i + 1 props = _RegionProperties(sl, label, label_image, diff --git a/skimage/measure/block.py b/skimage/measure/block.py index fad5668c..aabd1a39 100644 --- a/skimage/measure/block.py +++ b/skimage/measure/block.py @@ -28,27 +28,25 @@ def block_reduce(image, block_size, func=np.sum, cval=0): -------- >>> from skimage.measure import block_reduce >>> image = np.arange(3*3*4).reshape(3, 3, 4) - >>> image + >>> image # doctest: +NORMALIZE_WHITESPACE array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]], - [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]], - [[24, 25, 26, 27], [28, 29, 30, 31], [32, 33, 34, 35]]]) >>> block_reduce(image, block_size=(3, 3, 1), func=np.mean) array([[[ 16., 17., 18., 19.]]]) - >>> block_reduce(image, block_size=(1, 3, 4), func=np.max) + >>> image_max1 = block_reduce(image, block_size=(1, 3, 4), func=np.max) + >>> image_max1 # doctest: +NORMALIZE_WHITESPACE array([[[11]], - [[23]], - [[35]]]) - >>> block_reduce(image, block_size=(3, 1, 4), func=np.max) + >>> image_max2 = block_reduce(image, block_size=(3, 1, 4), func=np.max) + >>> image_max2 # doctest: +NORMALIZE_WHITESPACE array([[[27], [31], [35]]]) diff --git a/skimage/measure/fit.py b/skimage/measure/fit.py index 66502ffa..e16cd218 100644 --- a/skimage/measure/fit.py +++ b/skimage/measure/fit.py @@ -550,21 +550,23 @@ def ransac(data, model_class, min_samples, residual_threshold, >>> model = EllipseModel() >>> model.estimate(data) - >>> model._params - array([ 4.85808595e+02, 4.51492793e+02, 1.15018491e+03, - 5.52428289e+00, 7.32420126e-01]) + >>> model._params # doctest: +SKIP + array([ -3.30354146e+03, -2.87791160e+03, 5.59062118e+03, + 7.84365066e+00, 7.19203152e-01]) + Estimate ellipse model using RANSAC: >>> ransac_model, inliers = ransac(data, EllipseModel, 5, 3, max_trials=50) - >>> # ransac_model._params, inliers - - Should give the correct result estimated without the faulty data:: - - [ 20.12762373, 29.73563061, 4.81499637, 10.4743584, 0.05217117] - [ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49] + >>> ransac_model._params + array([ 20.12762373, 29.73563063, 4.81499637, 10.4743584 , 0.05217117]) + >>> inliers + array([False, False, False, False, True, True, True, True, True, + True, True, True, True, True, True, True, True, True, + True, True, True, True, True, True, True, True, True, + True, True, True, True, True, True, True, True, True, + True, True, True, True, True, True, True, True, True, + True, True, True, True, True], dtype=bool) Robustly estimate geometric transformation: @@ -578,10 +580,12 @@ def ransac(data, model_class, min_samples, residual_threshold, >>> dst[2] = (50, 50) >>> model, inliers = ransac((src, dst), SimilarityTransform, 2, 10) >>> inliers - array([ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]) - + array([False, False, False, True, True, True, True, True, True, + True, True, True, True, True, True, True, True, True, + True, True, True, True, True, True, True, True, True, + True, True, True, True, True, True, True, True, True, + True, True, True, True, True, True, True, True, True, + True, True, True, True, True], dtype=bool) """ diff --git a/skimage/measure/setup.py b/skimage/measure/setup.py index be57ca7b..af8a4be1 100644 --- a/skimage/measure/setup.py +++ b/skimage/measure/setup.py @@ -12,11 +12,11 @@ def configuration(parent_package='', top_path=None): config = Configuration('measure', parent_package, top_path) config.add_data_dir('tests') - cython(['_find_contours.pyx'], working_path=base_path) + cython(['_find_contours_cy.pyx'], working_path=base_path) cython(['_moments.pyx'], working_path=base_path) cython(['_marching_cubes_cy.pyx'], working_path=base_path) - config.add_extension('_find_contours', sources=['_find_contours.c'], + config.add_extension('_find_contours_cy', sources=['_find_contours_cy.c'], include_dirs=[get_numpy_include_dirs()]) config.add_extension('_moments', sources=['_moments.c'], include_dirs=[get_numpy_include_dirs()]) diff --git a/skimage/morphology/_skeletonize.py b/skimage/morphology/_skeletonize.py index 11181a7b..ddc62008 100644 --- a/skimage/morphology/_skeletonize.py +++ b/skimage/morphology/_skeletonize.py @@ -69,7 +69,7 @@ def skeletonize(image): [0, 0, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 0]], dtype=uint8) >>> skel = skeletonize(ellipse) - >>> skel + >>> skel.astype(np.uint8) array([[0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -212,7 +212,6 @@ def medial_axis(image, mask=None, return_distance=False): Examples -------- - >>> from skimage import morphology >>> square = np.zeros((7, 7), dtype=np.uint8) >>> square[1:-1, 2:-2] = 1 >>> square @@ -223,7 +222,7 @@ def medial_axis(image, mask=None, return_distance=False): [0, 0, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0]], dtype=uint8) - >>> morphology.medial_axis(square).astype(np.uint8) + >>> medial_axis(square).astype(np.uint8) array([[0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0], [0, 0, 0, 1, 0, 0, 0], diff --git a/skimage/morphology/convex_hull.py b/skimage/morphology/convex_hull.py index adc63607..1a26b842 100644 --- a/skimage/morphology/convex_hull.py +++ b/skimage/morphology/convex_hull.py @@ -88,8 +88,8 @@ def convex_hull_object(image, neighbors=8): hull : ndarray of bool Binary image with pixels in convex hull set to True. - Note - ---- + Notes + ----- This function uses skimage.morphology.label to define unique objects, finds the convex hull of each using convex_hull_image, and combines these regions with logical OR. Be aware the convex hulls of unconnected diff --git a/skimage/morphology/misc.py b/skimage/morphology/misc.py index 5c157e7f..dc8290d2 100644 --- a/skimage/morphology/misc.py +++ b/skimage/morphology/misc.py @@ -37,17 +37,17 @@ def remove_small_objects(ar, min_size=64, connectivity=1, in_place=False): >>> a = np.array([[0, 0, 0, 1, 0], ... [1, 1, 1, 0, 0], ... [1, 1, 1, 0, 1]], bool) - >>> b = morphology.remove_small_connected_components(a, 6) + >>> b = morphology.remove_small_objects(a, 6) >>> b array([[False, False, False, False, False], [ True, True, True, False, False], [ True, True, True, False, False]], dtype=bool) - >>> c = morphology.remove_small_connected_components(a, 7, connectivity=2) + >>> c = morphology.remove_small_objects(a, 7, connectivity=2) >>> c array([[False, False, False, True, False], [ True, True, True, False, False], [ True, True, True, False, False]], dtype=bool) - >>> d = morphology.remove_small_connected_components(a, 6, in_place=True) + >>> d = morphology.remove_small_objects(a, 6, in_place=True) >>> d is a True """ diff --git a/skimage/morphology/watershed.py b/skimage/morphology/watershed.py index 2bdb57b2..7318ceea 100644 --- a/skimage/morphology/watershed.py +++ b/skimage/morphology/watershed.py @@ -118,7 +118,8 @@ def watershed(image, markers, connectivity=None, offset=None, mask=None): >>> distance = ndimage.distance_transform_edt(image) >>> from skimage.feature import peak_local_max >>> local_maxi = peak_local_max(distance, labels=image, - ... footprint=np.ones((3, 3))) + ... footprint=np.ones((3, 3)), + ... indices=False) >>> markers = ndimage.label(local_maxi)[0] >>> labels = watershed(-distance, markers, mask=image) diff --git a/skimage/novice/__init__.py b/skimage/novice/__init__.py index 2c76c2b2..029d9a64 100644 --- a/skimage/novice/__init__.py +++ b/skimage/novice/__init__.py @@ -28,17 +28,17 @@ We can create a Picture object open opening an image file >>> picture = novice.open(data.data_dir + '/chelsea.png') Pictures know their format ->>> print picture.format -png +>>> picture.format +'png' ... and where they came from ->>> print picture.path.endswith('chelsea.png') +>>> picture.path.endswith('chelsea.png') True ... and their size ->>> print picture.size +>>> picture.size (451, 300) ->>> print picture.width +>>> picture.width 451 Changing `size` resizes the picture. @@ -51,9 +51,9 @@ and know their location in the picture. ... pixel.red /= 2 Pictures know if they've been modified from the original file ->>> print picture.modified +>>> picture.modified True ->>> print picture.path +>>> print(picture.path) None Pictures can be indexed like arrays @@ -61,11 +61,11 @@ Pictures can be indexed like arrays Saving the picture updates the path attribute, format, and modified state. >>> picture.save('save-demo.jpg') ->>> print picture.path.endswith('save-demo.jpg') +>>> picture.path.endswith('save-demo.jpg') True ->>> print picture.format -jpeg ->>> print picture.modified +>>> picture.format +'jpeg' +>>> picture.modified False """ diff --git a/skimage/segmentation/_join.py b/skimage/segmentation/_join.py index 6095382d..892b85e2 100644 --- a/skimage/segmentation/_join.py +++ b/skimage/segmentation/_join.py @@ -114,9 +114,12 @@ def relabel_sequential(label_field, offset=1): >>> relab array([5, 5, 6, 6, 7, 9, 8]) """ + m = label_field.max() + if not np.issubdtype(label_field.dtype, np.int): + new_type = np.min_scalar_type(int(m)) + label_field = label_field.astype(new_type) labels = np.unique(label_field) labels0 = labels[labels != 0] - m = labels.max() if m == len(labels0): # nothing to do, already 1...n labels return label_field, labels, labels forward_map = np.zeros(m+1, int) diff --git a/skimage/segmentation/slic_superpixels.py b/skimage/segmentation/slic_superpixels.py index 8276b1a8..21df45fd 100644 --- a/skimage/segmentation/slic_superpixels.py +++ b/skimage/segmentation/slic_superpixels.py @@ -87,9 +87,12 @@ def slic(image, n_segments=100, compactness=10., max_iter=10, sigma=None, >>> from skimage.segmentation import slic >>> from skimage.data import lena >>> img = lena() - >>> segments = slic(img, n_segments=100, compactness=10) - >>> # Increasing the compactness parameter yields more square regions - >>> segments = slic(img, n_segments=100, compactness=20) + >>> segments = slic(img, n_segments=100, compactness=10, sigma=0) + + Increasing the compactness parameter yields more square regions: + + >>> segments = slic(img, n_segments=100, compactness=20, sigma=0) + """ if sigma is None: diff --git a/skimage/segmentation/tests/test_join.py b/skimage/segmentation/tests/test_join.py index 548fcc8d..1b59f889 100644 --- a/skimage/segmentation/tests/test_join.py +++ b/skimage/segmentation/tests/test_join.py @@ -61,5 +61,17 @@ def test_relabel_sequential_offset5_with0(): assert_array_equal(inv, inv_ref) +def test_relabel_sequential_dtype(): + ar = np.array([1, 1, 5, 5, 8, 99, 42, 0], dtype=float) + ar_relab, fw, inv = relabel_sequential(ar, offset=5) + ar_relab_ref = np.array([5, 5, 6, 6, 7, 9, 8, 0]) + assert_array_equal(ar_relab, ar_relab_ref) + fw_ref = np.zeros(100, int) + fw_ref[1] = 5; fw_ref[5] = 6; fw_ref[8] = 7; fw_ref[42] = 8; fw_ref[99] = 9 + assert_array_equal(fw, fw_ref) + inv_ref = np.array([0, 0, 0, 0, 0, 1, 5, 8, 42, 99]) + assert_array_equal(inv, inv_ref) + + if __name__ == "__main__": np.testing.run_module_suite() diff --git a/skimage/transform/_geometric.py b/skimage/transform/_geometric.py index 6137383d..eb89460e 100644 --- a/skimage/transform/_geometric.py +++ b/skimage/transform/_geometric.py @@ -797,13 +797,14 @@ def estimate_transform(ttype, src, dst, **kwargs): >>> tform = tf.estimate_transform('similarity', src, dst) - >>> tform.inverse(tform(src)) # == src + >>> np.allclose(tform.inverse(tform(src)), src) + True >>> # warp image using the estimated transformation >>> from skimage import data >>> image = data.camera() - >>> warp(image, inverse_map=tform.inverse) + >>> warp(image, inverse_map=tform.inverse) # doctest: +SKIP >>> # create transformation with explicit parameters >>> tform2 = tf.SimilarityTransform(scale=1.1, rotation=1, @@ -811,7 +812,8 @@ def estimate_transform(ttype, src, dst, **kwargs): >>> # unite transformations, applied in order from left to right >>> tform3 = tform + tform2 - >>> tform3(src) # == tform2(tform(src)) + >>> np.allclose(tform3(src), tform2(tform(src))) + True """ ttype = ttype.lower() @@ -996,25 +998,25 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1, >>> from skimage.transform import SimilarityTransform >>> tform = SimilarityTransform(translation=(0, -10)) - >>> warp(image, tform) + >>> warp(image, tform) # doctest: +SKIP Shift an image to the right with a callable (slow): >>> def shift(xy): ... xy[:, 1] -= 10 ... return xy - >>> warp(image, shift_right) + >>> warp(image, shift_right) # doctest: +SKIP Use a transformation matrix to warp an image (fast): >>> matrix = np.array([[1, 0, 0], [0, 1, -10], [0, 0, 1]]) - >>> warp(image, matrix) + >>> warp(image, matrix) # doctest: +SKIP >>> from skimage.transform import ProjectiveTransform - >>> warp(image, ProjectiveTransform(matrix=matrix)) + >>> warp(image, ProjectiveTransform(matrix=matrix)) # doctest: +SKIP You can also use the inverse of a geometric transformation (fast): - >>> warp(image, tform.inverse) + >>> warp(image, tform.inverse) # doctest: +SKIP """ # Backward API compatibility diff --git a/skimage/transform/_warps.py b/skimage/transform/_warps.py index 64b129dd..23b56164 100644 --- a/skimage/transform/_warps.py +++ b/skimage/transform/_warps.py @@ -252,16 +252,16 @@ def downscale_local_mean(image, factors, cval=0): image : ndarray Down-sampled image with same number of dimensions as input image. - Example - ------- + Examples + -------- >>> a = np.arange(15).reshape(3, 5) >>> a array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) >>> downscale_local_mean(a, (2, 3)) - array([[3.5, 4.], - [5.5, 4.5]]) + array([[ 3.5, 4. ], + [ 5.5, 4.5]]) """ return block_reduce(image, factors, np.mean, cval) diff --git a/skimage/transform/hough_transform.py b/skimage/transform/hough_transform.py index 0a7d35a2..48cad399 100644 --- a/skimage/transform/hough_transform.py +++ b/skimage/transform/hough_transform.py @@ -40,8 +40,7 @@ def hough_line_peaks(hspace, angles, dists, min_distance=9, min_angle=10, Examples -------- - >>> import numpy as np - >>> from skimage.transform import hough_line, hough_peaks + >>> from skimage.transform import hough_line, hough_line_peaks >>> from skimage.draw import line >>> img = np.zeros((15, 15), dtype=np.bool_) >>> rr, cc = line(0, 0, 14, 14) @@ -49,11 +48,9 @@ def hough_line_peaks(hspace, angles, dists, min_distance=9, min_angle=10, >>> rr, cc = line(0, 14, 14, 0) >>> img[cc, rr] = 1 >>> hspace, angles, dists = hough_line(img) - >>> hspace, angles, dists = hough_peaks(hspace, angles, dists) - >>> angles - array([ 0.74590887, -0.79856126]) - >>> dists - array([ 10.74418605, 0.51162791]) + >>> hspace, angles, dists = hough_line_peaks(hspace, angles, dists) + >>> len(angles) + 2 """ diff --git a/skimage/transform/tests/test_radon_transform.py b/skimage/transform/tests/test_radon_transform.py index 6fbc3f62..9e51ad0a 100644 --- a/skimage/transform/tests/test_radon_transform.py +++ b/skimage/transform/tests/test_radon_transform.py @@ -5,17 +5,14 @@ from numpy.testing import assert_raises import itertools import os.path -from skimage.transform import radon, iradon +from skimage.transform import radon, iradon, iradon_sart, rescale from skimage.io import imread from skimage import data_dir -__PHANTOM = imread(os.path.join(data_dir, "phantom.png"), +PHANTOM = imread(os.path.join(data_dir, "phantom.png"), as_grey=True)[::2, ::2] - - -def _get_phantom(): - return __PHANTOM +PHANTOM = rescale(PHANTOM, 0.5, order=1) def _debug_plot(original, result, sinogram=None): @@ -39,7 +36,7 @@ def _debug_plot(original, result, sinogram=None): plt.show() -def rescale(x): +def _rescale_intensity(x): x = x.astype(float) x -= x.min() x /= x.max() @@ -117,7 +114,7 @@ def test_iradon_center(): def check_radon_iradon(interpolation_type, filter_type): debug = False - image = _get_phantom() + image = PHANTOM reconstructed = iradon(radon(image), filter=filter_type, interpolation=interpolation_type) delta = np.mean(np.abs(image - reconstructed)) @@ -128,7 +125,7 @@ def check_radon_iradon(interpolation_type, filter_type): if interpolation_type == 'nearest': allowed_delta = 0.03 else: - allowed_delta = 0.02 + allowed_delta = 0.025 else: allowed_delta = 0.05 assert delta < allowed_delta @@ -156,7 +153,7 @@ def test_iradon_angles(): radon_image_200 = radon(image, theta=np.linspace(0, 180, nb_angles, endpoint=False)) reconstructed = iradon(radon_image_200) - delta_200 = np.mean(abs(rescale(image) - rescale(reconstructed))) + delta_200 = np.mean(abs(_rescale_intensity(image) - _rescale_intensity(reconstructed))) assert delta_200 < 0.03 # Lower number of projections nb_angles = 80 @@ -225,7 +222,7 @@ def test_radon_circle(): r = np.sqrt((c0 - shape[0] // 2)**2 + (c1 - shape[1] // 2)**2) radius = min(shape) // 2 image = np.clip(radius - r, 0, np.inf) - image = rescale(image) + image = _rescale_intensity(image) angles = np.linspace(0, 180, min(shape), endpoint=False) sinogram = radon(image, theta=angles, circle=True) assert np.all(sinogram.std(axis=1) < 1e-2) @@ -314,14 +311,9 @@ def test_order_angles_golden_ratio(): def test_iradon_sart(): - from skimage.io import imread - from skimage import data_dir - from skimage.transform import rescale, radon, iradon_sart - debug = False - shepp_logan = imread(os.path.join(data_dir, "phantom.png"), as_grey=True) - image = rescale(shepp_logan, scale=0.4) + image = rescale(PHANTOM, 0.8) theta_ordered = np.linspace(0., 180., image.shape[0], endpoint=False) theta_missing_wedge = np.linspace(0., 150., image.shape[0], endpoint=True) for theta, error_factor in ((theta_ordered, 1.), @@ -344,15 +336,15 @@ def test_iradon_sart(): delta = np.mean(np.abs(reconstructed - image)) print('delta (1 iteration) =', delta) - assert delta < 0.016 * error_factor + assert delta < 0.02 * error_factor reconstructed = iradon_sart(sinogram, theta, reconstructed) delta = np.mean(np.abs(reconstructed - image)) print('delta (2 iterations) =', delta) - assert delta < 0.013 * error_factor + assert delta < 0.014 * error_factor reconstructed = iradon_sart(sinogram, theta, clip=(0, 1)) delta = np.mean(np.abs(reconstructed - image)) print('delta (1 iteration, clip) =', delta) - assert delta < 0.015 * error_factor + assert delta < 0.018 * error_factor np.random.seed(1239867) shifts = np.random.uniform(-3, 3, sinogram.shape[1]) @@ -377,7 +369,8 @@ def test_iradon_sart(): delta = np.mean(np.abs(reconstructed - image)) print('delta (1 iteration, shifted sinogram) =', delta) - assert delta < 0.018 * error_factor + assert delta < 0.022 * error_factor + if __name__ == "__main__": from numpy.testing import run_module_suite diff --git a/skimage/util/arraypad.py b/skimage/util/arraypad.py index 7ca70f59..66ad55ea 100644 --- a/skimage/util/arraypad.py +++ b/skimage/util/arraypad.py @@ -1220,26 +1220,26 @@ def pad(array, pad_width, mode=None, **kwargs): Examples -------- >>> a = [1, 2, 3, 4, 5] - >>> np.lib.pad(a, (2,3), 'constant', constant_values=(4,6)) + >>> pad(a, (2,3), 'constant', constant_values=(4,6)) array([4, 4, 1, 2, 3, 4, 5, 6, 6, 6]) - >>> np.lib.pad(a, (2,3), 'edge') + >>> pad(a, (2,3), 'edge') array([1, 1, 1, 2, 3, 4, 5, 5, 5, 5]) - >>> np.lib.pad(a, (2,3), 'linear_ramp', end_values=(5,-4)) + >>> pad(a, (2,3), 'linear_ramp', end_values=(5,-4)) array([ 5, 3, 1, 2, 3, 4, 5, 2, -1, -4]) - >>> np.lib.pad(a, (2,), 'maximum') + >>> pad(a, (2,), 'maximum') array([5, 5, 1, 2, 3, 4, 5, 5, 5]) - >>> np.lib.pad(a, (2,), 'mean') + >>> pad(a, (2,), 'mean') array([3, 3, 1, 2, 3, 4, 5, 3, 3]) - >>> np.lib.pad(a, (2,), 'median') + >>> pad(a, (2,), 'median') array([3, 3, 1, 2, 3, 4, 5, 3, 3]) >>> a = [[1,2], [3,4]] - >>> np.lib.pad(a, ((3, 2), (2, 3)), 'minimum') + >>> pad(a, ((3, 2), (2, 3)), 'minimum') array([[1, 1, 1, 2, 1, 1, 1], [1, 1, 1, 2, 1, 1, 1], [1, 1, 1, 2, 1, 1, 1], @@ -1249,19 +1249,19 @@ def pad(array, pad_width, mode=None, **kwargs): [1, 1, 1, 2, 1, 1, 1]]) >>> a = [1, 2, 3, 4, 5] - >>> np.lib.pad(a, (2,3), 'reflect') + >>> pad(a, (2,3), 'reflect') array([3, 2, 1, 2, 3, 4, 5, 4, 3, 2]) - >>> np.lib.pad(a, (2,3), 'reflect', reflect_type='odd') + >>> pad(a, (2,3), 'reflect', reflect_type='odd') array([-1, 0, 1, 2, 3, 4, 5, 6, 7, 8]) - >>> np.lib.pad(a, (2,3), 'symmetric') + >>> pad(a, (2,3), 'symmetric') array([2, 1, 1, 2, 3, 4, 5, 5, 4, 3]) - >>> np.lib.pad(a, (2,3), 'symmetric', reflect_type='odd') + >>> pad(a, (2,3), 'symmetric', reflect_type='odd') array([0, 1, 1, 2, 3, 4, 5, 5, 6, 7]) - >>> np.lib.pad(a, (2,3), 'wrap') + >>> pad(a, (2,3), 'wrap') array([4, 5, 1, 2, 3, 4, 5, 1, 2, 3]) >>> def padwithtens(vector, pad_width, iaxis, kwargs): @@ -1272,7 +1272,7 @@ def pad(array, pad_width, mode=None, **kwargs): >>> a = np.arange(6) >>> a = a.reshape((2,3)) - >>> np.lib.pad(a, 2, padwithtens) + >>> pad(a, 2, padwithtens) array([[10, 10, 10, 10, 10, 10, 10], [10, 10, 10, 10, 10, 10, 10], [10, 10, 0, 1, 2, 10, 10], diff --git a/skimage/util/montage.py b/skimage/util/montage.py index 805b78a8..4bc6aca8 100644 --- a/skimage/util/montage.py +++ b/skimage/util/montage.py @@ -51,31 +51,32 @@ def montage2d(arr_in, fill='mean', rescale_intensity=False, grid_shape=None): >>> import numpy as np >>> from skimage.util.montage import montage2d >>> arr_in = np.arange(3 * 2 * 2).reshape(3, 2, 2) - >>> print(arr_in) # doctest: +NORMALIZE_WHITESPACE - [[[ 0 1] - [ 2 3]] - [[ 4 5] - [ 6 7]] - [[ 8 9] - [10 11]]] + >>> arr_in # doctest: +NORMALIZE_WHITESPACE + array([[[ 0, 1], + [ 2, 3]], + [[ 4, 5], + [ 6, 7]], + [[ 8, 9], + [10, 11]]]) >>> arr_out = montage2d(arr_in) - >>> print(arr_out.shape) + >>> arr_out.shape (4, 4) - >>> print(arr_out) - [[ 0. 1. 4. 5. ] - [ 2. 3. 6. 7. ] - [ 8. 9. 5.5 5.5] - [ 10. 11. 5.5 5.5]] - >>> print(arr_in.mean()) + >>> arr_out + array([[ 0. , 1. , 4. , 5. ], + [ 2. , 3. , 6. , 7. ], + [ 8. , 9. , 5.5, 5.5], + [ 10. , 11. , 5.5, 5.5]]) + >>> arr_in.mean() 5.5 - >>> arr_out_nonsquare = montage2d(arr_in, grid_shape=(3, 4)) - >>> print(arr_out_nonsquare) - [[ 0. 1. 4. 5. ] - [ 2. 3. 6. 7. ] - [ 8. 9. 10. 11. ]] - >>> print(arr_out_nonsquare.shape) - (3, 4) + >>> arr_out_nonsquare = montage2d(arr_in, grid_shape=(1, 3)) + >>> arr_out_nonsquare + array([[ 0., 1., 4., 5., 8., 9.], + [ 2., 3., 6., 7., 10., 11.]]) + >>> arr_out_nonsquare.shape + (2, 6) + """ + assert arr_in.ndim == 3 n_images, height, width = arr_in.shape diff --git a/skimage/viewer/canvastools/painttool.py b/skimage/viewer/canvastools/painttool.py index 3b4132f0..7e7dd33a 100644 --- a/skimage/viewer/canvastools/painttool.py +++ b/skimage/viewer/canvastools/painttool.py @@ -158,8 +158,8 @@ class PaintTool(CanvasToolBase): class CenteredWindow(object): """Window that create slices numpy arrays over 2D windows. - Example - ------- + Examples + -------- >>> a = np.arange(16).reshape(4, 4) >>> w = CenteredWindow(1, a.shape) >>> a[w.at(1, 1)] diff --git a/skimage/viewer/plugins/measure.py b/skimage/viewer/plugins/measure.py index 71412a3b..eeaa13b0 100644 --- a/skimage/viewer/plugins/measure.py +++ b/skimage/viewer/plugins/measure.py @@ -47,4 +47,4 @@ class Measure(Plugin): dx = np.diff(x)[0] dy = np.diff(y)[0] self._length.text = '%.1f' % np.hypot(dx, dy) - self._angle.text = u'%.1f°' % (180 - np.arctan2(dy, dx) * rad2deg) + self._angle.text = '%.1f°' % (180 - np.arctan2(dy, dx) * rad2deg) diff --git a/skimage/viewer/viewers/core.py b/skimage/viewer/viewers/core.py index 8b5eb7ba..ad3bfcc9 100644 --- a/skimage/viewer/viewers/core.py +++ b/skimage/viewer/viewers/core.py @@ -73,7 +73,7 @@ class ImageViewer(QtGui.QMainWindow): >>> from skimage import data >>> image = data.coins() >>> viewer = ImageViewer(image) - >>> # viewer.show() + >>> viewer.show() # doctest: +SKIP """