mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-13 17:45:20 +08:00
Merge commit 'v0.5-100-gfeb3e92' into debian
* commit 'v0.5-100-gfeb3e92': TST: Increase radon transform threshold to make test more robust. BUG: Fix plugin import on systems without PIL or FreeImage. BUG: Ensure that the appropriate I/O plugin is used in the test suite. BUG: Fix Python 3 syntax error. Rename test module to match module. Add `__all__` to grey module. Remove unused variable. Replace `import *` with `import grey`. Fix dtype compatibility for functions in morphology.grey Make test module runnable. Rename greyscale morphology functions. Remove unused imports Add "page.png" and use for threshold example. Fixed padding in radon, iradon. Tests for small images. DOC: Add CSS for LaTeX math. Change "text" image to grayscale. DOC: Add example of adaptive thresholding.
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
"""
|
||||
=====================
|
||||
Adaptive Thresholding
|
||||
=====================
|
||||
|
||||
Thresholding is the simplest way to segment objects from a background. If that
|
||||
background is relatively uniform, then you can use a global threshold value to
|
||||
binarize the image by pixel-intensity. If there's large variation in the
|
||||
background intensity, however, adaptive thresholding (a.k.a. local or dynamic
|
||||
thresholding) may produce better results.
|
||||
|
||||
Here, we binarize an image using the `threshold_adaptive` function, which
|
||||
calculates thresholds in regions of size `block_size` surrounding each pixel
|
||||
(i.e. local neighborhoods). Each threshold value is the weighted mean of the
|
||||
local neighborhood minus an offset value.
|
||||
|
||||
"""
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from skimage import data
|
||||
from skimage.filter import threshold_otsu, threshold_adaptive
|
||||
|
||||
|
||||
image = data.page()
|
||||
|
||||
global_thresh = threshold_otsu(image)
|
||||
binary_global = image > global_thresh
|
||||
|
||||
block_size = 40
|
||||
binary_adaptive = threshold_adaptive(image, block_size, offset=10)
|
||||
|
||||
fig, axes = plt.subplots(nrows=3, figsize=(7, 8))
|
||||
ax0, ax1, ax2 = axes
|
||||
plt.gray()
|
||||
|
||||
ax0.imshow(image)
|
||||
ax0.set_title('Image')
|
||||
|
||||
ax1.imshow(binary_global)
|
||||
ax1.set_title('Global thresholding')
|
||||
|
||||
ax2.imshow(binary_adaptive)
|
||||
ax2.set_title('Adaptive thresholding')
|
||||
|
||||
for ax in axes:
|
||||
ax.axis('off')
|
||||
|
||||
plt.show()
|
||||
@@ -737,3 +737,16 @@ p.rubric {
|
||||
font-weight: bold;
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
/* Math */
|
||||
img.math {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.body div.math p {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
span.eqno {
|
||||
float: right;
|
||||
}
|
||||
|
||||
@@ -96,3 +96,12 @@ def moon():
|
||||
|
||||
"""
|
||||
return load("moon.png")
|
||||
|
||||
def page():
|
||||
"""Scanned page.
|
||||
|
||||
This image of printed text is useful for demonstrations requiring uneven
|
||||
background illumination.
|
||||
|
||||
"""
|
||||
return load("page.png")
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 42 KiB |
@@ -14,6 +14,19 @@ try:
|
||||
except OSError:
|
||||
FI_available = False
|
||||
|
||||
|
||||
def setup_module(self):
|
||||
"""The effect of the `plugin.use` call may be overridden by later imports.
|
||||
Call `use_plugin` directly before the tests to ensure that freeimage is
|
||||
used.
|
||||
|
||||
"""
|
||||
try:
|
||||
sio.use_plugin('freeimage')
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
@skipif(not FI_available)
|
||||
def test_imread():
|
||||
img = sio.imread(os.path.join(si.data_dir, 'color.png'))
|
||||
|
||||
@@ -18,6 +18,16 @@ else:
|
||||
PIL_available = True
|
||||
|
||||
|
||||
def setup_module(self):
|
||||
"""The effect of the `plugin.use` call may be overridden by later imports.
|
||||
Call `use_plugin` directly before the tests to ensure that PIL is used.
|
||||
|
||||
"""
|
||||
try:
|
||||
use_plugin('pil')
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
@skipif(not PIL_available)
|
||||
def test_imread_flatten():
|
||||
# a color image is flattened
|
||||
|
||||
+78
-34
@@ -5,11 +5,20 @@
|
||||
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import warnings
|
||||
|
||||
import numpy as np
|
||||
|
||||
eps = np.finfo(float).eps
|
||||
import skimage
|
||||
|
||||
def greyscale_erode(image, selem, out=None, shift_x=False, shift_y=False):
|
||||
|
||||
__all__ = ['erosion', 'dilation', 'opening', 'closing', 'white_tophat',
|
||||
'black_tophat', 'greyscale_erode', 'greyscale_dilate',
|
||||
'greyscale_open', 'greyscale_close', 'greyscale_white_top_hat',
|
||||
'greyscale_black_top_hat']
|
||||
|
||||
|
||||
def erosion(image, selem, out=None, shift_x=False, shift_y=False):
|
||||
"""Return greyscale morphological erosion of an image.
|
||||
|
||||
Morphological erosion sets a pixel at (i,j) to the minimum over all pixels
|
||||
@@ -19,7 +28,7 @@ def greyscale_erode(image, selem, out=None, shift_x=False, shift_y=False):
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
The image as a uint8 ndarray.
|
||||
Image array.
|
||||
|
||||
selem : ndarray
|
||||
The neighborhood expressed as a 2-D array of 1's and 0's.
|
||||
@@ -34,7 +43,7 @@ def greyscale_erode(image, selem, out=None, shift_x=False, shift_y=False):
|
||||
|
||||
Returns
|
||||
-------
|
||||
eroded : ndarray
|
||||
eroded : uint8 array
|
||||
The result of the morphological erosion.
|
||||
|
||||
Examples
|
||||
@@ -46,7 +55,7 @@ def greyscale_erode(image, selem, out=None, shift_x=False, shift_y=False):
|
||||
... [0, 1, 1, 1, 0],
|
||||
... [0, 1, 1, 1, 0],
|
||||
... [0, 0, 0, 0, 0]], dtype=np.uint8)
|
||||
>>> greyscale_erode(bright_square, square(3))
|
||||
>>> erosion(bright_square, square(3))
|
||||
array([[0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0],
|
||||
@@ -56,6 +65,8 @@ def greyscale_erode(image, selem, out=None, shift_x=False, shift_y=False):
|
||||
"""
|
||||
if image is out:
|
||||
raise NotImplementedError("In-place erosion not supported!")
|
||||
image = skimage.img_as_ubyte(image)
|
||||
|
||||
try:
|
||||
import skimage.morphology.cmorph as cmorph
|
||||
out = cmorph.erode(image, selem, out=out,
|
||||
@@ -64,7 +75,8 @@ def greyscale_erode(image, selem, out=None, shift_x=False, shift_y=False):
|
||||
except ImportError:
|
||||
raise ImportError("cmorph extension not available.")
|
||||
|
||||
def greyscale_dilate(image, selem, out=None, shift_x=False, shift_y=False):
|
||||
|
||||
def dilation(image, selem, out=None, shift_x=False, shift_y=False):
|
||||
"""Return greyscale morphological dilation of an image.
|
||||
|
||||
Morphological dilation sets a pixel at (i,j) to the maximum over all pixels
|
||||
@@ -75,7 +87,7 @@ def greyscale_dilate(image, selem, out=None, shift_x=False, shift_y=False):
|
||||
----------
|
||||
|
||||
image : ndarray
|
||||
The image as a uint8 ndarray.
|
||||
Image array.
|
||||
|
||||
selem : ndarray
|
||||
The neighborhood expressed as a 2-D array of 1's and 0's.
|
||||
@@ -90,7 +102,7 @@ def greyscale_dilate(image, selem, out=None, shift_x=False, shift_y=False):
|
||||
|
||||
Returns
|
||||
-------
|
||||
dilated : ndarray
|
||||
dilated : uint8 array
|
||||
The result of the morphological dilation.
|
||||
|
||||
Examples
|
||||
@@ -102,7 +114,7 @@ def greyscale_dilate(image, selem, out=None, shift_x=False, shift_y=False):
|
||||
... [0, 0, 1, 0, 0],
|
||||
... [0, 0, 0, 0, 0],
|
||||
... [0, 0, 0, 0, 0]], dtype=np.uint8)
|
||||
>>> greyscale_dilate(bright_pixel, square(3))
|
||||
>>> dilation(bright_pixel, square(3))
|
||||
array([[0, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 0],
|
||||
[0, 1, 1, 1, 0],
|
||||
@@ -112,6 +124,8 @@ def greyscale_dilate(image, selem, out=None, shift_x=False, shift_y=False):
|
||||
"""
|
||||
if image is out:
|
||||
raise NotImplementedError("In-place dilation not supported!")
|
||||
image = skimage.img_as_ubyte(image)
|
||||
|
||||
try:
|
||||
from . import cmorph
|
||||
out = cmorph.dilate(image, selem, out=out,
|
||||
@@ -120,7 +134,8 @@ def greyscale_dilate(image, selem, out=None, shift_x=False, shift_y=False):
|
||||
except ImportError:
|
||||
raise ImportError("cmorph extension not available.")
|
||||
|
||||
def greyscale_open(image, selem, out=None):
|
||||
|
||||
def opening(image, selem, out=None):
|
||||
"""Return greyscale morphological opening of an image.
|
||||
|
||||
The morphological opening on an image is defined as an erosion followed by
|
||||
@@ -131,7 +146,7 @@ def greyscale_open(image, selem, out=None):
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
The image as a uint8 ndarray.
|
||||
Image array.
|
||||
|
||||
selem : ndarray
|
||||
The neighborhood expressed as a 2-D array of 1's and 0's.
|
||||
@@ -142,7 +157,7 @@ def greyscale_open(image, selem, out=None):
|
||||
|
||||
Returns
|
||||
-------
|
||||
opening : ndarray
|
||||
opening : uint8 array
|
||||
The result of the morphological opening.
|
||||
|
||||
Examples
|
||||
@@ -154,7 +169,7 @@ def greyscale_open(image, selem, out=None):
|
||||
... [1, 1, 1, 1, 1],
|
||||
... [1, 1, 0, 1, 1],
|
||||
... [1, 0, 0, 0, 1]], dtype=np.uint8)
|
||||
>>> greyscale_open(bad_connection, square(3))
|
||||
>>> opening(bad_connection, square(3))
|
||||
array([[0, 0, 0, 0, 0],
|
||||
[1, 1, 0, 1, 1],
|
||||
[1, 1, 0, 1, 1],
|
||||
@@ -166,12 +181,12 @@ def greyscale_open(image, selem, out=None):
|
||||
shift_x = True if (w % 2) == 0 else False
|
||||
shift_y = True if (h % 2) == 0 else False
|
||||
|
||||
eroded = greyscale_erode(image, selem)
|
||||
out = greyscale_dilate(eroded, selem, out=out,
|
||||
shift_x=shift_x, shift_y=shift_y)
|
||||
eroded = erosion(image, selem)
|
||||
out = dilation(eroded, selem, out=out, shift_x=shift_x, shift_y=shift_y)
|
||||
return out
|
||||
|
||||
def greyscale_close(image, selem, out=None):
|
||||
|
||||
def closing(image, selem, out=None):
|
||||
"""Return greyscale morphological closing of an image.
|
||||
|
||||
The morphological closing on an image is defined as a dilation followed by
|
||||
@@ -182,7 +197,7 @@ def greyscale_close(image, selem, out=None):
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
The image as a uint8 ndarray.
|
||||
Image array.
|
||||
|
||||
selem : ndarray
|
||||
The neighborhood expressed as a 2-D array of 1's and 0's.
|
||||
@@ -193,8 +208,8 @@ def greyscale_close(image, selem, out=None):
|
||||
|
||||
Returns
|
||||
-------
|
||||
opening : ndarray
|
||||
The result of the morphological opening.
|
||||
closing : uint8 array
|
||||
The result of the morphological closing.
|
||||
|
||||
Examples
|
||||
--------
|
||||
@@ -205,7 +220,7 @@ def greyscale_close(image, selem, out=None):
|
||||
... [1, 1, 0, 1, 1],
|
||||
... [0, 0, 0, 0, 0],
|
||||
... [0, 0, 0, 0, 0]], dtype=np.uint8)
|
||||
>>> greyscale_close(broken_line, square(3))
|
||||
>>> closing(broken_line, square(3))
|
||||
array([[0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 1, 1],
|
||||
@@ -217,12 +232,12 @@ def greyscale_close(image, selem, out=None):
|
||||
shift_x = True if (w % 2) == 0 else False
|
||||
shift_y = True if (h % 2) == 0 else False
|
||||
|
||||
dilated = greyscale_dilate(image, selem)
|
||||
out = greyscale_erode(dilated, selem, out=out,
|
||||
shift_x=shift_x, shift_y=shift_y)
|
||||
dilated = dilation(image, selem)
|
||||
out = erosion(dilated, selem, out=out, shift_x=shift_x, shift_y=shift_y)
|
||||
return out
|
||||
|
||||
def greyscale_white_top_hat(image, selem, out=None):
|
||||
|
||||
def white_tophat(image, selem, out=None):
|
||||
"""Return white top hat of an image.
|
||||
|
||||
The white top hat of an image is defined as the image minus its
|
||||
@@ -232,7 +247,7 @@ def greyscale_white_top_hat(image, selem, out=None):
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
The image as a uint8 ndarray.
|
||||
Image array.
|
||||
|
||||
selem : ndarray
|
||||
The neighborhood expressed as a 2-D array of 1's and 0's.
|
||||
@@ -243,7 +258,7 @@ def greyscale_white_top_hat(image, selem, out=None):
|
||||
|
||||
Returns
|
||||
-------
|
||||
opening : ndarray
|
||||
opening : uint8 array
|
||||
The result of the morphological white top hat.
|
||||
|
||||
Examples
|
||||
@@ -255,7 +270,7 @@ def greyscale_white_top_hat(image, selem, out=None):
|
||||
... [3, 5, 9, 5, 3],
|
||||
... [3, 4, 5, 4, 3],
|
||||
... [2, 3, 3, 3, 2]], dtype=np.uint8)
|
||||
>>> greyscale_white_top_hat(bright_on_grey, square(3))
|
||||
>>> white_tophat(bright_on_grey, square(3))
|
||||
array([[0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0],
|
||||
[0, 1, 5, 1, 0],
|
||||
@@ -265,12 +280,14 @@ def greyscale_white_top_hat(image, selem, out=None):
|
||||
"""
|
||||
if image is out:
|
||||
raise NotImplementedError("Cannot perform white top hat in place.")
|
||||
image = skimage.img_as_ubyte(image)
|
||||
|
||||
out = greyscale_open(image, selem, out=out)
|
||||
out = opening(image, selem, out=out)
|
||||
out = image - out
|
||||
return out
|
||||
|
||||
def greyscale_black_top_hat(image, selem, out=None):
|
||||
|
||||
def black_tophat(image, selem, out=None):
|
||||
"""Return black top hat of an image.
|
||||
|
||||
The black top hat of an image is defined as its morphological closing minus
|
||||
@@ -281,7 +298,7 @@ def greyscale_black_top_hat(image, selem, out=None):
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
The image as a uint8 ndarray.
|
||||
Image array.
|
||||
|
||||
selem : ndarray
|
||||
The neighborhood expressed as a 2-D array of 1's and 0's.
|
||||
@@ -292,7 +309,7 @@ def greyscale_black_top_hat(image, selem, out=None):
|
||||
|
||||
Returns
|
||||
-------
|
||||
opening : ndarray
|
||||
opening : uint8 array
|
||||
The result of the black top filter.
|
||||
|
||||
Examples
|
||||
@@ -304,7 +321,7 @@ def greyscale_black_top_hat(image, selem, out=None):
|
||||
... [6, 4, 0, 4, 6],
|
||||
... [6, 5, 4, 5, 6],
|
||||
... [7, 6, 6, 6, 7]], dtype=np.uint8)
|
||||
>>> greyscale_black_top_hat(dark_on_grey, square(3))
|
||||
>>> black_tophat(dark_on_grey, square(3))
|
||||
array([[0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0],
|
||||
[0, 1, 5, 1, 0],
|
||||
@@ -314,7 +331,34 @@ def greyscale_black_top_hat(image, selem, out=None):
|
||||
"""
|
||||
if image is out:
|
||||
raise NotImplementedError("Cannot perform white top hat in place.")
|
||||
out = greyscale_close(image, selem, out=out)
|
||||
image = skimage.img_as_ubyte(image)
|
||||
|
||||
out = closing(image, selem, out=out)
|
||||
out = out - image
|
||||
return out
|
||||
|
||||
|
||||
def greyscale_erode(*args, **kwargs):
|
||||
warnings.warn("`greyscale_erode` renamed `erosion`.")
|
||||
return erosion(*args, **kwargs)
|
||||
|
||||
def greyscale_dilate(*args, **kwargs):
|
||||
warnings.warn("`greyscale_dilate` renamed `dilation`.")
|
||||
return dilation(*args, **kwargs)
|
||||
|
||||
def greyscale_open(*args, **kwargs):
|
||||
warnings.warn("`greyscale_open` renamed `opening`.")
|
||||
return opening(*args, **kwargs)
|
||||
|
||||
def greyscale_close(*args, **kwargs):
|
||||
warnings.warn("`greyscale_close` renamed `closing`.")
|
||||
return closing(*args, **kwargs)
|
||||
|
||||
def greyscale_white_top_hat(*args, **kwargs):
|
||||
warnings.warn("`greyscale_white_top_hat` renamed `white_tophat`.")
|
||||
return white_tophat(*args, **kwargs)
|
||||
|
||||
def greyscale_black_top_hat(*args, **kwargs):
|
||||
warnings.warn("`greyscale_black_top_hat` renamed `black_tophat`.")
|
||||
return black_tophat(*args, **kwargs)
|
||||
|
||||
|
||||
+67
-27
@@ -1,12 +1,13 @@
|
||||
import os.path
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import *
|
||||
from numpy import testing
|
||||
|
||||
import skimage
|
||||
from skimage import data_dir
|
||||
from skimage.io import imread
|
||||
from skimage import data_dir
|
||||
from skimage.morphology import *
|
||||
from skimage.morphology import grey
|
||||
from skimage.morphology import selem
|
||||
|
||||
|
||||
lena = np.load(os.path.join(data_dir, 'lena_GRAY_U8.npy'))
|
||||
|
||||
@@ -19,48 +20,48 @@ class TestMorphology():
|
||||
expected_result = matlab_results[arrname]
|
||||
mask = strel_func(k)
|
||||
actual_result = morph_func(lena, mask)
|
||||
assert_equal(expected_result, actual_result)
|
||||
testing.assert_equal(expected_result, actual_result)
|
||||
k = k + 1
|
||||
|
||||
def test_erode_diamond(self):
|
||||
self.morph_worker(lena, "diamond-erode-matlab-output.npz",
|
||||
greyscale_erode, diamond)
|
||||
grey.erosion, selem.diamond)
|
||||
|
||||
def test_dilate_diamond(self):
|
||||
self.morph_worker(lena, "diamond-dilate-matlab-output.npz",
|
||||
greyscale_dilate, diamond)
|
||||
grey.dilation, selem.diamond)
|
||||
|
||||
def test_open_diamond(self):
|
||||
self.morph_worker(lena, "diamond-open-matlab-output.npz",
|
||||
greyscale_open, diamond)
|
||||
grey.opening, selem.diamond)
|
||||
|
||||
def test_close_diamond(self):
|
||||
self.morph_worker(lena, "diamond-close-matlab-output.npz",
|
||||
greyscale_close, diamond)
|
||||
grey.closing, selem.diamond)
|
||||
|
||||
def test_tophat_diamond(self):
|
||||
self.morph_worker(lena, "diamond-tophat-matlab-output.npz",
|
||||
greyscale_white_top_hat, diamond)
|
||||
grey.white_tophat, selem.diamond)
|
||||
|
||||
def test_bothat_diamond(self):
|
||||
self.morph_worker(lena, "diamond-bothat-matlab-output.npz",
|
||||
greyscale_black_top_hat, diamond)
|
||||
grey.black_tophat, selem.diamond)
|
||||
|
||||
def test_erode_disk(self):
|
||||
self.morph_worker(lena, "disk-erode-matlab-output.npz",
|
||||
greyscale_erode, disk)
|
||||
grey.erosion, selem.disk)
|
||||
|
||||
def test_dilate_disk(self):
|
||||
self.morph_worker(lena, "disk-dilate-matlab-output.npz",
|
||||
greyscale_dilate, disk)
|
||||
grey.dilation, selem.disk)
|
||||
|
||||
def test_open_disk(self):
|
||||
self.morph_worker(lena, "disk-open-matlab-output.npz",
|
||||
greyscale_open, disk)
|
||||
grey.opening, selem.disk)
|
||||
|
||||
def test_close_disk(self):
|
||||
self.morph_worker(lena, "disk-close-matlab-output.npz",
|
||||
greyscale_close, disk)
|
||||
grey.closing, selem.disk)
|
||||
|
||||
|
||||
class TestEccentricStructuringElements():
|
||||
@@ -69,50 +70,89 @@ class TestEccentricStructuringElements():
|
||||
self.black_pixel = 255 * np.ones((4, 4), dtype=np.uint8)
|
||||
self.black_pixel[1, 1] = 0
|
||||
self.white_pixel = 255 - self.black_pixel
|
||||
self.selems = [square(2), rectangle(2, 2),
|
||||
rectangle(2, 1), rectangle(1, 2)]
|
||||
self.selems = [selem.square(2), selem.rectangle(2, 2),
|
||||
selem.rectangle(2, 1), selem.rectangle(1, 2)]
|
||||
|
||||
def test_dilate_erode_symmetry(self):
|
||||
for s in self.selems:
|
||||
c = greyscale_erode(self.black_pixel, s)
|
||||
d = greyscale_dilate(self.white_pixel, s)
|
||||
c = grey.erosion(self.black_pixel, s)
|
||||
d = grey.dilation(self.white_pixel, s)
|
||||
assert np.all(c == (255 - d))
|
||||
|
||||
def test_open_black_pixel(self):
|
||||
for s in self.selems:
|
||||
grey_open = greyscale_open(self.black_pixel, s)
|
||||
grey_open = grey.opening(self.black_pixel, s)
|
||||
assert np.all(grey_open == self.black_pixel)
|
||||
|
||||
def test_close_white_pixel(self):
|
||||
for s in self.selems:
|
||||
grey_close = greyscale_close(self.white_pixel, s)
|
||||
grey_close = grey.closing(self.white_pixel, s)
|
||||
assert np.all(grey_close == self.white_pixel)
|
||||
|
||||
def test_open_white_pixel(self):
|
||||
for s in self.selems:
|
||||
assert np.all(greyscale_open(self.white_pixel, s) == 0)
|
||||
assert np.all(grey.opening(self.white_pixel, s) == 0)
|
||||
|
||||
def test_close_black_pixel(self):
|
||||
for s in self.selems:
|
||||
assert np.all(greyscale_close(self.black_pixel, s) == 255)
|
||||
assert np.all(grey.closing(self.black_pixel, s) == 255)
|
||||
|
||||
def test_white_tophat_white_pixel(self):
|
||||
for s in self.selems:
|
||||
tophat = greyscale_white_top_hat(self.white_pixel, s)
|
||||
tophat = grey.white_tophat(self.white_pixel, s)
|
||||
assert np.all(tophat == self.white_pixel)
|
||||
|
||||
def test_black_tophat_black_pixel(self):
|
||||
for s in self.selems:
|
||||
tophat = greyscale_black_top_hat(self.black_pixel, s)
|
||||
tophat = grey.black_tophat(self.black_pixel, s)
|
||||
assert np.all(tophat == (255 - self.black_pixel))
|
||||
|
||||
def test_white_tophat_black_pixel(self):
|
||||
for s in self.selems:
|
||||
tophat = greyscale_white_top_hat(self.black_pixel, s)
|
||||
tophat = grey.white_tophat(self.black_pixel, s)
|
||||
assert np.all(tophat == 0)
|
||||
|
||||
def test_black_tophat_white_pixel(self):
|
||||
for s in self.selems:
|
||||
tophat = greyscale_black_top_hat(self.white_pixel, s)
|
||||
tophat = grey.black_tophat(self.white_pixel, s)
|
||||
assert np.all(tophat == 0)
|
||||
|
||||
|
||||
class TestDTypes():
|
||||
|
||||
def setUp(self):
|
||||
k = 5
|
||||
arrname = '%03i' % k
|
||||
|
||||
self.disk = selem.disk(k)
|
||||
|
||||
fname_opening = os.path.join(data_dir, "disk-open-matlab-output.npz")
|
||||
self.expected_opening = np.load(fname_opening)[arrname]
|
||||
|
||||
fname_closing = os.path.join(data_dir, "disk-close-matlab-output.npz")
|
||||
self.expected_closing = np.load(fname_closing)[arrname]
|
||||
|
||||
def _test_image(self, image):
|
||||
result_opening = grey.opening(image, self.disk)
|
||||
testing.assert_equal(result_opening, self.expected_opening)
|
||||
|
||||
result_closing = grey.closing(image, self.disk)
|
||||
testing.assert_equal(result_closing, self.expected_closing)
|
||||
|
||||
def test_float(self):
|
||||
image = skimage.img_as_float(lena)
|
||||
self._test_image(image)
|
||||
|
||||
@testing.decorators.skipif(True)
|
||||
def test_int(self):
|
||||
image = skimage.img_as_int(lena)
|
||||
self._test_image(image)
|
||||
|
||||
def test_uint(self):
|
||||
image = skimage.img_as_uint(lena)
|
||||
self._test_image(image)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testing.run_module_suite()
|
||||
|
||||
@@ -44,8 +44,8 @@ def radon(image, theta=None):
|
||||
theta = np.arange(180)
|
||||
height, width = image.shape
|
||||
diagonal = np.sqrt(height ** 2 + width ** 2)
|
||||
heightpad = np.ceil(diagonal - height) + 2
|
||||
widthpad = np.ceil(diagonal - width) + 2
|
||||
heightpad = np.ceil(diagonal - height)
|
||||
widthpad = np.ceil(diagonal - width)
|
||||
padded_image = np.zeros((int(height + heightpad),
|
||||
int(width + widthpad)))
|
||||
y0, y1 = int(np.ceil(heightpad / 2)), \
|
||||
@@ -57,14 +57,16 @@ def radon(image, theta=None):
|
||||
out = np.zeros((max(padded_image.shape), len(theta)))
|
||||
|
||||
h, w = padded_image.shape
|
||||
shift0 = np.array([[1, 0, -w/2.],
|
||||
[0, 1, -h/2.],
|
||||
dh, dw = h / 2, w / 2
|
||||
shift0 = np.array([[1, 0, -dw],
|
||||
[0, 1, -dh],
|
||||
[0, 0, 1]])
|
||||
|
||||
shift1 = np.array([[1, 0, w/2.],
|
||||
[0, 1, h/2.],
|
||||
shift1 = np.array([[1, 0, dw],
|
||||
[0, 1, dh],
|
||||
[0, 0, 1]])
|
||||
|
||||
|
||||
def build_rotation(theta):
|
||||
T = -np.deg2rad(theta)
|
||||
|
||||
@@ -129,7 +131,7 @@ def iradon(radon_image, theta=None, output_size=None,
|
||||
th = (np.pi / 180.0) * theta
|
||||
# if output size not specified, estimate from input radon image
|
||||
if not output_size:
|
||||
output_size = 2 * np.floor(radon_image.shape[0] / (2 * np.sqrt(2)))
|
||||
output_size = int(np.floor(np.sqrt((radon_image.shape[0]) ** 2 / 2.0)))
|
||||
n = radon_image.shape[0]
|
||||
|
||||
img = radon_image.copy()
|
||||
@@ -166,13 +168,14 @@ def iradon(radon_image, theta=None, output_size=None,
|
||||
# resize filtered image back to original size
|
||||
radon_filtered = radon_filtered[:radon_image.shape[0], :]
|
||||
reconstructed = np.zeros((output_size, output_size))
|
||||
mid_index = np.ceil(n/2);
|
||||
mid_index = np.ceil(n / 2.0)
|
||||
|
||||
x = output_size
|
||||
y = output_size
|
||||
[X, Y] = np.mgrid[0.0:x, 0.0:y]
|
||||
xpr = X - (output_size + 1.0) / 2.0
|
||||
ypr = Y - (output_size + 1.0) / 2.0
|
||||
|
||||
xpr = X - int(output_size) / 2
|
||||
ypr = Y - int(output_size) / 2
|
||||
|
||||
# reconstruct image by interpolation
|
||||
if interpolation == "nearest":
|
||||
for i in range(len(theta)):
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import *
|
||||
from skimage.transform import *
|
||||
@@ -10,6 +12,7 @@ def rescale(x):
|
||||
|
||||
def test_radon_iradon():
|
||||
size = 100
|
||||
debug = False
|
||||
image = np.tri(size) + np.tri(size)[::-1]
|
||||
for filter_type in ["ramp", "shepp-logan", "cosine", "hamming", "hann"]:
|
||||
reconstructed = iradon(radon(image), filter=filter_type)
|
||||
@@ -18,12 +21,13 @@ def test_radon_iradon():
|
||||
reconstructed = rescale(reconstructed)
|
||||
delta = np.mean(np.abs(image - reconstructed))
|
||||
|
||||
## print delta
|
||||
## import matplotlib.pyplot as plt
|
||||
## f, (ax1, ax2) = plt.subplots(1, 2)
|
||||
## ax1.imshow(image, cmap=plt.cm.gray)
|
||||
## ax2.imshow(reconstructed, cmap=plt.cm.gray)
|
||||
## plt.show()
|
||||
if debug:
|
||||
print(delta)
|
||||
import matplotlib.pyplot as plt
|
||||
f, (ax1, ax2) = plt.subplots(1, 2)
|
||||
ax1.imshow(image, cmap=plt.cm.gray)
|
||||
ax2.imshow(reconstructed, cmap=plt.cm.gray)
|
||||
plt.show()
|
||||
|
||||
assert delta < 0.05
|
||||
|
||||
@@ -33,7 +37,7 @@ def test_radon_iradon():
|
||||
size = 20
|
||||
image = np.tri(size) + np.tri(size)[::-1]
|
||||
reconstructed = iradon(radon(image), filter="ramp", interpolation="nearest")
|
||||
|
||||
|
||||
def test_iradon_angles():
|
||||
"""
|
||||
Test with different number of projections
|
||||
@@ -43,7 +47,7 @@ def test_iradon_angles():
|
||||
image = np.tri(size) + np.tri(size)[::-1]
|
||||
# Large number of projections: a good quality is expected
|
||||
nb_angles = 200
|
||||
radon_image_200 = radon(image, theta=np.linspace(0, 180, nb_angles,
|
||||
radon_image_200 = radon(image, theta=np.linspace(0, 180, nb_angles,
|
||||
endpoint=False))
|
||||
reconstructed = iradon(radon_image_200)
|
||||
delta_200 = np.mean(abs(rescale(image) - rescale(reconstructed)))
|
||||
@@ -60,7 +64,33 @@ def test_iradon_angles():
|
||||
# Loss of quality when the number of projections is reduced
|
||||
assert delta_80 > delta_200
|
||||
|
||||
|
||||
def test_radon_minimal():
|
||||
"""
|
||||
Test for small images for various angles
|
||||
"""
|
||||
thetas = [np.arange(180)]
|
||||
for theta in thetas:
|
||||
a = np.zeros((3, 3))
|
||||
a[1, 1] = 1
|
||||
p = radon(a, theta)
|
||||
reconstructed = iradon(p, theta)
|
||||
reconstructed /= np.max(reconstructed)
|
||||
assert np.all(abs(a - reconstructed) < 0.4)
|
||||
|
||||
b = np.zeros((4, 4))
|
||||
b[1:3, 1:3] = 1
|
||||
p = radon(b, theta)
|
||||
reconstructed = iradon(p, theta)
|
||||
reconstructed /= np.max(reconstructed)
|
||||
assert np.all(abs(b - reconstructed) < 0.4)
|
||||
|
||||
c = np.zeros((5, 5))
|
||||
c[1:3, 1:3] = 1
|
||||
p = radon(c, theta)
|
||||
reconstructed = iradon(p, theta)
|
||||
reconstructed /= np.max(reconstructed)
|
||||
assert np.all(abs(c - reconstructed) < 0.4)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_module_suite()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user