This commit is contained in:
Olivier Debeir
2012-10-29 18:06:42 +01:00
77 changed files with 1313 additions and 544 deletions
+1 -1
View File
@@ -107,7 +107,7 @@
- Johannes Schönberger
Drawing functions, adaptive thresholding, regionprops, geometric
transformations, LBPs, polygon approximations, and more.
transformations, LBPs, polygon approximations, web layout, and more.
- Pavel Campr
Fixes and tests for Histograms of Oriented Gradients.
+4 -4
View File
@@ -4,8 +4,8 @@ Development process
:doc:`Read this overview <gitwash/index>` of how to use Git with
``skimage``. Here's the long and short of it:
* Go to `https://github.com/scikits-image/scikits-image
<http://github.com/scikits-image/scikits-image>`_ and follow the
* Go to `https://github.com/scikit-image/scikit-image
<http://github.com/scikit-image/scikit-image>`_ and follow the
instructions on making your own fork.
* Create a new branch for the feature you want to work on. Since the
branch name will appear in the merge message, use a sensible name
@@ -42,7 +42,7 @@ Guidelines
* Follow the `Python PEPs <http://www.python.org/dev/peps/pep-0008/>`_
where possible.
* No major changes should be committed without review. Ask on the
`mailing list <http://groups.google.com/group/scikits-image>`_ if
`mailing list <http://groups.google.com/group/scikit-image>`_ if
you get no response to your pull request.
* Examples in the gallery should have a maximum figure width of 8 inches.
@@ -99,4 +99,4 @@ detailing the test coverage::
Bugs
````
Please `report bugs on Github <https://github.com/scikits-image/scikits-image/issues>`_.
Please `report bugs on Github <https://github.com/scikit-image/scikit-image/issues>`_.
+1 -1
View File
@@ -1,7 +1,7 @@
Unless otherwise specified by LICENSE.txt files in individual
directories, all code is
Copyright (C) 2011, the scikits-image team
Copyright (C) 2011, the scikit-image team
All rights reserved.
Redistribution and use in source and binary forms, with or without
+2 -2
View File
@@ -3,11 +3,11 @@ Image Processing SciKit
Source
------
https://github.com/scikits-image/scikits-image
https://github.com/scikit-image/scikit-image
Mailing List
------------
http://groups.google.com/group/scikits-image
http://groups.google.com/group/scikit-image
Installation from source
------------------------
+1 -1
View File
@@ -38,7 +38,7 @@ How to make a new release of ``skimage``
- In ``bento.info``, set to ``0.X.dev0``.
- Update the web frontpage:
The webpage is kept in a separate repo: scikits-image-web
The webpage is kept in a separate repo: scikit-image-web
- Sync your branch with the remote repo: ``git pull``.
If you try to ``make gh-pages`` when your branch is out of sync, it
+2 -110
View File
@@ -16,122 +16,14 @@ How to contribute to ``skimage``
Developing Open Source is great fun! Join us on the `skimage mailing
list <http://groups.google.com/group/scikits-image>`_ and tell us which of the
list <http://groups.google.com/group/scikit-image>`_ and tell us which of the
following challenges you'd like to solve.
* Mentoring is available for those new to scientific programming in Python.
* The technical detail of the `development process`_ is given below.
* :doc:`How to use GitHub <gitwash/index>` when developing skimage
* If you're looking something to implement, you can find a list of `requested features on github <https://github.com/scikit-image/scikit-image/wiki/Requested-features>`__. In addition, you can browse the `open issues on github <https://github.com/scikit-image/scikit-image/issues?state=open>`__.
.. contents::
:local:
Tasks
-----
.. :doc:`gsoc2011`
.. :doc:`coverage_table`
Implement Algorithms
````````````````````
- Graph cut segmentation
- `Image colorization <http://www.cs.huji.ac.il/~yweiss/Colorization/>`__
- Fast 2D convex hull (consider using CellProfiler version)
`Algorithm overview <http://www.tcs.fudan.edu.cn/rudolf/Courses/Algorithms/Alg_cs_07w/Webprojects/Zhaobo_hull/index.html#section26>`__.
`One free implementation
<http://cm.bell-labs.com/cm/cs/who/clarkson/2dch.c>`_.
[Compare against current implementation]
- Convex hulls of objects in a labels matrix (simply adapt current convex hull
image code--this one's low hanging fruit). Generalise this solution to also
skeletonize objects in a labels matrix.
- Add binary features (BRIEF, BRISK, FREAK)
- Add `STAR features <http://pr.willowgarage.com/wiki/Star_Detector>`__
- `Blurring kernel estimation <http://bit.ly/Nril3u>`__
Drawing (directly on an ndarray)
````````````````````````````````
- Wu's algorithm for circles
- Text rendering
- Add anti-aliasing
Infrastructure
--------------
- Add @greyimage decorator to check if input is a greyscale image
- :strike:`Implement a new backend system so that we may start including
PyOpenCL-based algorithms`
Adapt existing code for use
```````````````````````````
These snippets and packages have already been written. Some need to be
modified to work as part of the scikit, others may be lacking in documentation
or tests.
* :strike:`Connected components`
* Nadav's bilateral filtering (first compare against CellProfiler's
code, based on http://groups.csail.mit.edu/graphics/bilagrid/bilagrid_web.pdf)
Also see https://github.com/stefanv/scikits-image/tree/bilateral
* 2D image warping via thin-plate splines [ask Zach Pincus]
Merge code provided by `CellProfiler <http://www.cellprofiler.org>`_ team
`````````````````````````````````````````````````````````````````````````
* Roberts filter - convolution with diagonal and anti-diagonal
kernels to detect edges
* Minimum enclosing circles of objects in a labels matrix
* spur removal, thinning, thickening, and other morphological operations on
binary images, framework for creating arbitrary morphological operations
using a 3x3 grid.
Their SVN repository is read-accessible at
- https://svn.broadinstitute.org/CellProfiler/trunk/CellProfiler/cellprofiler
The files for the above algorithms are
- https://svn.broadinstitute.org/CellProfiler/trunk/CellProfiler/cellprofiler/cpmath/cpmorphology.py
- https://svn.broadinstitute.org/CellProfiler/trunk/CellProfiler/cellprofiler/cpmath/filter.py
There are test suites for the files at
- https://svn.broadinstitute.org/CellProfiler/trunk/CellProfiler/cellprofiler/cpmath/tests/test_cpmorphology.py
- https://svn.broadinstitute.org/CellProfiler/trunk/CellProfiler/cellprofiler/cpmath/tests/test_filter.py
Quoting a message from Lee Kamentsky to Stefan van der Walt sent on
5 August 2009::
We're part of the Broad Institute which is non-profit. We would be happy
to include our algorithm code in SciPy under the BSD license since that is
more appropriate for a library that might be integrated into a
commercial product whereas CellProfiler needs the more stringent
protection of GPL as an application.
In 2010, Vebjorn Ljosa officially released parts of the code under a
BSD license (:doc:`cell_profiler` | `original message
<http://groups.google.com/group/scikits-image/browse_thread/thread/c4f8fc584bfd839d>`_).
Thanks to Lee Kamentsky, Thouis Jones and Anne Carpenter and their colleagues
who contributed.
Rework linear filters
`````````````````````
* Fast, SSE2 convolution (high priority) (see prototype in pull requests)
* Should take kernel or function for parameter (currently only takes function)
* Kernel shape should be specifiable (currently defaults to image shape)
io
``
* Update ``qt_plugin.py`` and other plugins to view collections.
* Rewrite GTK backend using GObject Introspection for Py3K compatibility.
* Add DICOM plugin for `GDCM <http://sourceforge.net/apps/mediawiki/gdcm>`__.
* Add ``imread_collection`` to all ``imread`` backends
* Better video loading (move to plugin framework, add backends)
viewer
``````
* Using the visualization tools, add an FFT-domain image editor
docs
````
* Add examples to the gallery
* Write topics for the `user guide
<http://scikits-image.org/docs/dev/user_guide.html>`_
* Integrate BiBTeX plugin into Sphinx build
+7 -4
View File
@@ -1,15 +1,15 @@
Name: scikits-image
Name: scikit-image
Version: 0.8.dev0
Summary: Image processing routines for SciPy
Url: http://scikits-image.org
DownloadUrl: http://github.com/scikits-image/scikits-image
Url: http://scikit-image.org
DownloadUrl: http://github.com/scikit-image/scikit-image
Description: Image Processing SciKit
Image processing algorithms for SciPy, including IO, morphology, filtering,
warping, color manipulation, object detection, etc.
Please refer to the online documentation at
http://scikits-image.org/
http://scikit-image.org/
Maintainer: Stefan van der Walt
MaintainerEmail: stefan@sun.ac.za
License: Modified BSD
@@ -64,6 +64,9 @@ Library:
Extension: skimage.filter._ctmf
Sources:
skimage/filter/_ctmf.pyx
Extension: skimage.filter._denoise
Sources:
skimage/filter/_denoise.pyx
Extension: skimage.morphology.ccomp
Sources:
skimage/morphology/ccomp.pyx
+2 -1
View File
@@ -69,7 +69,8 @@ def print_results(cy_bento, cy_setup):
print(text)
print('-' * len(text))
print # blank line; just for aesthetics
print "Bento errors:"
print "-------------"
if cy_bento:
info("The following extensions in 'bento.info' were not found:")
+4 -4
View File
@@ -77,17 +77,17 @@ qthelp:
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in build/qthelp, like this:"
@echo "# qcollectiongenerator build/qthelp/scikitsimage.qhcp"
@echo "# qcollectiongenerator build/qthelp/scikitimage.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile build/qthelp/scikitsimage.qhc"
@echo "# assistant -collectionFile build/qthelp/scikitimage.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(DEST)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/scikitsimage"
@echo "# ln -s build/devhelp $$HOME/.local/share/devhelp/scikitsimage"
@echo "# mkdir -p $$HOME/.local/share/devhelp/scikitimage"
@echo "# ln -s build/devhelp $$HOME/.local/share/devhelp/scikitimage"
@echo "# devhelp"
latex:
+66
View File
@@ -0,0 +1,66 @@
"""
=============================
Denoising the picture of Lena
=============================
In this example, we denoise a noisy version of the picture of Lena using the
total variation and bilateral denoising filter.
These algorithms typically produce "posterized" images with flat domains
separated by sharp edges. It is possible to change the degree of posterization
by controlling the tradeoff between denoising and faithfulness to the original
image.
Total variation filter
----------------------
The result of this filter is an image that has a minimal total variation norm,
while being as close to the initial image as possible. The total variation is
the L1 norm of the gradient of the image.
Bilateral filter
----------------
A bilateral filter is an edge-preserving and noise reducing filter. It averages
pixels based on their spatial closeness and radiometric similarity.
"""
import numpy as np
import matplotlib.pyplot as plt
from skimage import data, color, img_as_float
from skimage.filter import denoise_tv, denoise_bilateral
lena = img_as_float(data.lena())
lena = lena[220:300, 220:320]
noisy = lena + 0.5 * lena.std() * np.random.random(lena.shape)
noisy = np.clip(noisy, 0, 1)
fig, ax = plt.subplots(nrows=2, ncols=3, figsize=(8, 5))
ax[0, 0].imshow(noisy)
ax[0, 0].axis('off')
ax[0, 0].set_title('noisy')
ax[0, 1].imshow(denoise_tv(noisy, weight=0.1))
ax[0, 1].axis('off')
ax[0, 1].set_title('TV')
ax[0, 2].imshow(denoise_bilateral(noisy, sigma_range=0.03, sigma_spatial=15))
ax[0, 2].axis('off')
ax[0, 2].set_title('Bilateral')
ax[1, 0].imshow(denoise_tv(noisy, weight=0.2))
ax[1, 0].axis('off')
ax[1, 0].set_title('(more) TV')
ax[1, 1].imshow(denoise_bilateral(noisy, sigma_range=0.06, sigma_spatial=15))
ax[1, 1].axis('off')
ax[1, 1].set_title('(more) Bilateral')
ax[1, 2].imshow(lena)
ax[1, 2].axis('off')
ax[1, 2].set_title('original')
fig.subplots_adjust(wspace=0.02, hspace=0.2,
top=0.9, bottom=0.05, left=0, right=1)
plt.show()
-51
View File
@@ -1,51 +0,0 @@
"""
====================================================
Denoising the picture of Lena using total variation
====================================================
In this example, we denoise a noisy version of the picture of Lena
using the total variation denoising filter. The result of this filter
is an image that has a minimal total variation norm, while being as
close to the initial image as possible. The total variation is the L1
norm of the gradient of the image, and minimizing the total variation
typically produces "posterized" images with flat domains separated by
sharp edges.
It is possible to change the degree of posterization by controlling
the tradeoff between denoising and faithfulness to the original image.
"""
import numpy as np
import matplotlib.pyplot as plt
from skimage import data, color, img_as_ubyte
from skimage.filter import tv_denoise
l = img_as_ubyte(color.rgb2gray(data.lena()))
l = l[230:290, 220:320]
noisy = l + 0.4 * l.std() * np.random.random(l.shape)
tv_denoised = tv_denoise(noisy, weight=10)
plt.figure(figsize=(8, 2))
plt.subplot(131)
plt.imshow(noisy, cmap=plt.cm.gray, vmin=40, vmax=220)
plt.axis('off')
plt.title('noisy', fontsize=20)
plt.subplot(132)
plt.imshow(tv_denoised, cmap=plt.cm.gray, vmin=40, vmax=220)
plt.axis('off')
plt.title('TV denoising', fontsize=20)
tv_denoised = tv_denoise(noisy, weight=50)
plt.subplot(133)
plt.imshow(tv_denoised, cmap=plt.cm.gray, vmin=40, vmax=220)
plt.axis('off')
plt.title('(more) TV denoising', fontsize=20)
plt.subplots_adjust(wspace=0.02, hspace=0.02, top=0.9, bottom=0, left=0,
right=1)
plt.show()
+5 -5
View File
@@ -63,8 +63,8 @@ import matplotlib.pyplot as plt
import numpy as np
from skimage.data import lena
from skimage.segmentation import felzenszwalb, \
visualize_boundaries, slic, quickshift
from skimage.segmentation import felzenszwalb, slic, quickshift
from skimage.segmentation import mark_boundaries
from skimage.util import img_as_float
img = img_as_float(lena()[::2, ::2])
@@ -80,11 +80,11 @@ fig, ax = plt.subplots(1, 3)
fig.set_size_inches(8, 3, forward=True)
plt.subplots_adjust(0.05, 0.05, 0.95, 0.95, 0.05, 0.05)
ax[0].imshow(visualize_boundaries(img, segments_fz))
ax[0].imshow(mark_boundaries(img, segments_fz))
ax[0].set_title("Felzenszwalbs's method")
ax[1].imshow(visualize_boundaries(img, segments_slic))
ax[1].imshow(mark_boundaries(img, segments_slic))
ax[1].set_title("SLIC")
ax[2].imshow(visualize_boundaries(img, segments_quick))
ax[2].imshow(mark_boundaries(img, segments_quick))
ax[2].set_title("Quickshift")
for a in ax:
a.set_xticks(())
+33 -6
View File
@@ -27,9 +27,10 @@ plot2rst_rcparams : dict
plot2rst_default_thumb : str
Path (relative to doc root) of default thumbnail image.
plot2rst_thumb_scale : float
Scale factor for thumbnail (e.g., 0.2 to scale plot to 1/5th the
original size).
plot2rst_thumb_shape : float
Shape of thumbnail in pixels. The image is resized to fit within this shape
and the excess is filled with white pixels. This fixed size ensures that
that gallery images are displayed in a grid.
plot2rst_plot_tag : str
When this tag is found in the example file, the current plot is saved and
@@ -73,7 +74,10 @@ import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib import image
from skimage import io
from skimage import transform
from skimage.util.dtype import dtype_range
LITERALINCLUDE = """
@@ -160,7 +164,7 @@ def setup(app):
('../examples', 'auto_examples'), True)
app.add_config_value('plot2rst_rcparams', {}, True)
app.add_config_value('plot2rst_default_thumb', None, True)
app.add_config_value('plot2rst_thumb_scale', 0.25, True)
app.add_config_value('plot2rst_thumb_shape', (250, 300), True)
app.add_config_value('plot2rst_plot_tag', 'PLOT2RST.current_figure', True)
app.add_config_value('plot2rst_index_name', 'index', True)
@@ -335,7 +339,8 @@ def write_example(src_name, src_dir, rst_dir, cfg):
thumb_path = thumb_dir.pjoin(src_name[:-3] + '.png')
first_image_file = image_dir.pjoin(figure_list[0].lstrip('/'))
if first_image_file.exists:
image.thumbnail(first_image_file, thumb_path, cfg.plot2rst_thumb_scale)
first_image = io.imread(first_image_file)
save_thumbnail(first_image, thumb_path, cfg.plot2rst_thumb_shape)
if not thumb_path.exists:
if cfg.plot2rst_default_thumb is None:
@@ -345,6 +350,28 @@ def write_example(src_name, src_dir, rst_dir, cfg):
shutil.copy(cfg.plot2rst_default_thumb, thumb_path)
def save_thumbnail(image, thumb_path, shape):
"""Save image as a thumbnail with the specified shape.
The image is first resized to fit within the specified shape and then
centered in an array of the specified shape before saving.
"""
rescale = min(float(w_1) / w_2 for w_1, w_2 in zip(shape, image.shape))
small_shape = (rescale * np.asarray(image.shape[:2])).astype(int)
small_image = transform.resize(image, small_shape)
if len(image.shape) == 3:
shape = shape + (image.shape[2],)
background_value = dtype_range[small_image.dtype.type][1]
thumb = background_value * np.ones(shape, dtype=small_image.dtype)
i = (shape[0] - small_shape[0]) // 2
j = (shape[1] - small_shape[1]) // 2
thumb[i:i+small_shape[0], j:j+small_shape[1]] = small_image
io.imsave(thumb_path, thumb)
def _plots_are_current(src_path, image_path):
first_image_file = Path(image_path.format(1))
needs_replot = (not first_image_file.exists or
+2 -2
View File
@@ -1,11 +1,11 @@
.PHONY: logo
logo: green_orange_snake.png snake_logo.svg
inkscape --export-png=scikits_image_logo.png --export-dpi=100 \
inkscape --export-png=scikit_image_logo.png --export-dpi=100 \
--export-area-drawing --export-background-opacity=1 \
snake_logo.svg
python shrink_logo.py
green_orange_snake.png:
python scikits_image_logo.py --no-plot
python scikit_image_logo.py --no-plot
+2 -2
View File
@@ -2,7 +2,7 @@ from skimage import io, transform
s = 0.7
img = io.imread('scikits_image_logo.png')
img = io.imread('scikit_image_logo.png')
h, w, c = img.shape
print "\nScaling down logo by %.1fx..." % s
@@ -13,4 +13,4 @@ img = transform.homography(img, [[s, 0, 0],
output_shape=(int(h*s), int(w*s), 4),
order=3)
io.imsave('scikits_image_logo_small.png', img)
io.imsave('scikit_image_logo_small.png', img)
+2 -2
View File
@@ -74,9 +74,9 @@ if "%1" == "qthelp" (
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in build/qthelp, like this:
echo.^> qcollectiongenerator build\qthelp\scikitsimage.qhcp
echo.^> qcollectiongenerator build\qthelp\scikitimage.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile build\qthelp\scikitsimage.ghc
echo.^> assistant -collectionFile build\qthelp\scikitimage.ghc
goto end
)
+2 -2
View File
@@ -9,11 +9,11 @@ Python (>=2.6 or 3.x), NumPy and SciPy can be installed.
For more information, visit our website
http://scikit-image.org
http://scikits-image.org
or the examples gallery at
http://scikit-image.org/docs/0.3/auto_examples/
http://scikits-image.org/docs/0.3/auto_examples/
New Features
------------
+5 -5
View File
@@ -1,26 +1,26 @@
Announcement: scikit-image 0.4
Announcement: scikits-image 0.4
===============================
We're happy to announce the 0.4 release of scikit-image, an image processing
We're happy to announce the 0.4 release of scikits-image, an image processing
toolbox for SciPy.
Please visit our examples gallery to see what we've been up to:
http://scikit-image.org/docs/0.4/auto_examples/
http://scikits-image.org/docs/0.4/auto_examples/
Note that, in this release, we renamed the module from ``scikits.image`` to
``skimage``, to work around name space conflicts with other scikits (similarly,
the machine learning scikit is now imported as ``sklearn``).
A big shout-out also to everyone currently at SciPy India; have fun, and
remember to join the scikit-image sprint!
remember to join the scikits-image sprint!
This release runs under all major operating systems where Python (>=2.6 or
3.x), NumPy and SciPy can be installed.
For more information, visit our website
http://scikit-image.org
http://scikits-image.org
New Features
------------
+3 -3
View File
@@ -1,12 +1,12 @@
Announcement: scikit-image 0.5
Announcement: scikits-image 0.5
===============================
We're happy to announce the 0.5 release of scikit-image, our image processing
We're happy to announce the 0.5 release of scikits-image, our image processing
toolbox for SciPy.
For more information, please visit our website
http://scikit-image.org
http://scikits-image.org
New Features
------------
+3 -3
View File
@@ -1,9 +1,9 @@
Announcement: scikit-image 0.6
Announcement: scikits-image 0.6
===============================
We're happy to announce the 6th version of scikit-image!
We're happy to announce the 6th version of scikits-image!
scikit-image is an image processing toolbox for SciPy that includes algorithms
Scikits-image is an image processing toolbox for SciPy that includes algorithms
for segmentation, geometric transformations, color space manipulation,
analysis, filtering, morphology, feature detection, and more.
+4 -4
View File
@@ -1,9 +1,9 @@
Announcement: scikit-image 0.7.0
Announcement: scikits-image 0.7.0
=================================
We're happy to announce the 7th version of scikit-image!
We're happy to announce the 7th version of scikits-image!
scikit-image is an image processing toolbox for SciPy that includes algorithms
Scikits-image is an image processing toolbox for SciPy that includes algorithms
for segmentation, geometric transformations, color space manipulation,
analysis, filtering, morphology, feature detection, and more.
@@ -15,7 +15,7 @@ For more information, examples, and documentation, please visit our website
New Features
------------
It's been only 3 months since scikit-image 0.6 was released, but in that short
It's been only 3 months since scikits-image 0.6 was released, but in that short
time, we've managed to add plenty of new features and enhancements, including
- Geometric image transforms
+1 -1
View File
@@ -1,5 +1,5 @@
function insert_version_links() {
var labels = ['dev', '0.7', '0.6', '0.5', '0.4', '0.3'];
var labels = ['dev', '0.7.0', '0.6', '0.5', '0.4', '0.3'];
for (i = 0; i < labels.length; i++){
open_list = '<li>'
+2 -2
View File
@@ -1,5 +1,5 @@
<li><a href="{{ pathto(master_doc) }}">Home</a></li>
<li><a href="/">Home</a></li>
<li><a href="/download.html">Download</a></li>
<li><a href="/docs/dev/auto_examples">Gallery</a></li>
<li><a href="/docs">Documentation</a></li>
<li><a href="/docs/dev">Documentation</a></li>
<li><a href="https://github.com/scikit-image/scikit-image">Source</a></li>
+2 -2
View File
@@ -176,7 +176,7 @@ html_sidebars = {
#html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = 'scikitsimagedoc'
htmlhelp_basename = 'scikitimagedoc'
# -- Options for LaTeX output --------------------------------------------------
@@ -190,7 +190,7 @@ htmlhelp_basename = 'scikitsimagedoc'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('contents', 'scikitsimage.tex', u'The Image Scikit Documentation',
('contents', 'scikitimage.tex', u'The Image Scikit Documentation',
u'SciPy Developers', 'manual'),
]
+1 -3
View File
@@ -1,8 +1,6 @@
Pre-built installation
----------------------
.. !! Also update scikit-image-web !!
`Windows binaries
<http://www.lfd.uci.edu/~gohlke/pythonlibs/#scikits.image>`__
are kindly provided by Christoph Gohlke.
@@ -23,7 +21,7 @@ or
::
pip -U scikit-image
pip install -U scikit-image
Installation from source
------------------------
@@ -14,10 +14,9 @@ pre {
font-size: 11px;
}
h1, h2, h3, h4 {
clear: left;
h1, h2, h3, h4, h5, h6 {
clear: left;
}
h1 {
font-size: 30px;
line-height: 36px;
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

-5
View File
@@ -71,11 +71,6 @@ issued::
float64 to uint8
array([ 0, 128, 255], dtype=uint8)
Wherever possible, functions should try to handle input without explicit
conversion. For example, there is no need to force values to a specific type
for doing a convolution; a plotting function, on the other hand, needs to know
the range of the input.
Output types
============
+4 -4
View File
@@ -6,17 +6,17 @@ Image processing algorithms for SciPy, including IO, morphology, filtering,
warping, color manipulation, object detection, etc.
Please refer to the online documentation at
http://scikits-image.org/
http://scikit-image.org/
"""
DISTNAME = 'scikits-image'
DISTNAME = 'scikit-image'
DESCRIPTION = 'Image processing routines for SciPy'
LONG_DESCRIPTION = descr
MAINTAINER = 'Stefan van der Walt'
MAINTAINER_EMAIL = 'stefan@sun.ac.za'
URL = 'http://scikits-image.org'
URL = 'http://scikit-image.org'
LICENSE = 'Modified BSD'
DOWNLOAD_URL = 'http://github.com/scikits-image/scikits-image'
DOWNLOAD_URL = 'http://github.com/scikit-image/scikit-image'
VERSION = '0.8dev'
PYTHON_VERSION = (2, 5)
DEPENDENCIES = {
+2 -2
View File
@@ -1,6 +1,6 @@
"""Image Processing SciKit (Toolbox for SciPy)
``scikits-image`` (a.k.a. ``skimage``) is a collection of algorithms for image
``scikit-image`` (a.k.a. ``skimage``) is a collection of algorithms for image
processing and computer vision.
The main package of ``skimage`` only provides a few utilities for converting
@@ -65,7 +65,7 @@ except ImportError:
def _setup_test(verbose=False):
import functools
args = ['', '--exe', '-w', pkg_dir]
args = ['', pkg_dir, '--exe']
if verbose:
args.extend(['-v', '-s'])
+5 -2
View File
@@ -18,7 +18,10 @@ cdef double bicubic_interpolation(double* image, int rows, int cols,
double r, double c, char mode,
double cval)
cdef double get_pixel(double* image, int rows, int cols, int r, int c,
char mode, double cval)
cdef double get_pixel2d(double* image, int rows, int cols, int r, int c,
char mode, double cval)
cdef double get_pixel3d(double* image, int rows, int cols, int dims, int r,
int c, int d, char mode, double cval)
cdef int coord_map(int dim, int coord, char mode)
+44 -10
View File
@@ -35,8 +35,8 @@ cdef inline double nearest_neighbour_interpolation(double* image, int rows,
"""
return get_pixel(image, rows, cols, <int>round(r), <int>round(c),
mode, cval)
return get_pixel2d(image, rows, cols, <int>round(r), <int>round(c),
mode, cval)
cdef inline double bilinear_interpolation(double* image, int rows, int cols,
@@ -72,10 +72,10 @@ cdef inline double bilinear_interpolation(double* image, int rows, int cols,
maxc = <int>ceil(c)
dr = r - minr
dc = c - minc
top = (1 - dc) * get_pixel(image, rows, cols, minr, minc, mode, cval) \
+ dc * get_pixel(image, rows, cols, minr, maxc, mode, cval)
bottom = (1 - dc) * get_pixel(image, rows, cols, maxr, minc, mode, cval) \
+ dc * get_pixel(image, rows, cols, maxr, maxc, mode, cval)
top = (1 - dc) * get_pixel2d(image, rows, cols, minr, minc, mode, cval) \
+ dc * get_pixel2d(image, rows, cols, minr, maxc, mode, cval)
bottom = (1 - dc) * get_pixel2d(image, rows, cols, maxr, minc, mode, cval) \
+ dc * get_pixel2d(image, rows, cols, maxr, maxc, mode, cval)
return (1 - dr) * top + dr * bottom
@@ -144,7 +144,7 @@ cdef inline double biquadratic_interpolation(double* image, int rows, int cols,
# row-wise cubic interpolation
for pr in range(r0, r0 + 3):
for pc in range(c0, c0 + 3):
fc[pc - c0] = get_pixel(image, rows, cols, pr, pc, mode, cval)
fc[pc - c0] = get_pixel2d(image, rows, cols, pr, pc, mode, cval)
fr[pr - r0] = quadratic_interpolation(xc, fc)
# cubic interpolation for interpolated values of each row
@@ -216,15 +216,15 @@ cdef inline double bicubic_interpolation(double* image, int rows, int cols,
# row-wise cubic interpolation
for pr in range(r0, r0 + 4):
for pc in range(c0, c0 + 4):
fc[pc - c0] = get_pixel(image, rows, cols, pr, pc, mode, cval)
fc[pc - c0] = get_pixel2d(image, rows, cols, pr, pc, mode, cval)
fr[pr - r0] = cubic_interpolation(xc, fc)
# cubic interpolation for interpolated values of each row
return cubic_interpolation(xr, fr)
cdef inline double get_pixel(double* image, int rows, int cols, int r, int c,
char mode, double cval):
cdef inline double get_pixel2d(double* image, int rows, int cols, int r, int c,
char mode, double cval):
"""Get a pixel from the image, taking wrapping mode into consideration.
Parameters
@@ -255,6 +255,40 @@ cdef inline double get_pixel(double* image, int rows, int cols, int r, int c,
return image[coord_map(rows, r, mode) * cols + coord_map(cols, c, mode)]
cdef inline double get_pixel3d(double* image, int rows, int cols, int dims, int r,
int c, int d, char mode, double cval):
"""Get a pixel from the image, taking wrapping mode into consideration.
Parameters
----------
image : double array
Input image.
rows, cols, dims : int
Shape of image.
r, c, d : int
Position at which to get the pixel.
mode : {'C', 'W', 'R', 'N'}
Wrapping mode. Constant, Wrap, Reflect or Nearest.
cval : double
Constant value to use for constant mode.
Returns
-------
value : double
Pixel value at given position.
"""
if mode == 'C':
if (r < 0) or (r > rows - 1) or (c < 0) or (c > cols - 1):
return cval
else:
return image[r * cols * dims + c * dims + d]
else:
return image[coord_map(rows, r, mode) * cols * dims
+ coord_map(cols, c, mode) * dims
+ d]
cdef inline int coord_map(int dim, int coord, char mode):
"""
Wrap a coordinate, according to a given mode.
+4 -4
View File
@@ -28,11 +28,11 @@ def configuration(parent_package='', top_path=None):
if __name__ == '__main__':
from numpy.distutils.core import setup
setup(maintainer='Scikits-image Developers',
author='Scikits-image Developers',
maintainer_email='scikits-image@googlegroups.com',
setup(maintainer='scikit-image Developers',
author='scikit-image Developers',
maintainer_email='scikit-image@googlegroups.com',
description='Transforms',
url='https://github.com/scikits-image/scikits-image',
url='https://github.com/scikit-image/scikit-image',
license='SciPy License (BSD Style)',
**(configuration(top_path='').todict())
)
+43
View File
@@ -0,0 +1,43 @@
import warnings
import functools
__all__ = ['deprecated']
class deprecated(object):
"""Decorator to mark deprecated functions with warning.
Adapted from <http://wiki.python.org/moin/PythonDecoratorLibrary>.
Parameters
----------
alt_func : str
If given, tell user what function to use instead.
behavior : {'warn', 'raise'}
Behavior during call to deprecated function: 'warn' = warn user that
function is deprecated; 'raise' = raise error.
"""
def __init__(self, alt_func=None, behavior='warn'):
self.alt_func = alt_func
self.behavior = behavior
def __call__(self, func):
msg = "Call to deprecated function `%s`." % func.__name__
if self.alt_func is not None:
msg = msg + " Use `%s` instead." % self.alt_func
@functools.wraps(func)
def wrapped(*args, **kwargs):
if self.behavior == 'warn':
warnings.warn_explicit(msg,
category=DeprecationWarning,
filename=func.func_code.co_filename,
lineno=func.func_code.co_firstlineno + 1)
elif self.behavior == 'raise':
raise DeprecationWarning(msg)
return func(*args, **kwargs)
return wrapped
+40 -14
View File
@@ -45,7 +45,7 @@ from __future__ import division
__all__ = ['convert_colorspace', 'rgb2hsv', 'hsv2rgb', 'rgb2xyz', 'xyz2rgb',
'rgb2rgbcie', 'rgbcie2rgb', 'rgb2grey', 'rgb2gray', 'gray2rgb',
'xyz2lab', 'lab2xyz', 'lab2rgb', 'rgb2lab'
'xyz2lab', 'lab2xyz', 'lab2rgb', 'rgb2lab', 'is_rgb', 'is_gray'
]
__docformat__ = "restructuredtext en"
@@ -55,6 +55,31 @@ from scipy import linalg
from ..util import dtype
def is_rgb(image):
"""Test whether the image is RGB or RGBA.
Parameters
----------
image : ndarray
Input image.
"""
return (image.ndim == 3 and image.shape[2] in (3, 4))
def is_gray(image):
"""Test whether the image is gray (i.e. has only one color band).
Parameters
----------
image : ndarray
Input image.
"""
return image.ndim == 2
def convert_colorspace(arr, fromspace, tospace):
"""Convert an image array to a new color space.
@@ -281,7 +306,7 @@ rgbcie_from_rgb = np.dot(rgbcie_from_xyz, xyz_from_rgb)
rgb_from_rgbcie = np.dot(rgb_from_xyz, xyz_from_rgbcie)
grey_from_rgb = np.array([[0.2125, 0.7154, 0.0721],
gray_from_rgb = np.array([[0.2125, 0.7154, 0.0721],
[0, 0, 0],
[0, 0, 0]])
@@ -458,7 +483,7 @@ def rgbcie2rgb(rgbcie):
return _convert(rgb_from_rgbcie, rgbcie)
def rgb2grey(rgb):
def rgb2gray(rgb):
"""Compute luminance of an RGB image.
Parameters
@@ -475,7 +500,7 @@ def rgb2grey(rgb):
Raises
------
ValueError
If `rgb2grey` is not a 3-D array of shape (.., .., 3) or
If `rgb2gray` is not a 3-D array of shape (.., .., 3) or
(.., .., 4).
References
@@ -493,21 +518,21 @@ def rgb2grey(rgb):
Examples
--------
>>> from skimage.color import rgb2grey
>>> from skimage.color import rgb2gray
>>> from skimage import data
>>> lena = data.lena()
>>> lena_grey = rgb2grey(lena)
>>> lena_gray = rgb2gray(lena)
"""
if rgb.ndim == 2:
return rgb
return _convert(grey_from_rgb, rgb[:, :, :3])[..., 0]
return _convert(gray_from_rgb, rgb[:, :, :3])[..., 0]
rgb2gray = rgb2grey
rgb2grey = rgb2gray
def gray2rgb(image):
"""Create an RGB representation of a grey-level image.
"""Create an RGB representation of a gray-level image.
Parameters
----------
@@ -525,11 +550,12 @@ def gray2rgb(image):
If the input is not 2-dimensional.
"""
if image.ndim != 2:
raise ValueError('Gray-level image should be two-dimensional.')
M, N = image.shape
return np.dstack((image, image, image))
if is_rgb(image):
return image
elif is_gray(image):
return np.dstack((image, image, image))
else:
raise ValueError("Input image expected to be RGB, RGBA or gray.")
def xyz2lab(xyz):
+21 -2
View File
@@ -25,10 +25,11 @@ from skimage.color import (
convert_colorspace,
rgb2grey, gray2rgb,
xyz2lab, lab2xyz,
lab2rgb, rgb2lab
lab2rgb, rgb2lab,
is_rgb, is_gray
)
from skimage import data_dir
from skimage import data_dir, data
import colorsys
@@ -196,5 +197,23 @@ def test_gray2rgb():
assert_equal(z[..., 0], x)
assert_equal(z[0, 1, :], [128, 128, 128])
def test_gray2rgb_rgb():
x = np.random.random((5, 5, 4))
y = gray2rgb(x)
assert_equal(x, y)
def test_is_rgb():
color = data.lena()
gray = data.camera()
assert is_rgb(color)
assert not is_gray(color)
assert is_gray(gray)
assert not is_gray(color)
if __name__ == "__main__":
run_module_suite()
+13
View File
@@ -114,3 +114,16 @@ def page():
"""
return load("page.png")
def clock():
"""Motion blurred clock.
This photograph of a wall clock was taken while moving the camera in an
aproximately horizontal direction. It may be used to illustrate
inverse filters and deconvolution.
Released into the public domain by the photographer (Stefan van der Walt).
"""
return load("clock_motion.png")
Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

+22 -1
View File
@@ -15,9 +15,30 @@ def test_camera():
def test_checkerboard():
""" Test that checkerboard image can be loaded. """
""" Test that "checkerboard" image can be loaded. """
data.checkerboard()
def test_text():
""" Test that "text" image can be loaded. """
data.text()
def test_moon():
""" Test that "moon" image can be loaded. """
data.moon()
def test_page():
""" Test that "page" image can be loaded. """
data.page()
def test_page():
""" Test that "clock" image can be loaded. """
data.clock()
if __name__ == "__main__":
from numpy.testing import run_module_suite
run_module_suite()
+4 -4
View File
@@ -21,11 +21,11 @@ def configuration(parent_package='', top_path=None):
if __name__ == '__main__':
from numpy.distutils.core import setup
setup(maintainer='scikits-image developers',
author='scikits-image developers',
maintainer_email='scikits-image@googlegroups.com',
setup(maintainer='scikit-image developers',
author='scikit-image developers',
maintainer_email='scikit-image@googlegroups.com',
description='Drawing',
url='https://github.com/scikits-image/scikits-image',
url='https://github.com/scikit-image/scikit-image',
license='SciPy License (BSD Style)',
**(configuration(top_path='').todict())
)
+4 -4
View File
@@ -24,11 +24,11 @@ def configuration(parent_package='', top_path=None):
if __name__ == '__main__':
from numpy.distutils.core import setup
setup(maintainer='scikits-image Developers',
author='scikits-image Developers',
maintainer_email='scikits-image@googlegroups.com',
setup(maintainer='scikit-image Developers',
author='scikit-image Developers',
maintainer_email='scikit-image@googlegroups.com',
description='Features',
url='https://github.com/scikits-image/scikits-image',
url='https://github.com/scikit-image/scikit-image',
license='SciPy License (BSD Style)',
**(configuration(top_path='').todict())
)
+4 -2
View File
@@ -1,7 +1,9 @@
from .lpi_filter import *
from .ctmf import median_filter
from ._canny import canny
from .edges import sobel, hsobel, vsobel, hprewitt, vprewitt, prewitt
from ._tv_denoise import tv_denoise
from .edges import (sobel, hsobel, vsobel, scharr, hscharr, vscharr, prewitt,
hprewitt, vprewitt)
from .denoise import tv_denoise, denoise_tv
from ._denoise import denoise_bilateral
from ._rank_order import rank_order
from .thresholding import threshold_otsu, threshold_adaptive
+177
View File
@@ -0,0 +1,177 @@
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
cimport numpy as cnp
import numpy as np
from libc.math cimport exp, fabs, sqrt
from libc.stdlib cimport malloc, free
from skimage._shared.interpolation cimport get_pixel3d
from skimage.util import img_as_float
cdef inline double _gaussian_weight(double sigma, double value):
return exp(-0.5 * (value / sigma)**2)
cdef double* _compute_color_lut(int bins, double sigma, double max_value):
cdef:
double* color_lut = <double*>malloc(bins * sizeof(double))
Py_ssize_t b
for b in range(bins):
color_lut[b] = _gaussian_weight(sigma, b * max_value / bins)
return color_lut
cdef double* _compute_range_lut(int win_size, double sigma):
cdef:
double* range_lut = <double*>malloc(win_size**2 * sizeof(double))
Py_ssize_t kr, kc
Py_ssize_t window_ext = (win_size - 1) / 2
double dist
for kr in range(win_size):
for kc in range(win_size):
dist = sqrt((kr - window_ext)**2 + (kc - window_ext)**2)
range_lut[kr * win_size + kc] = _gaussian_weight(sigma, dist)
return range_lut
def denoise_bilateral(image, int win_size=5, sigma_range=None,
double sigma_spatial=1, int bins=10000, mode='constant',
double cval=0):
"""Denoise image using bilateral filter.
This is an edge-preserving and noise reducing denoising filter. It averages
pixels based on their spatial closeness and radiometric similarity.
Spatial closeness is measured by the gaussian function of the euclidian
distance between two pixels and a certain standard deviation
(`sigma_spatial`).
Radiometric similarity is measured by the gaussian function of the euclidian
distance between two color values and a certain standard deviation
(`sigma_range`).
Parameters
----------
image : ndarray
Input image.
win_size : int
Window size for filtering.
sigma_range : float
Standard deviation for grayvalue/color distance (radiometric
similarity). A larger value results in averaging of pixels with larger
radiometric differences. Note, that the image will be converted using
the `img_as_float` function and thus the standard deviation is in
respect to the range `[0, 1]`.
sigma_spatial : float
Standard deviation for range distance. A larger value results in
averaging of pixels with larger spatial differences.
bins : int
Number of discrete values for gaussian weights of color filtering.
A larger value results in improved accuracy.
mode : string
How to handle values outside the image borders. See
`scipy.ndimage.map_coordinates` for detail.
cval : string
Used in conjunction with mode 'constant', the value outside
the image boundaries.
Returns
-------
denoised : ndarray
Denoised image.
References
----------
.. [1] http://users.soe.ucsc.edu/~manduchi/Papers/ICCV98.pdf
"""
image = np.atleast_3d(img_as_float(image))
cdef:
Py_ssize_t rows = image.shape[0]
Py_ssize_t cols = image.shape[1]
Py_ssize_t dims = image.shape[2]
Py_ssize_t window_ext = (win_size - 1) / 2
double max_value = image.max()
cnp.ndarray[dtype=cnp.double_t, ndim=3, mode='c'] cimage = \
np.ascontiguousarray(image)
cnp.ndarray[dtype=cnp.double_t, ndim=3, mode='c'] out = \
np.zeros((rows, cols, dims), dtype=np.double)
double* image_data = <double*>cimage.data
double* out_data = <double*>out.data
double* color_lut = _compute_color_lut(bins, sigma_range, max_value)
double* range_lut = _compute_range_lut(win_size, sigma_spatial)
Py_ssize_t r, c, d, wr, wc, kr, kc, rr, cc, pixel_addr
double value, weight, dist, total_weight, csigma_range, color_weight, \
range_weight
double dist_scale = bins / dims / max_value
double* values = <double*>malloc(dims * sizeof(double))
double* centres = <double*>malloc(dims * sizeof(double))
double* total_values = <double*>malloc(dims * sizeof(double))
if sigma_range is None:
csigma_range = image.std()
else:
csigma_range = sigma_range
if mode not in ('constant', 'wrap', 'reflect', 'nearest'):
raise ValueError("Invalid mode specified. Please use "
"`constant`, `nearest`, `wrap` or `reflect`.")
cdef char cmode = ord(mode[0].upper())
for r in range(rows):
for c in range(cols):
pixel_addr = r * cols * dims + c * dims
total_weight = 0
for d in range(dims):
total_values[d] = 0
centres[d] = image_data[pixel_addr + d]
for wr in range(-window_ext, window_ext + 1):
rr = wr + r
kr = wr + window_ext
for wc in range(-window_ext, window_ext + 1):
cc = wc + c
kc = wc + window_ext
# save pixel values for all dims and compute euclidian
# distance between centre stack and current position
dist = 0
for d in range(dims):
value = get_pixel3d(image_data, rows, cols, dims,
rr, cc, d, cmode, cval)
values[d] = value
dist += (centres[d] - value)**2
dist = sqrt(dist)
range_weight = range_lut[kr * win_size + kc]
color_weight = color_lut[<int>(dist * dist_scale)]
weight = range_weight * color_weight
for d in range(dims):
total_values[d] += values[d] * weight
total_weight += weight
for d in range(dims):
out_data[pixel_addr + d] = total_values[d] / total_weight
free(color_lut)
free(range_lut)
free(values)
free(centres)
free(total_values)
return out
@@ -1,37 +1,35 @@
import numpy as np
from skimage import img_as_float
from skimage._shared.utils import deprecated
def _tv_denoise_3d(im, weight=100, eps=2.e-4, n_iter_max=200):
"""
Perform total-variation denoising on 3-D arrays
def _denoise_tv_3d(im, weight=100, eps=2.e-4, n_iter_max=200):
"""Perform total-variation denoising on 3-D arrays.
Parameters
----------
im: ndarray
3-D input data to be denoised
3-D input data to be denoised.
weight: float, optional
denoising weight. The greater ``weight``, the more denoising (at
the expense of fidelity to ``input``)
Denoising weight. The greater ``weight``, the more denoising (at
the expense of fidelity to ``input``).
eps: float, optional
relative difference of the value of the cost function that determines
Relative difference of the value of the cost function that determines
the stop criterion. The algorithm stops when:
(E_(n-1) - E_n) < eps * E_0
n_iter_max: int, optional
maximal number of iterations used for the optimization.
Maximal number of iterations used for the optimization.
Returns
-------
out: ndarray
denoised array of floats
Denoised array of floats.
Notes
-----
Rudin, Osher and Fatemi algorithm
Rudin, Osher and Fatemi algorithm.
Examples
---------
@@ -40,7 +38,7 @@ def _tv_denoise_3d(im, weight=100, eps=2.e-4, n_iter_max=200):
>>> 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 = tv_denoise_3d(mask, weight=100)
>>> res = denoise_tv_3d(mask, weight=100)
"""
px = np.zeros_like(im)
py = np.zeros_like(im)
@@ -85,44 +83,40 @@ def _tv_denoise_3d(im, weight=100, eps=2.e-4, n_iter_max=200):
return out
def _tv_denoise_2d(im, weight=50, eps=2.e-4, n_iter_max=200):
"""
Perform total-variation denoising
def _denoise_tv_2d(im, weight=50, eps=2.e-4, n_iter_max=200):
"""Perform total-variation denoising.
Parameters
----------
im: ndarray
input data to be denoised
Input data to be denoised.
weight: float, optional
denoising weight. The greater ``weight``, the more denoising (at
Denoising weight. The greater ``weight``, the more denoising (at
the expense of fidelity to ``input``)
eps: float, optional
relative difference of the value of the cost function that determines
Relative difference of the value of the cost function that determines
the stop criterion. The algorithm stops when:
(E_(n-1) - E_n) < eps * E_0
n_iter_max: int, optional
maximal number of iterations used for the optimization.
Maximal number of iterations used for the optimization.
Returns
-------
out: ndarray
denoised array of floats
Denoised array of floats.
Notes
-----
The principle of total variation denoising is explained in
http://en.wikipedia.org/wiki/Total_variation_denoising
http://en.wikipedia.org/wiki/Total_variation_denoising.
This code is an implementation of the algorithm of Rudin, Fatemi and Osher
that was proposed by Chambolle in [1]_.
References
----------
.. [1] A. Chambolle, An algorithm for total variation minimization and
applications, Journal of Mathematical Imaging and Vision,
Springer, 2004, 20, 89-97.
@@ -134,7 +128,7 @@ def _tv_denoise_2d(im, weight=50, eps=2.e-4, n_iter_max=200):
>>> import scipy
>>> lena = scipy.lena().astype(np.float)
>>> lena += 0.5 * lena.std()*np.random.randn(*lena.shape)
>>> denoised_lena = tv_denoise(lena, weight=60.0)
>>> denoised_lena = denoise_tv(lena, weight=60.0)
"""
px = np.zeros_like(im)
py = np.zeros_like(im)
@@ -172,34 +166,31 @@ def _tv_denoise_2d(im, weight=50, eps=2.e-4, n_iter_max=200):
return out
def tv_denoise(im, weight=50, eps=2.e-4, n_iter_max=200):
"""
Perform total-variation denoising on 2-d and 3-d images
def denoise_tv(im, weight=50, eps=2.e-4, n_iter_max=200):
"""Perform total-variation denoising on 2-d and 3-d images.
Parameters
----------
im: ndarray (2d or 3d) of ints, uints or floats
input data to be denoised. `im` can be of any numeric type,
Input data to be denoised. `im` can be of any numeric type,
but it is cast into an ndarray of floats for the computation
of the denoised image.
weight: float, optional
denoising weight. The greater ``weight``, the more denoising (at
the expense of fidelity to ``input``)
Denoising weight. The greater ``weight``, the more denoising (at
the expense of fidelity to ``input``).
eps: float, optional
relative difference of the value of the cost function that
Relative difference of the value of the cost function that
determines the stop criterion. The algorithm stops when:
(E_(n-1) - E_n) < eps * E_0
n_iter_max: int, optional
maximal number of iterations used for the optimization.
Maximal number of iterations used for the optimization.
Returns
-------
out: ndarray
denoised array of floats
Denoised array of floats.
Notes
-----
@@ -217,7 +208,6 @@ def tv_denoise(im, weight=50, eps=2.e-4, n_iter_max=200):
References
----------
.. [1] A. Chambolle, An algorithm for total variation minimization and
applications, Journal of Mathematical Imaging and Vision,
Springer, 2004, 20, 89-97.
@@ -230,23 +220,26 @@ def tv_denoise(im, weight=50, eps=2.e-4, n_iter_max=200):
>>> import scipy
>>> lena = scipy.lena().astype(np.float)
>>> lena += 0.5 * lena.std()*np.random.randn(*lena.shape)
>>> denoised_lena = tv_denoise(lena, weight=60)
>>> denoised_lena = denoise_tv(lena, weight=60)
>>> # 3D example on synthetic data
>>> 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 = tv_denoise_3d(mask, weight=100)
>>> res = denoise_tv_3d(mask, weight=100)
"""
im_type = im.dtype
if not im_type.kind == 'f':
im = img_as_float(im)
if im.ndim == 2:
out = _tv_denoise_2d(im, weight, eps, n_iter_max)
out = _denoise_tv_2d(im, weight, eps, n_iter_max)
elif im.ndim == 3:
out = _tv_denoise_3d(im, weight, eps, n_iter_max)
out = _denoise_tv_3d(im, weight, eps, n_iter_max)
else:
raise ValueError('only 2-d and 3-d images may be denoised with this '
'function')
return out
tv_denoise = deprecated('skimage.filter.denoise_tv')(denoise_tv)
+136 -23
View File
@@ -1,6 +1,7 @@
"""edges.py - Sobel edge filter
"""edges.py - Edge filters
Originally part of CellProfiler, code licensed under both GPL and BSD licenses.
Sobel and Prewitt filters originally part of CellProfiler, code licensed under
both GPL and BSD licenses.
Website: http://www.cellprofiler.org
Copyright (c) 2003-2009 Massachusetts Institute of Technology
Copyright (c) 2009-2011 Broad Institute
@@ -34,13 +35,13 @@ def _mask_filter_result(result, mask):
def sobel(image, mask=None):
"""Calculate the absolute magnitude Sobel to find edges.
"""Find the edge magnitude using the Sobel transform.
Parameters
----------
image : array_like, dtype=float
image : 2-D array
Image to process.
mask : array_like, dtype=bool, optional
mask : 2-D array, optional
An optional mask to limit the application to a certain area.
Note that pixels surrounding masked regions are also masked to
prevent masked regions from affecting the result.
@@ -48,7 +49,7 @@ def sobel(image, mask=None):
Returns
-------
output : ndarray
The Sobel edge map.
The Sobel edge map.
Notes
-----
@@ -67,9 +68,9 @@ def hsobel(image, mask=None):
Parameters
----------
image : array_like, dtype=float
image : 2-D array
Image to process.
mask : array_like, dtype=bool, optional
mask : 2-D array, optional
An optional mask to limit the application to a certain area.
Note that pixels surrounding masked regions are also masked to
prevent masked regions from affecting the result.
@@ -77,7 +78,7 @@ def hsobel(image, mask=None):
Returns
-------
output : ndarray
The Sobel edge map.
The Sobel edge map.
Notes
-----
@@ -102,9 +103,9 @@ def vsobel(image, mask=None):
Parameters
----------
image : array_like, dtype=float
image : 2-D array
Image to process
mask : array_like, dtype=bool, optional
mask : 2-D array, optional
An optional mask to limit the application to a certain area
Note that pixels surrounding masked regions are also masked to
prevent masked regions from affecting the result.
@@ -112,7 +113,7 @@ def vsobel(image, mask=None):
Returns
-------
output : ndarray
The Sobel edge map.
The Sobel edge map.
Notes
-----
@@ -132,14 +133,14 @@ def vsobel(image, mask=None):
return _mask_filter_result(result, mask)
def prewitt(image, mask=None):
"""Find the edge magnitude using the Prewitt transform.
def scharr(image, mask=None):
"""Find the edge magnitude using the Scharr transform.
Parameters
----------
image : array_like, dtype=float
image : 2-D array
Image to process.
mask : array_like, dtype=bool, optional
mask : 2-D array, optional
An optional mask to limit the application to a certain area.
Note that pixels surrounding masked regions are also masked to
prevent masked regions from affecting the result.
@@ -147,7 +148,119 @@ def prewitt(image, mask=None):
Returns
-------
output : ndarray
The Prewitt edge map.
The Scharr edge map.
Notes
-----
Take the square root of the sum of the squares of the horizontal and
vertical Scharrs to get a magnitude that's somewhat insensitive to
direction.
References
----------
.. [1] D. Kroon, 2009, Short Paper University Twente, Numerical Optimization
of Kernel Based Image Derivatives.
"""
return np.sqrt(hscharr(image, mask)**2 + vscharr(image, mask)**2)
def hscharr(image, mask=None):
"""Find the horizontal edges of an image using the Scharr transform.
Parameters
----------
image : 2-D array
Image to process.
mask : 2-D array, optional
An optional mask to limit the application to a certain area.
Note that pixels surrounding masked regions are also masked to
prevent masked regions from affecting the result.
Returns
-------
output : ndarray
The Scharr edge map.
Notes
-----
We use the following kernel and return the absolute value of the
result at each point::
3 10 3
0 0 0
-3 -10 -3
References
----------
.. [1] D. Kroon, 2009, Short Paper University Twente, Numerical Optimization
of Kernel Based Image Derivatives.
"""
image = img_as_float(image)
result = np.abs(convolve(image,
np.array([[ 3, 10, 3],
[ 0, 0, 0],
[-3, -10, -3]]).astype(float) / 16.0))
return _mask_filter_result(result, mask)
def vscharr(image, mask=None):
"""Find the vertical edges of an image using the Scharr transform.
Parameters
----------
image : 2-D array
Image to process
mask : 2-D array, optional
An optional mask to limit the application to a certain area
Note that pixels surrounding masked regions are also masked to
prevent masked regions from affecting the result.
Returns
-------
output : ndarray
The Scharr edge map.
Notes
-----
We use the following kernel and return the absolute value of the
result at each point::
3 0 -3
10 0 -10
3 0 -3
References
----------
.. [1] D. Kroon, 2009, Short Paper University Twente, Numerical Optimization
of Kernel Based Image Derivatives.
"""
image = img_as_float(image)
result = np.abs(convolve(image,
np.array([[ 3, 0, -3],
[10, 0, -10],
[ 3, 0, -3]]).astype(float) / 16.0))
return _mask_filter_result(result, mask)
def prewitt(image, mask=None):
"""Find the edge magnitude using the Prewitt transform.
Parameters
----------
image : 2-D array
Image to process.
mask : 2-D array, optional
An optional mask to limit the application to a certain area.
Note that pixels surrounding masked regions are also masked to
prevent masked regions from affecting the result.
Returns
-------
output : ndarray
The Prewitt edge map.
Notes
-----
@@ -162,9 +275,9 @@ def hprewitt(image, mask=None):
Parameters
----------
image : array_like, dtype=float
image : 2-D array
Image to process.
mask : array_like, dtype=bool, optional
mask : 2-D array, optional
An optional mask to limit the application to a certain area.
Note that pixels surrounding masked regions are also masked to
prevent masked regions from affecting the result.
@@ -172,7 +285,7 @@ def hprewitt(image, mask=None):
Returns
-------
output : ndarray
The Prewitt edge map.
The Prewitt edge map.
Notes
-----
@@ -197,9 +310,9 @@ def vprewitt(image, mask=None):
Parameters
----------
image : array_like, dtype=float
image : 2-D array
Image to process.
mask : array_like, dtype=bool, optional
mask : 2-D array, optional
An optional mask to limit the application to a certain area.
Note that pixels surrounding masked regions are also masked to
prevent masked regions from affecting the result.
@@ -207,7 +320,7 @@ def vprewitt(image, mask=None):
Returns
-------
output : ndarray
The Prewitt edge map.
The Prewitt edge map.
Notes
-----
+1 -1
View File
@@ -75,7 +75,7 @@ class LPIFilter2D(object):
>>> filter = LPIFilter2D(filt_func)
"""
if impulse_response is None:
if not callable(impulse_response):
raise ValueError("Impulse response must be a callable.")
self.impulse_response = impulse_response
+7 -4
View File
@@ -13,19 +13,22 @@ def configuration(parent_package='', top_path=None):
config.add_data_dir('tests')
cython(['_ctmf.pyx'], working_path=base_path)
cython(['_denoise.pyx'], working_path=base_path)
config.add_extension('_ctmf', sources=['_ctmf.c'],
include_dirs=[get_numpy_include_dirs()])
config.add_extension('_denoise', sources=['_denoise.c'],
include_dirs=[get_numpy_include_dirs(), '../_shared'])
return config
if __name__ == '__main__':
from numpy.distutils.core import setup
setup(maintainer='scikits-image Developers',
author='scikits-image Developers',
maintainer_email='scikits-image@googlegroups.com',
setup(maintainer='scikit-image Developers',
author='scikit-image Developers',
maintainer_email='scikit-image@googlegroups.com',
description='Filters',
url='https://github.com/scikits-image/scikits-image',
url='https://github.com/scikit-image/scikit-image',
license='SciPy License (BSD Style)',
**(configuration(top_path='').todict())
)
+5
View File
@@ -61,3 +61,8 @@ class TestCanny(unittest.TestCase):
def test_image_shape(self):
self.assertRaises(TypeError, F.canny, np.zeros((20, 20, 20)), 4, 0, 0)
def test_mask_none(self):
result1 = F.canny(np.zeros((20, 20)), 4, 0, 0, np.ones((20, 20), bool))
result2 = F.canny(np.zeros((20, 20)), 4, 0, 0)
self.assertTrue(np.all(result1 == result2))
+6
View File
@@ -117,5 +117,11 @@ def test_insufficient_size():
median_filter(img, radius=1)
@raises(TypeError)
def test_wrong_shape():
img = np.empty((10, 10, 3))
median_filter(img)
if __name__ == "__main__":
np.testing.run_module_suite()
+90
View File
@@ -0,0 +1,90 @@
import numpy as np
from numpy.testing import run_module_suite, assert_raises
from skimage import filter, data, color, img_as_float
lena = img_as_float(data.lena()[:256, :256])
lena_gray = color.rgb2gray(lena)
def test_denoise_tv_2d():
# lena image
img = lena_gray
# add noise to lena
img += 0.5 * img.std() * np.random.random(img.shape)
# clip noise so that it does not exceed allowed range for float images.
img = np.clip(img, 0, 1)
# denoise
denoised_lena = filter.denoise_tv(img, weight=60.0)
# which dtype?
assert denoised_lena.dtype in [np.float, np.float32, np.float64]
from scipy import ndimage
grad = ndimage.morphological_gradient(img, size=((3, 3)))
grad_denoised = ndimage.morphological_gradient(
denoised_lena, size=((3, 3)))
# test if the total variation has decreased
assert grad_denoised.dtype == np.float
assert (np.sqrt((grad_denoised**2).sum())
< np.sqrt((grad**2).sum()) / 2)
def test_denoise_tv_float_result_range():
# lena image
img = lena_gray
int_lena = np.multiply(img, 255).astype(np.uint8)
assert np.max(int_lena) > 1
denoised_int_lena = filter.denoise_tv(int_lena, weight=60.0)
# test if the value range of output float data is within [0.0:1.0]
assert denoised_int_lena.dtype == np.float
assert np.max(denoised_int_lena) <= 1.0
assert np.min(denoised_int_lena) >= 0.0
def test_denoise_tv_3d():
"""Apply the TV denoising algorithm on a 3D image representing a sphere."""
x, y, z = np.ogrid[0:40, 0:40, 0:40]
mask = (x - 22)**2 + (y - 20)**2 + (z - 17)**2 < 8**2
mask = 100 * mask.astype(np.float)
mask += 60
mask += 20 * np.random.random(mask.shape)
mask[mask < 0] = 0
mask[mask > 255] = 255
res = filter.denoise_tv(mask.astype(np.uint8), weight=100)
assert res.dtype == np.float
assert res.std() * 255 < mask.std()
# test wrong number of dimensions
assert_raises(ValueError, filter.denoise_tv, np.random.random((8, 8, 8, 8)))
def test_denoise_bilateral_2d():
img = lena_gray
# add some random noise
img += 0.5 * img.std() * np.random.random(img.shape)
img = np.clip(img, 0, 1)
out1 = filter.denoise_bilateral(img, sigma_range=0.1, sigma_spatial=20)
out2 = filter.denoise_bilateral(img, sigma_range=0.2, sigma_spatial=30)
# make sure noise is reduced
assert img.std() > out1.std()
assert out1.std() > out2.std()
def test_denoise_bilateral_3d():
img = lena
# add some random noise
img += 0.5 * img.std() * np.random.random(img.shape)
img = np.clip(img, 0, 1)
out1 = filter.denoise_bilateral(img, sigma_range=0.1, sigma_spatial=20)
out2 = filter.denoise_bilateral(img, sigma_range=0.2, sigma_spatial=30)
# make sure noise is reduced
assert img.std() > out1.std()
assert out1.std() > out2.std()
if __name__ == "__main__":
run_module_suite()
+122 -2
View File
@@ -9,6 +9,7 @@ def test_sobel_zeros():
result = F.sobel(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_sobel_mask():
"""Sobel on a masked array should be zero"""
np.random.seed(0)
@@ -16,6 +17,7 @@ def test_sobel_mask():
np.zeros((10, 10), bool))
assert (np.all(result == 0))
def test_sobel_horizontal():
"""Sobel on an edge should be a horizontal line"""
i, j = np.mgrid[-5:6, -5:6]
@@ -26,6 +28,7 @@ def test_sobel_horizontal():
assert (np.all(result[i == 0] == 1))
assert (np.all(result[np.abs(i) > 1] == 0))
def test_sobel_vertical():
"""Sobel on a vertical edge should be a vertical line"""
i, j = np.mgrid[-5:6, -5:6]
@@ -41,6 +44,7 @@ def test_hsobel_zeros():
result = F.hsobel(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_hsobel_mask():
"""Horizontal Sobel on a masked array should be zero"""
np.random.seed(0)
@@ -48,6 +52,7 @@ def test_hsobel_mask():
np.zeros((10, 10), bool))
assert (np.all(result == 0))
def test_hsobel_horizontal():
"""Horizontal Sobel on an edge should be a horizontal line"""
i, j = np.mgrid[-5:6, -5:6]
@@ -58,6 +63,7 @@ def test_hsobel_horizontal():
assert (np.all(result[i == 0] == 1))
assert (np.all(result[np.abs(i) > 1] == 0))
def test_hsobel_vertical():
"""Horizontal Sobel on a vertical edge should be zero"""
i, j = np.mgrid[-5:6, -5:6]
@@ -71,6 +77,7 @@ def test_vsobel_zeros():
result = F.vsobel(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_vsobel_mask():
"""Vertical Sobel on a masked array should be zero"""
np.random.seed(0)
@@ -78,6 +85,7 @@ def test_vsobel_mask():
np.zeros((10, 10), bool))
assert (np.all(result == 0))
def test_vsobel_vertical():
"""Vertical Sobel on an edge should be a vertical line"""
i, j = np.mgrid[-5:6, -5:6]
@@ -88,6 +96,7 @@ def test_vsobel_vertical():
assert (np.all(result[j == 0] == 1))
assert (np.all(result[np.abs(j) > 1] == 0))
def test_vsobel_horizontal():
"""vertical Sobel on a horizontal edge should be zero"""
i, j = np.mgrid[-5:6, -5:6]
@@ -97,11 +106,114 @@ def test_vsobel_horizontal():
assert (np.all(np.abs(result) < eps))
def test_scharr_zeros():
"""Scharr on an array of all zeros"""
result = F.scharr(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_scharr_mask():
"""Scharr on a masked array should be zero"""
np.random.seed(0)
result = F.scharr(np.random.uniform(size=(10, 10)),
np.zeros((10, 10), bool))
assert (np.all(result == 0))
def test_scharr_horizontal():
"""Scharr on an edge should be a horizontal line"""
i, j = np.mgrid[-5:6, -5:6]
image = (i >= 0).astype(float)
result = F.scharr(image)
# Fudge the eroded points
i[np.abs(j) == 5] = 10000
assert (np.all(result[i == 0] == 1))
assert (np.all(result[np.abs(i) > 1] == 0))
def test_scharr_vertical():
"""Scharr on a vertical edge should be a vertical line"""
i, j = np.mgrid[-5:6, -5:6]
image = (j >= 0).astype(float)
result = F.scharr(image)
j[np.abs(i) == 5] = 10000
assert (np.all(result[j == 0] == 1))
assert (np.all(result[np.abs(j) > 1] == 0))
def test_hscharr_zeros():
"""Horizontal Scharr on an array of all zeros"""
result = F.hscharr(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_hscharr_mask():
"""Horizontal Scharr on a masked array should be zero"""
np.random.seed(0)
result = F.hscharr(np.random.uniform(size=(10, 10)),
np.zeros((10, 10), bool))
assert (np.all(result == 0))
def test_hscharr_horizontal():
"""Horizontal Scharr on an edge should be a horizontal line"""
i, j = np.mgrid[-5:6, -5:6]
image = (i >= 0).astype(float)
result = F.hscharr(image)
# Fudge the eroded points
i[np.abs(j) == 5] = 10000
assert (np.all(result[i == 0] == 1))
assert (np.all(result[np.abs(i) > 1] == 0))
def test_hscharr_vertical():
"""Horizontal Scharr on a vertical edge should be zero"""
i, j = np.mgrid[-5:6, -5:6]
image = (j >= 0).astype(float)
result = F.hscharr(image)
assert (np.all(result == 0))
def test_vscharr_zeros():
"""Vertical Scharr on an array of all zeros"""
result = F.vscharr(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_vscharr_mask():
"""Vertical Scharr on a masked array should be zero"""
np.random.seed(0)
result = F.vscharr(np.random.uniform(size=(10, 10)),
np.zeros((10, 10), bool))
assert (np.all(result == 0))
def test_vscharr_vertical():
"""Vertical Scharr on an edge should be a vertical line"""
i, j = np.mgrid[-5:6, -5:6]
image = (j >= 0).astype(float)
result = F.vscharr(image)
# Fudge the eroded points
j[np.abs(i) == 5] = 10000
assert (np.all(result[j == 0] == 1))
assert (np.all(result[np.abs(j) > 1] == 0))
def test_vscharr_horizontal():
"""vertical Scharr on a horizontal edge should be zero"""
i, j = np.mgrid[-5:6, -5:6]
image = (i >= 0).astype(float)
result = F.vscharr(image)
eps = .000001
assert (np.all(np.abs(result) < eps))
def test_prewitt_zeros():
"""Prewitt on an array of all zeros"""
result = F.prewitt(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_prewitt_mask():
"""Prewitt on a masked array should be zero"""
np.random.seed(0)
@@ -110,6 +222,7 @@ def test_prewitt_mask():
eps = .000001
assert (np.all(np.abs(result) < eps))
def test_prewitt_horizontal():
"""Prewitt on an edge should be a horizontal line"""
i, j = np.mgrid[-5:6, -5:6]
@@ -121,6 +234,7 @@ def test_prewitt_horizontal():
assert (np.all(result[i == 0] == 1))
assert (np.all(np.abs(result[np.abs(i) > 1]) < eps))
def test_prewitt_vertical():
"""Prewitt on a vertical edge should be a vertical line"""
i, j = np.mgrid[-5:6, -5:6]
@@ -137,6 +251,7 @@ def test_hprewitt_zeros():
result = F.hprewitt(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_hprewitt_mask():
"""Horizontal prewitt on a masked array should be zero"""
np.random.seed(0)
@@ -145,6 +260,7 @@ def test_hprewitt_mask():
eps = .000001
assert (np.all(np.abs(result) < eps))
def test_hprewitt_horizontal():
"""Horizontal prewitt on an edge should be a horizontal line"""
i, j = np.mgrid[-5:6, -5:6]
@@ -156,6 +272,7 @@ def test_hprewitt_horizontal():
assert (np.all(result[i == 0] == 1))
assert (np.all(np.abs(result[np.abs(i) > 1]) < eps))
def test_hprewitt_vertical():
"""Horizontal prewitt on a vertical edge should be zero"""
i, j = np.mgrid[-5:6, -5:6]
@@ -170,6 +287,7 @@ def test_vprewitt_zeros():
result = F.vprewitt(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_vprewitt_mask():
"""Vertical prewitt on a masked array should be zero"""
np.random.seed(0)
@@ -177,6 +295,7 @@ def test_vprewitt_mask():
np.zeros((10, 10), bool))
assert (np.all(result == 0))
def test_vprewitt_vertical():
"""Vertical prewitt on an edge should be a vertical line"""
i, j = np.mgrid[-5:6, -5:6]
@@ -188,6 +307,7 @@ def test_vprewitt_vertical():
eps = .000001
assert (np.all(np.abs(result[np.abs(j) > 1]) < eps))
def test_vprewitt_horizontal():
"""Vertical prewitt on a horizontal edge should be zero"""
i, j = np.mgrid[-5:6, -5:6]
@@ -209,7 +329,7 @@ def test_horizontal_mask_line():
expected[1:-1, 1:-1] = 0.2 # constant gradient for most of image,
expected[4:7, 1:-1] = 0 # but line and neighbors masked
for grad_func in (F.hprewitt, F.hsobel):
for grad_func in (F.hprewitt, F.hsobel, F.hscharr):
result = grad_func(vgrad, mask)
yield assert_close, result, expected
@@ -226,7 +346,7 @@ def test_vertical_mask_line():
expected[1:-1, 1:-1] = 0.2 # constant gradient for most of image,
expected[1:-1, 4:7] = 0 # but line and neighbors masked
for grad_func in (F.vprewitt, F.vsobel):
for grad_func in (F.vprewitt, F.vsobel, F.vscharr):
result = grad_func(hgrad, mask)
yield assert_close, result, expected
+6 -1
View File
@@ -8,7 +8,8 @@ from skimage.io import *
from skimage.filter import *
class TestLPIFilter2D():
class TestLPIFilter2D(object):
img = imread(os.path.join(data_dir, 'camera.png'),
flatten=True)[:50, :50]
@@ -55,5 +56,9 @@ class TestLPIFilter2D():
g1 = wiener(F[::-1, ::-1], self.filt_func)
assert ((g - g1[::-1, ::-1]).sum() < 1)
def test_non_callable(self):
assert_raises(ValueError, LPIFilter2D, None)
if __name__ == "__main__":
run_module_suite()
-69
View File
@@ -1,69 +0,0 @@
import numpy as np
from numpy.testing import run_module_suite
from skimage import filter, data, color
class TestTvDenoise():
def test_tv_denoise_2d(self):
"""
Apply the TV denoising algorithm on the lena image provided
by scipy
"""
# lena image
lena = color.rgb2gray(data.lena())[:256, :256]
# add noise to lena
lena += 0.5 * lena.std() * np.random.randn(*lena.shape)
# clip noise so that it does not exceed allowed range for float images.
lena = np.clip(lena, 0, 1)
# denoise
denoised_lena = filter.tv_denoise(lena, weight=60.0)
# which dtype?
assert denoised_lena.dtype in [np.float, np.float32, np.float64]
from scipy import ndimage
grad = ndimage.morphological_gradient(lena, size=((3, 3)))
grad_denoised = ndimage.morphological_gradient(
denoised_lena, size=((3, 3)))
# test if the total variation has decreased
assert grad_denoised.dtype == np.float
assert (np.sqrt((grad_denoised**2).sum())
< np.sqrt((grad**2).sum()) / 2)
def test_tv_denoise_float_result_range(self):
# lena image
lena = color.rgb2gray(data.lena())[:256, :256]
int_lena = np.multiply(lena, 255).astype(np.uint8)
assert np.max(int_lena) > 1
denoised_int_lena = filter.tv_denoise(int_lena, weight=60.0)
# test if the value range of output float data is within [0.0:1.0]
assert denoised_int_lena.dtype == np.float
assert np.max(denoised_int_lena) <= 1.0
assert np.min(denoised_int_lena) >= 0.0
def test_tv_denoise_3d(self):
"""
Apply the TV denoising algorithm on a 3D image representing
a sphere.
"""
x, y, z = np.ogrid[0:40, 0:40, 0:40]
mask = (x - 22)**2 + (y - 20)**2 + (z - 17)**2 < 8**2
mask = 100 * mask.astype(np.float)
mask += 60
mask += 20 * np.random.randn(*mask.shape)
mask[mask < 0] = 0
mask[mask > 255] = 255
res = filter.tv_denoise(mask.astype(np.uint8), weight=100)
assert res.dtype == np.float
assert res.std() * 255 < mask.std()
# test wrong number of dimensions
a = np.random.random((8, 8, 8, 8))
try:
res = filter.tv_denoise(a)
except ValueError:
pass
if __name__ == "__main__":
run_module_suite()
+3 -3
View File
@@ -29,10 +29,10 @@ def configuration(parent_package='', top_path=None):
if __name__ == '__main__':
from numpy.distutils.core import setup
setup(maintainer='scikits-image Developers',
maintainer_email='scikits-image@googlegroups.com',
setup(maintainer='scikit-image Developers',
maintainer_email='scikit-image@googlegroups.com',
description='Graph-based Image-processing Algorithms',
url='https://github.com/scikits-image/scikits-image',
url='https://github.com/scikit-image/scikit-image',
license='Modified BSD',
**(configuration(top_path='').todict())
)
+2 -2
View File
@@ -3,9 +3,9 @@ Skivi is written/maintained/developed by:
S. Chris Colbert - sccolbert@gmail.com
Skivi is free software and is part of the scikits-image project.
Skivi is free software and is part of the scikit-image project.
Skivi is governed by the licenses of the scikits-image project.
Skivi is governed by the licenses of the scikit-image project.
Please report any bugs to the author.
+3 -3
View File
@@ -31,10 +31,10 @@ def configuration(parent_package='', top_path=None):
if __name__ == '__main__':
from numpy.distutils.core import setup
setup(maintainer='scikits-image Developers',
maintainer_email='scikits-image@googlegroups.com',
setup(maintainer='scikit-image Developers',
maintainer_email='scikit-image@googlegroups.com',
description='Image I/O Routines',
url='https://github.com/scikits-image/scikits-image',
url='https://github.com/scikit-image/scikit-image',
license='Modified BSD',
**(configuration(top_path='').todict())
)
+1 -1
View File
@@ -28,7 +28,7 @@ def approximate_polygon(coords, tolerance):
----------
.. [1] http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
"""
if tolerance == 0:
if tolerance <= 0:
return coords
chain = np.zeros(coords.shape[0], 'bool')
+1 -1
View File
@@ -98,7 +98,7 @@ def find_contours(array, level,
"""
array = np.asarray(array, dtype=np.double)
if array.ndim != 2:
raise RuntimeError('Only 2D arrays are supported.')
raise ValueError('Only 2D arrays are supported.')
level = float(level)
if (fully_connected not in _param_options or
positive_orientation not in _param_options):
+3 -3
View File
@@ -24,10 +24,10 @@ def configuration(parent_package='', top_path=None):
if __name__ == '__main__':
from numpy.distutils.core import setup
setup(maintainer='scikits-image Developers',
maintainer_email='scikits-image@googlegroups.com',
setup(maintainer='scikit-image Developers',
maintainer_email='scikit-image@googlegroups.com',
description='Graph-based Image-processing Algorithms',
url='https://github.com/scikits-image/scikits-image',
url='https://github.com/scikit-image/scikit-image',
license='Modified BSD',
**(configuration(top_path='').todict())
)
+35 -27
View File
@@ -21,34 +21,37 @@ r = np.sqrt(x**2 + y**2)
def test_binary():
contours = find_contours(a, 0.5)
ref = [[6. , 1.5],
[5. , 1.5],
[4. , 1.5],
[3. , 1.5],
[2. , 1.5],
[1.5, 2. ],
[1.5, 3. ],
[1.5, 4. ],
[1.5, 5. ],
[1.5, 6. ],
[1. , 6.5],
[0.5, 6. ],
[0.5, 5. ],
[0.5, 4. ],
[0.5, 3. ],
[0.5, 2. ],
[0.5, 1. ],
[1. , 0.5],
[2. , 0.5],
[3. , 0.5],
[4. , 0.5],
[5. , 0.5],
[6. , 0.5],
[6.5, 1. ],
[6. , 1.5]]
contours = find_contours(a, 0.5, positive_orientation='high')
assert len(contours) == 1
assert_array_equal(contours[0],
[[6. , 1.5],
[5. , 1.5],
[4. , 1.5],
[3. , 1.5],
[2. , 1.5],
[1.5, 2. ],
[1.5, 3. ],
[1.5, 4. ],
[1.5, 5. ],
[1.5, 6. ],
[1. , 6.5],
[0.5, 6. ],
[0.5, 5. ],
[0.5, 4. ],
[0.5, 3. ],
[0.5, 2. ],
[0.5, 1. ],
[1. , 0.5],
[2. , 0.5],
[3. , 0.5],
[4. , 0.5],
[5. , 0.5],
[6. , 0.5],
[6.5, 1. ],
[6. , 1.5]])
assert_array_equal(contours[0][::-1], ref)
def test_float():
@@ -70,6 +73,11 @@ def test_memory_order():
assert len(contours) == 1
def test_invalid_input():
assert_raises(ValueError, find_contours, r, 0.5, 'foo', 'bar')
assert_raises(ValueError, find_contours, r[..., None], 0.5)
if __name__ == '__main__':
from numpy.testing import run_module_suite
run_module_suite()
+6
View File
@@ -22,6 +22,8 @@ def test_approximate_polygon():
out = approximate_polygon(square, -1)
np.testing.assert_array_equal(out, square)
out = approximate_polygon(square, 0)
np.testing.assert_array_equal(out, square)
def test_subdivide_polygon():
@@ -51,6 +53,10 @@ def test_subdivide_polygon():
np.testing.assert_equal(new_square3.shape[0],
2 * (square3.shape[0] - mask_len + 2))
# not supported B-Spline degree
np.testing.assert_raises(ValueError, subdivide_polygon, square, 0)
np.testing.assert_raises(ValueError, subdivide_polygon, square, 8)
if __name__ == "__main__":
np.testing.run_module_suite()
+36 -4
View File
@@ -1,9 +1,9 @@
from numpy.testing import assert_array_equal, assert_almost_equal, \
assert_array_almost_equal
assert_array_almost_equal, assert_raises
import numpy as np
import math
from skimage.measure import regionprops
from skimage.measure._regionprops import regionprops, PROPS, perimeter
SAMPLE = np.array(
@@ -22,6 +22,16 @@ INTENSITY_SAMPLE = SAMPLE.copy()
INTENSITY_SAMPLE[1, 9:11] = 2
def test_unsupported_dtype():
assert_raises(TypeError, regionprops, np.zeros((10, 10), dtype=np.double))
def test_all_props():
props = regionprops(SAMPLE, 'all', INTENSITY_SAMPLE)[0]
for prop in PROPS:
assert prop in props
def test_area():
area = regionprops(SAMPLE, ['Area'])[0]['Area']
assert area == np.sum(SAMPLE)
@@ -36,6 +46,7 @@ def test_bbox():
bbox = regionprops(SAMPLE_mod, ['BoundingBox'])[0]['BoundingBox']
assert_array_almost_equal(bbox, (0, 0, SAMPLE.shape[0], SAMPLE.shape[1]-1))
def test_central_moments():
mu = regionprops(SAMPLE, ['CentralMoments'])[0]['CentralMoments']
#: determined with OpenCV
@@ -48,6 +59,7 @@ def test_central_moments():
assert_almost_equal(mu[2,1], 2000.296296296291)
assert_almost_equal(mu[3,0], -760.0246913580195)
def test_centroid():
centroid = regionprops(SAMPLE, ['Centroid'])[0]['Centroid']
# determined with MATLAB
@@ -90,6 +102,11 @@ def test_eccentricity():
eps = regionprops(SAMPLE, ['Eccentricity'])[0]['Eccentricity']
assert_almost_equal(eps, 0.814629313427)
img = np.zeros((5, 5), dtype=np.int)
img[2, 2] = 1
eps = regionprops(img, ['Eccentricity'])[0]['Eccentricity']
assert_almost_equal(eps, 0)
def test_equiv_diameter():
diameter = regionprops(SAMPLE, ['EquivDiameter'])[0]['EquivDiameter']
@@ -142,6 +159,11 @@ def test_filled_area():
assert area == np.sum(SAMPLE)
def test_filled_image():
img = regionprops(SAMPLE, ['FilledImage'])[0]['FilledImage']
assert_array_equal(img, SAMPLE)
def test_major_axis_length():
length = regionprops(SAMPLE, ['MajorAxisLength'])[0]['MajorAxisLength']
# MATLAB has different interpretation of ellipse than found in literature,
@@ -188,6 +210,7 @@ def test_moments():
assert_almost_equal(m[2,1], 43882.0)
assert_almost_equal(m[3,0], 95588.0)
def test_normalized_moments():
nu = regionprops(SAMPLE, ['NormalizedMoments'])[0]['NormalizedMoments']
#: determined with OpenCV
@@ -198,6 +221,7 @@ def test_normalized_moments():
assert_almost_equal(nu[2,1], 0.045473992910668816)
assert_almost_equal(nu[3,0], -0.017278118992041805)
def test_orientation():
orientation = regionprops(SAMPLE, ['Orientation'])[0]['Orientation']
# determined with MATLAB
@@ -219,15 +243,21 @@ def test_orientation():
)[0]['Orientation']
assert_almost_equal(orientation_diag, -math.pi / 4)
def test_perimeter():
perimeter = regionprops(SAMPLE, ['Perimeter'])[0]['Perimeter']
assert_almost_equal(perimeter, 59.2132034355964)
per = regionprops(SAMPLE, ['Perimeter'])[0]['Perimeter']
assert_almost_equal(per, 59.2132034355964)
per = perimeter(SAMPLE.astype('double'), neighbourhood=8)
assert_almost_equal(per, 43.1213203436)
def test_solidity():
solidity = regionprops(SAMPLE, ['Solidity'])[0]['Solidity']
# determined with MATLAB
assert_almost_equal(solidity, 0.580645161290323)
def test_weighted_central_moments():
wmu = regionprops(SAMPLE, ['WeightedCentralMoments'], INTENSITY_SAMPLE
)[0]['WeightedCentralMoments']
@@ -281,6 +311,7 @@ def test_weighted_moments():
)
assert_array_almost_equal(wm, ref)
def test_weighted_normalized_moments():
wnu = regionprops(SAMPLE, ['WeightedNormalizedMoments'], INTENSITY_SAMPLE
)[0]['WeightedNormalizedMoments']
@@ -292,6 +323,7 @@ def test_weighted_normalized_moments():
)
assert_array_almost_equal(wnu, ref)
if __name__ == "__main__":
from numpy.testing import run_module_suite
run_module_suite()
@@ -1,5 +1,5 @@
import numpy as np
from numpy.testing import assert_equal
from numpy.testing import assert_equal, assert_raises
from skimage.measure import structural_similarity as ssim
@@ -24,20 +24,19 @@ def test_ssim_image():
S1 = ssim(X, Y, win_size=3)
assert(S1 < 0.3)
## Come up with a better way of testing the gradient
##
## def test_ssim_grad():
## N = 30
## X = np.random.random((N, N)) * 255
## Y = np.random.random((N, N)) * 255
## def func(Y):
## return ssim(X, Y, dynamic_range=255)
# NOTE: This test is known to randomly fail on some systems (Mac OS X 10.6)
def test_ssim_grad():
N = 30
X = np.random.random((N, N)) * 255
Y = np.random.random((N, N)) * 255
## def grad(Y):
## return ssim(X, Y, dynamic_range=255, gradient=True)[1]
f = ssim(X, Y, dynamic_range=255)
g = ssim(X, Y, dynamic_range=255, gradient=True)
## assert(np.all(opt.check_grad(func, grad, Y) < 0.05))
assert f < 0.05
assert g[0] < 0.05
assert np.all(g[1] < 0.05)
def test_ssim_dtype():
@@ -56,5 +55,15 @@ def test_ssim_dtype():
assert S2 < 0.1
def test_invalid_input():
X = np.zeros((3, 3), dtype=np.double)
Y = np.zeros((3, 3), dtype=np.int)
assert_raises(ValueError, ssim, X, Y)
Y = np.zeros((4, 4), dtype=np.double)
assert_raises(ValueError, ssim, X, Y)
assert_raises(ValueError, ssim, X, X, win_size=8)
if __name__ == "__main__":
np.testing.run_module_suite()
+6 -9
View File
@@ -1,10 +1,3 @@
"""
:author: Damian Eads, 2009
:license: modified BSD
"""
__docformat__ = 'restructuredtext en'
import warnings
from skimage import img_as_ubyte
@@ -45,6 +38,7 @@ def erosion(image, selem, out=None, shift_x=False, shift_y=False):
Examples
--------
>>> # Erosion shrinks bright regions
>>> import numpy as np
>>> from skimage.morphology import square
>>> bright_square = np.array([[0, 0, 0, 0, 0],
... [0, 1, 1, 1, 0],
@@ -97,6 +91,7 @@ def dilation(image, selem, out=None, shift_x=False, shift_y=False):
Examples
--------
>>> # Dilation enlarges bright regions
>>> import numpy as np
>>> from skimage.morphology import square
>>> bright_pixel = np.array([[0, 0, 0, 0, 0],
... [0, 0, 0, 0, 0],
@@ -146,6 +141,7 @@ def opening(image, selem, out=None):
Examples
--------
>>> # Open up gap between two bright regions (but also shrink regions)
>>> import numpy as np
>>> from skimage.morphology import square
>>> bad_connection = np.array([[1, 0, 0, 0, 1],
... [1, 1, 0, 1, 1],
@@ -196,6 +192,7 @@ def closing(image, selem, out=None):
Examples
--------
>>> # Close a gap between two bright lines
>>> import numpy as np
>>> from skimage.morphology import square
>>> broken_line = np.array([[0, 0, 0, 0, 0],
... [0, 0, 0, 0, 0],
@@ -245,6 +242,7 @@ def white_tophat(image, selem, out=None):
Examples
--------
>>> # Subtract grey background from bright peak
>>> import numpy as np
>>> from skimage.morphology import square
>>> bright_on_grey = np.array([[2, 3, 3, 3, 2],
... [3, 4, 5, 4, 3],
@@ -261,7 +259,6 @@ def white_tophat(image, selem, out=None):
"""
if image is out:
raise NotImplementedError("Cannot perform white top hat in place.")
image = img_as_ubyte(image)
out = opening(image, selem, out=out)
out = image - out
@@ -294,6 +291,7 @@ def black_tophat(image, selem, out=None):
Examples
--------
>>> # Change dark peak to bright peak and subtract background
>>> import numpy as np
>>> from skimage.morphology import square
>>> dark_on_grey = np.array([[7, 6, 6, 6, 7],
... [6, 5, 4, 5, 6],
@@ -311,7 +309,6 @@ def black_tophat(image, selem, out=None):
if image is out:
raise NotImplementedError("Cannot perform white top hat in place.")
image = img_as_ubyte(image)
out = closing(image, selem, out=out)
out = out - image
+3 -3
View File
@@ -39,11 +39,11 @@ def configuration(parent_package='', top_path=None):
if __name__ == '__main__':
from numpy.distutils.core import setup
setup(maintainer='scikits-image Developers',
setup(maintainer='scikit-image Developers',
author='Damian Eads',
maintainer_email='scikits-image@googlegroups.com',
maintainer_email='scikit-image@googlegroups.com',
description='Morphology Wrapper',
url='https://github.com/scikits-image/scikits-image',
url='https://github.com/scikit-image/scikit-image',
license='SciPy License (BSD Style)',
**(configuration(top_path='').todict())
)
+1 -1
View File
@@ -2,5 +2,5 @@ from .random_walker_segmentation import random_walker
from ._felzenszwalb import felzenszwalb
from ._slic import slic
from ._quickshift import quickshift
from .boundaries import find_boundaries, visualize_boundaries
from .boundaries import find_boundaries, visualize_boundaries, mark_boundaries
from ._clear_border import clear_border
+32 -6
View File
@@ -1,19 +1,45 @@
import numpy as np
from ..morphology import dilation, square
from ..util import img_as_float
from ..color import gray2rgb
from .._shared.utils import deprecated
def find_boundaries(label_img):
"""Return bool array where boundaries between labeled regions are True."""
boundaries = np.zeros(label_img.shape, dtype=np.bool)
boundaries[1:, :] += label_img[1:, :] != label_img[:-1, :]
boundaries[:, 1:] += label_img[:, 1:] != label_img[:, :-1]
return boundaries
def visualize_boundaries(img, label_img):
img = img_as_float(img, force_copy=True)
def mark_boundaries(image, label_img, color=(1, 1, 0), outline_color=None):
"""Return image with boundaries between labeled regions highlighted.
Parameters
----------
image : (M, N[, 3]) array
Grayscale or RGB image.
label_img : (M, N) array
Label array where regions are marked by different integer values.
color : length-3 sequence
RGB color of boundaries in the output image.
outline_color : length-3 sequence
RGB color surrounding boundaries in the output image. If None, no
outline is drawn.
"""
if image.ndim == 2:
image = gray2rgb(image)
image = img_as_float(image, force_copy=True)
boundaries = find_boundaries(label_img)
outer_boundaries = dilation(boundaries.astype(np.uint8), square(2))
img[outer_boundaries != 0, :] = np.array([0, 0, 0]) # black
img[boundaries, :] = np.array([1, 1, 0]) # yellow
return img
if outline_color is not None:
outer_boundaries = dilation(boundaries.astype(np.uint8), square(2))
image[outer_boundaries != 0, :] = np.array(outline_color)
image[boundaries, :] = np.array(color)
return image
@deprecated('mark_boundaries')
def visualize_boundaries(*args, **kwargs):
return mark_boundaries(*args, **kwargs)
+3 -3
View File
@@ -25,10 +25,10 @@ def configuration(parent_package='', top_path=None):
if __name__ == '__main__':
from numpy.distutils.core import setup
setup(maintainer='scikits-image Developers',
maintainer_email='scikits-image@googlegroups.com',
setup(maintainer='scikit-image Developers',
maintainer_email='scikit-image@googlegroups.com',
description='Segmentation Algorithms',
url='https://github.com/scikits-image/scikits-image',
url='https://github.com/scikit-image/scikit-image',
license='SciPy License (BSD Style)',
**(configuration(top_path='').todict())
)
+1 -1
View File
@@ -6,6 +6,6 @@ from ._geometric import (warp, warp_coords, estimate_transform,
SimilarityTransform, AffineTransform,
ProjectiveTransform, PolynomialTransform,
PiecewiseAffineTransform)
from ._warps import swirl, homography, resize, rotate
from ._warps import swirl, homography, resize, rotate, rescale
from .pyramids import (pyramid_reduce, pyramid_expand,
pyramid_gaussian, pyramid_laplacian)
+4 -3
View File
@@ -1015,7 +1015,8 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1,
if mode == 'constant' and not (0 <= cval <= 1):
clipped[out == cval] = cval
if clipped.shape[0] == 1 or clipped.shape[1] == 1:
if clipped.ndim == 3 and orig_ndim == 2:
# remove singleton dim introduced by atleast_3d
return clipped[..., 0]
else:
return clipped
else: # remove singleton dim introduced by atleast_3d
return clipped.squeeze()
+86 -15
View File
@@ -1,17 +1,21 @@
import numpy as np
from scipy import ndimage
from ._geometric import (warp, SimilarityTransform, AffineTransform,
ProjectiveTransform)
def resize(image, output_shape, order=1, mode='constant', cval=0.):
"""Resize image.
"""Resize image to match a certain size.
Parameters
----------
image : ndarray
Input image.
output_shape : tuple or ndarray
Size of the generated output image `(rows, cols)`.
Size of the generated output image `(rows, cols[, dim])`. If `dim` is
not provided, the number of channels are preserved. In case the number
of input channels does not equal the number of output channels a
3-dimensional interpolation is applied.
Returns
-------
@@ -32,24 +36,88 @@ def resize(image, output_shape, order=1, mode='constant', cval=0.):
"""
rows, cols = output_shape
rows, cols = output_shape[0], output_shape[1]
orig_rows, orig_cols = image.shape[0], image.shape[1]
rscale = float(orig_rows) / rows
cscale = float(orig_cols) / cols
row_scale = float(orig_rows) / rows
col_scale = float(orig_cols) / cols
# 3 control points necessary to estimate exact AffineTransform
src_corners = np.array([[1, 1], [1, rows], [cols, rows]]) - 1
dst_corners = np.zeros(src_corners.shape, dtype=np.double)
# take into account that 0th pixel is at position (0.5, 0.5)
dst_corners[:, 0] = cscale * (src_corners[:, 0] + 0.5) - 0.5
dst_corners[:, 1] = rscale * (src_corners[:, 1] + 0.5) - 0.5
# 3-dimensional interpolation
if len(output_shape) == 3 and (image.ndim == 2
or output_shape[2] != image.shape[2]):
dim = output_shape[2]
orig_dim = 1 if image.ndim == 2 else image.shape[2]
dim_scale = float(orig_dim) / dim
tform = AffineTransform()
tform.estimate(src_corners, dst_corners)
map_rows, map_cols, map_dims = np.mgrid[:rows, :cols, :dim]
map_rows = row_scale * (map_rows + 0.5) - 0.5
map_cols = col_scale * (map_cols + 0.5) - 0.5
map_dims = dim_scale * (map_dims + 0.5) - 0.5
return warp(image, tform, output_shape=output_shape, order=order,
mode=mode, cval=cval)
coord_map = np.array([map_rows, map_cols, map_dims])
out = ndimage.map_coordinates(image, coord_map, order=order, mode=mode,
cval=cval)
else: # 2-dimensional interpolation
# 3 control points necessary to estimate exact AffineTransform
src_corners = np.array([[1, 1], [1, rows], [cols, rows]]) - 1
dst_corners = np.zeros(src_corners.shape, dtype=np.double)
# take into account that 0th pixel is at position (0.5, 0.5)
dst_corners[:, 0] = col_scale * (src_corners[:, 0] + 0.5) - 0.5
dst_corners[:, 1] = row_scale * (src_corners[:, 1] + 0.5) - 0.5
tform = AffineTransform()
tform.estimate(src_corners, dst_corners)
out = warp(image, tform, output_shape=output_shape, order=order,
mode=mode, cval=cval)
return out
def rescale(image, scale, order=1, mode='constant', cval=0.):
"""Scale image by a certain factor.
Parameters
----------
image : ndarray
Input image.
scale : {float, tuple of floats}
Scale factors. Separate scale factors can be defined as
`(row_scale, col_scale)`.
Returns
-------
scaled : ndarray
Scaled version of the input.
Other parameters
----------------
order : int
Order of splines used in interpolation. See
`scipy.ndimage.map_coordinates` for detail.
mode : string
How to handle values outside the image borders. See
`scipy.ndimage.map_coordinates` for detail.
cval : string
Used in conjunction with mode 'constant', the value outside
the image boundaries.
"""
try:
row_scale, col_scale = scale
except TypeError:
row_scale = col_scale = scale
orig_rows, orig_cols = image.shape[0], image.shape[1]
rows = np.round(row_scale * orig_rows)
cols = np.round(col_scale * orig_cols)
output_shape = (rows, cols)
return resize(image, output_shape, order=order, mode=mode, cval=cval)
def rotate(image, angle, resize=False, order=1, mode='constant', cval=0.):
@@ -280,3 +348,6 @@ def homography(image, H, output_shape=None, order=1,
tform = ProjectiveTransform(H)
return warp(image, inverse_map=tform.inverse, output_shape=output_shape,
order=order, mode=mode, cval=cval)
return warp(image, inverse_map=tform.inverse, output_shape=output_shape,
order=order, mode=mode, cval=cval)
+5 -5
View File
@@ -57,7 +57,7 @@ def pyramid_reduce(image, downscale=2, sigma=None, order=1,
References
----------
..[1] http://web.mit.edu/persci/people/adelson/pub_pdfs/pyramid83.pdf
.. [1] http://web.mit.edu/persci/people/adelson/pub_pdfs/pyramid83.pdf
"""
@@ -111,7 +111,7 @@ def pyramid_expand(image, upscale=2, sigma=None, order=1,
References
----------
..[1] http://web.mit.edu/persci/people/adelson/pub_pdfs/pyramid83.pdf
.. [1] http://web.mit.edu/persci/people/adelson/pub_pdfs/pyramid83.pdf
"""
@@ -176,7 +176,7 @@ def pyramid_gaussian(image, max_layer=-1, downscale=2, sigma=None, order=1,
References
----------
..[1] http://web.mit.edu/persci/people/adelson/pub_pdfs/pyramid83.pdf
.. [1] http://web.mit.edu/persci/people/adelson/pub_pdfs/pyramid83.pdf
"""
@@ -257,8 +257,8 @@ def pyramid_laplacian(image, max_layer=-1, downscale=2, sigma=None, order=1,
References
----------
..[1] http://web.mit.edu/persci/people/adelson/pub_pdfs/pyramid83.pdf
..[2] http://sepwww.stanford.edu/~morgan/texturematch/paper_html/node3.html
.. [1] http://web.mit.edu/persci/people/adelson/pub_pdfs/pyramid83.pdf
.. [2] http://sepwww.stanford.edu/~morgan/texturematch/paper_html/node3.html
"""
+5 -7
View File
@@ -20,19 +20,17 @@ def configuration(parent_package='', top_path=None):
include_dirs=[get_numpy_include_dirs()])
config.add_extension('_warps_cy', sources=['_warps_cy.c'],
include_dirs=[get_numpy_include_dirs(), '../_shared'],
extra_compile_args=['-fopenmp'],
extra_link_args=['-fopenmp'])
include_dirs=[get_numpy_include_dirs(), '../_shared'])
return config
if __name__ == '__main__':
from numpy.distutils.core import setup
setup(maintainer='Scikits-image Developers',
author='Scikits-image Developers',
maintainer_email='scikits-image@googlegroups.com',
setup(maintainer='scikit-image Developers',
author='scikit-image Developers',
maintainer_email='scikit-image@googlegroups.com',
description='Transforms',
url='https://github.com/scikits-image/scikits-image',
url='https://github.com/scikit-image/scikit-image',
license='SciPy License (BSD Style)',
**(configuration(top_path='').todict())
)
+44 -13
View File
@@ -1,41 +1,72 @@
from numpy.testing import assert_array_equal, run_module_suite
from numpy.testing import assert_array_equal, assert_raises, run_module_suite
from skimage import data
from skimage.transform import (pyramid_reduce, pyramid_expand,
pyramid_gaussian, pyramid_laplacian)
from skimage.transform import pyramids
image = data.lena()
image_gray = image[..., 0]
def test_pyramid_reduce():
def test_pyramid_reduce_rgb():
rows, cols, dim = image.shape
out = pyramid_reduce(image, downscale=2)
out = pyramids.pyramid_reduce(image, downscale=2)
assert_array_equal(out.shape, (rows / 2, cols / 2, dim))
def test_pyramid_expand():
def test_pyramid_reduce_gray():
rows, cols = image_gray.shape
out = pyramids.pyramid_reduce(image_gray, downscale=2)
assert_array_equal(out.shape, (rows / 2, cols / 2))
def test_pyramid_expand_rgb():
rows, cols, dim = image.shape
out = pyramid_expand(image, upscale=2)
out = pyramids.pyramid_expand(image, upscale=2)
assert_array_equal(out.shape, (rows * 2, cols * 2, dim))
def test_build_gaussian_pyramid():
rows, cols, dim = image.shape
pyramid = pyramid_gaussian(image, downscale=2)
def test_pyramid_expand_gray():
rows, cols = image_gray.shape
out = pyramids.pyramid_expand(image_gray, upscale=2)
assert_array_equal(out.shape, (rows * 2, cols * 2))
def test_build_gaussian_pyramid_rgb():
rows, cols, dim = image.shape
pyramid = pyramids.pyramid_gaussian(image, downscale=2)
for layer, out in enumerate(pyramid):
layer_shape = (rows / 2 ** layer, cols / 2 ** layer, dim)
assert_array_equal(out.shape, layer_shape)
def test_build_laplacian_pyramid():
rows, cols, dim = image.shape
pyramid = pyramid_laplacian(image, downscale=2)
def test_build_gaussian_pyramid_gray():
rows, cols = image_gray.shape
pyramid = pyramids.pyramid_gaussian(image_gray, downscale=2)
for layer, out in enumerate(pyramid):
layer_shape = (rows / 2 ** layer, cols / 2 ** layer)
assert_array_equal(out.shape, layer_shape)
def test_build_laplacian_pyramid_rgb():
rows, cols, dim = image.shape
pyramid = pyramids.pyramid_laplacian(image, downscale=2)
for layer, out in enumerate(pyramid):
layer_shape = (rows / 2 ** layer, cols / 2 ** layer, dim)
assert_array_equal(out.shape, layer_shape)
def test_build_laplacian_pyramid_gray():
rows, cols = image_gray.shape
pyramid = pyramids.pyramid_laplacian(image_gray, downscale=2)
for layer, out in enumerate(pyramid):
layer_shape = (rows / 2 ** layer, cols / 2 ** layer)
assert_array_equal(out.shape, layer_shape)
def test_check_factor():
assert_raises(ValueError, pyramids._check_factor, 0.99)
assert_raises(ValueError, pyramids._check_factor, - 2)
if __name__ == "__main__":
run_module_suite()
+56 -2
View File
@@ -2,7 +2,7 @@ from numpy.testing import assert_array_almost_equal, run_module_suite
import numpy as np
from scipy.ndimage import map_coordinates
from skimage.transform import (warp, warp_coords, rotate, resize,
from skimage.transform import (warp, warp_coords, rotate, resize, rescale,
AffineTransform,
ProjectiveTransform,
SimilarityTransform, homography)
@@ -85,7 +85,25 @@ def test_rotate():
assert_array_almost_equal(x90, np.rot90(x))
def test_resize():
def test_rescale():
# same scale factor
x = np.zeros((5, 5), dtype=np.double)
x[1, 1] = 1
scaled = rescale(x, 2, order=0)
ref = np.zeros((10, 10))
ref[2:4, 2:4] = 1
assert_array_almost_equal(scaled, ref)
# different scale factors
x = np.zeros((5, 5), dtype=np.double)
x[1, 1] = 1
scaled = rescale(x, (2, 1), order=0)
ref = np.zeros((10, 5))
ref[2:4, 1] = 1
assert_array_almost_equal(scaled, ref)
def test_resize2d():
x = np.zeros((5, 5), dtype=np.double)
x[1, 1] = 1
resized = resize(x, (10, 10), order=0)
@@ -94,6 +112,42 @@ def test_resize():
assert_array_almost_equal(resized, ref)
def test_resize3d_keep():
# keep 3rd dimension
x = np.zeros((5, 5, 3), dtype=np.double)
x[1, 1, :] = 1
resized = resize(x, (10, 10), order=0)
ref = np.zeros((10, 10, 3))
ref[2:4, 2:4, :] = 1
assert_array_almost_equal(resized, ref)
resized = resize(x, (10, 10, 3), order=0)
assert_array_almost_equal(resized, ref)
def test_resize3d_resize():
# resize 3rd dimension
x = np.zeros((5, 5, 3), dtype=np.double)
x[1, 1, :] = 1
resized = resize(x, (10, 10, 1), order=0)
ref = np.zeros((10, 10, 1))
ref[2:4, 2:4] = 1
assert_array_almost_equal(resized, ref)
def test_resize3d_bilinear():
# bilinear 3rd dimension
x = np.zeros((5, 5, 2), dtype=np.double)
x[1, 1, 0] = 0
x[1, 1, 1] = 1
resized = resize(x, (10, 10, 1), order=1)
ref = np.zeros((10, 10, 1))
ref[1:5, 1:5, :] = 0.03125
ref[1:5, 2:4, :] = 0.09375
ref[2:4, 1:5, :] = 0.09375
ref[2:4, 2:4, :] = 0.28125
assert_array_almost_equal(resized, ref)
def test_swirl():
image = img_as_float(data.checkerboard())
+2
View File
@@ -71,6 +71,8 @@ def montage2d(arr_in, fill='mean', rescale_intensity=False):
assert arr_in.ndim == 3
n_images, height, width = arr_in.shape
arr_in = arr_in.copy()
# -- rescale intensity if necessary
if rescale_intensity: