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

This commit is contained in:
François Boulogne
2013-03-19 16:16:49 +01:00
127 changed files with 4290 additions and 2116 deletions
+7
View File
@@ -132,3 +132,10 @@
- François Boulogne
Andres Method for circle perimeter, ellipse perimeter drawing.
Circular Hough Transform
- Thouis Jones
Vectorized operators for arrays of 16-bit ints.
- Xavier Moles Lopez
Color separation (color deconvolution) for several stainings.
+3
View File
@@ -81,6 +81,9 @@ Stylistic Guidelines
hough(canny(my_image))
* Use `Py_ssize_t` as data type for all indexing, shape and size variables in
C/C++ and Cython code.
Test coverage
-------------
+9 -1
View File
@@ -12,7 +12,7 @@ How to make a new release of ``skimage``
- Edit ``doc/source/themes/agogo/static/docversions.js`` and commit
- Build a clean version of the docs. Run ``make`` in the root dir, then
``rm build -rf; make html`` in the docs.
``rm -rf build; make html`` in the docs.
- Run ``make html`` again to copy the newly generated ``random.js`` into
place. Double check ``random.js``, otherwise the skimage.org front
page gets broken!
@@ -49,8 +49,16 @@ How to make a new release of ``skimage``
- Build using ``make gh-pages``.
- Push upstream: ``git push`` in ``gh-pages``.
- Update the development docs for the new version ``0.Xdev`` just like above
- Post release notes on mailing lists, blog, G+, etc.
- scikit-image@googlegroups.com
- scipy-user@scipy.org
- scikit-learn-general@lists.sourceforge.net
- pythonvision@googlegroups.com
Debian
------
+1 -1
View File
@@ -1,5 +1,5 @@
Name: scikit-image
Version: 0.8.dev0
Version: 0.9.dev0
Summary: Image processing routines for SciPy
Url: http://scikit-image.org
DownloadUrl: http://github.com/scikit-image/scikit-image
+1 -1
View File
@@ -90,7 +90,7 @@ devhelp:
@echo "# ln -s build/devhelp $$HOME/.local/share/devhelp/scikitimage"
@echo "# devhelp"
latex:
latex: api
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(DEST)/latex
@echo
@echo "Build finished; the LaTeX files are in $(DEST)/latex."
@@ -90,12 +90,8 @@ plt.title('Filling the holes')
Small spurious objects are easily removed by setting a minimum size for valid
objects.
"""
label_objects, nb_labels = ndimage.label(fill_coins)
sizes = np.bincount(label_objects.ravel())
mask_sizes = sizes > 20
mask_sizes[0] = 0
coins_cleaned = mask_sizes[label_objects]
from skimage import morphology
coins_cleaned = morphology.remove_small_objects(fill_coins, 21)
plt.figure(figsize=(4, 3))
plt.imshow(coins_cleaned, cmap=plt.cm.gray, interpolation='nearest')
@@ -149,8 +145,7 @@ plt.title('markers')
Finally, we use the watershed transform to fill regions of the elevation map starting from the markers determined above:
"""
from skimage.morphology import watershed
segmentation = watershed(elevation_map, markers)
segmentation = morphology.watershed(elevation_map, markers)
plt.figure(figsize=(4, 3))
plt.imshow(segmentation, cmap=plt.cm.gray, interpolation='nearest')
+72
View File
@@ -0,0 +1,72 @@
"""
========================
Circular Hough Transform
========================
The Hough transform in its simplest form is a `method to detect
straight lines <http://en.wikipedia.org/wiki/Hough_transform>`__
but it can also be used to detect circles.
In the following example, the Hough transform is used to detect
coin positions and match their edges. We provide a range of
plausible radii. For each radius, two circles are extracted and
we finally keep the five most prominent candidates.
The result shows that coin positions are well-detected.
Algorithm overview
------------------
Given a black circle on a white background, we first guess its
radius (or a range of radii) to construct a new circle.
This circle is applied on each black pixel of the original picture
and the coordinates of this circle are voting in an accumulator.
From this geometrical construction, the original circle center
position receives the highest score.
Note that the accumulator size is built to be larger than the
original picture in order to detect centers outside the frame.
Its size is extended by two times the larger radius.
"""
import numpy as np
import matplotlib.pyplot as plt
from skimage import data, filter, color
from skimage.transform import hough_circle
from skimage.feature import peak_local_max
from skimage.draw import circle_perimeter
# Load picture and detect edges
image = data.coins()[0:95, 70:370]
edges = filter.canny(image, sigma=3, low_threshold=10, high_threshold=50)
fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(6, 6))
# Detect two radii
hough_radii = np.arange(15, 30, 2)
hough_res = hough_circle(edges, hough_radii)
centers = []
accums = []
radii = []
for radius, h in zip(hough_radii, hough_res):
# For each radius, extract two circles
peaks = peak_local_max(h, num_peaks=2)
centers.extend(peaks - hough_radii.max())
accums.extend(h[peaks[:, 0], peaks[:, 1]])
radii.extend([radius, radius])
# Draw the most prominent 5 circles
image = color.gray2rgb(image)
for idx in np.argsort(accums)[::-1][:5]:
center_x, center_y = centers[idx]
radius = radii[idx]
cx, cy = circle_perimeter(center_y, center_x, radius)
image[cy, cx] = (220, 20, 20)
ax.imshow(image, cmap=plt.cm.gray)
plt.show()
-1
View File
@@ -11,7 +11,6 @@ position of corners.
"""
import numpy as np
from matplotlib import pyplot as plt
from skimage import data
-1
View File
@@ -19,7 +19,6 @@ that fall within the 2nd and 98th percentiles [2]_.
"""
from skimage import data, img_as_float
from skimage.util.dtype import dtype_range
from skimage import exposure
import matplotlib.pyplot as plt
+70
View File
@@ -0,0 +1,70 @@
"""
==============================================
Immunohistochemical staining colors separation
==============================================
In this example we separate the immunohistochemical (IHC) staining
from the hematoxylin counterstaining. The separation is achieved with the
method described in [1]_, known as "color deconvolution".
The IHC staining expression of the FHL2 protein is here revealed with
Diaminobenzidine (DAB) which gives a brown color.
.. [1] A. C. Ruifrok and D. A. Johnston, "Quantification of histochemical
staining by color deconvolution.," Analytical and quantitative
cytology and histology / the International Academy of Cytology [and]
American Society of Cytology, vol. 23, no. 4, pp. 291-9, Aug. 2001.
"""
import matplotlib.pyplot as plt
from skimage import data
from skimage.color import rgb2hed
ihc_rgb = data.immunohistochemistry()
ihc_hed = rgb2hed(ihc_rgb)
fig, axes = plt.subplots(2, 2, figsize=(7, 6))
ax0, ax1, ax2, ax3 = axes.ravel()
ax0.imshow(ihc_rgb)
ax0.set_title("Original image")
ax1.imshow(ihc_hed[:, :, 0], cmap=plt.cm.gray)
ax1.set_title("Hematoxylin")
ax2.imshow(ihc_hed[:, :, 1], cmap=plt.cm.gray)
ax2.set_title("Eosin")
ax3.imshow(ihc_hed[:, :, 2], cmap=plt.cm.gray)
ax3.set_title("DAB")
for ax in axes.ravel():
ax.axis('off')
fig.subplots_adjust(hspace=0.3)
"""
.. image:: PLOT2RST.current_figure
Now we can easily manipulate the hematoxylin and DAB "channels":
"""
import numpy as np
from skimage.exposure import rescale_intensity
# Rescale hematoxylin and DAB signals and give them a fluorescence look
h = rescale_intensity(ihc_hed[:, :, 0], out_range=(0, 1))
d = rescale_intensity(ihc_hed[:, :, 2], out_range=(0, 1))
zdh = np.dstack((np.zeros_like(h), d, h))
plt.figure()
plt.imshow(zdh)
plt.title("Stain separated image (rescaled)")
plt.axis('off')
plt.show()
"""
.. image:: PLOT2RST.current_figure
"""
+9 -9
View File
@@ -12,8 +12,8 @@ each other using the Kullback-Leibler-Divergence.
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import scipy.ndimage as nd
import skimage.feature as ft
from skimage.transform import rotate
from skimage.feature import local_binary_pattern
from skimage import data
@@ -34,7 +34,7 @@ def kullback_leibler_divergence(p, q):
def match(refs, img):
best_score = 10
best_name = None
lbp = ft.local_binary_pattern(img, P, R, METHOD)
lbp = local_binary_pattern(img, P, R, METHOD)
hist, _ = np.histogram(lbp, normed=True, bins=P + 2, range=(0, P + 2))
for name, ref in refs.items():
ref_hist, _ = np.histogram(ref, normed=True, bins=P + 2,
@@ -51,19 +51,19 @@ grass = data.load('grass.png')
wall = data.load('rough-wall.png')
refs = {
'brick': ft.local_binary_pattern(brick, P, R, METHOD),
'grass': ft.local_binary_pattern(grass, P, R, METHOD),
'wall': ft.local_binary_pattern(wall, P, R, METHOD)
'brick': local_binary_pattern(brick, P, R, METHOD),
'grass': local_binary_pattern(grass, P, R, METHOD),
'wall': local_binary_pattern(wall, P, R, METHOD)
}
# classify rotated textures
print 'Rotated images matched against references using LBP:'
print 'original: brick, rotated: 30deg, match result:',
print match(refs, nd.rotate(brick, angle=30, reshape=False))
print match(refs, rotate(brick, angle=30, resize=False))
print 'original: brick, rotated: 70deg, match result:',
print match(refs, nd.rotate(brick, angle=70, reshape=False))
print match(refs, rotate(brick, angle=70, resize=False))
print 'original: grass, rotated: 145deg, match result:',
print match(refs, nd.rotate(grass, angle=145, reshape=False))
print match(refs, rotate(grass, angle=145, resize=False))
# plot histograms of LBP of textures
fig, ((ax1, ax2, ax3), (ax4, ax5, ax6)) = plt.subplots(nrows=2, ncols=3,
+1 -1
View File
@@ -57,7 +57,7 @@ img = data.moon()
# Contrast stretching
p2 = np.percentile(img, 2)
p98 = np.percentile(img, 98)
img_rescale = exposure.equalize(img)
img_rescale = exposure.equalize_hist(img)
# Equalization
selem = disk(30)
+3 -3
View File
@@ -22,11 +22,11 @@ import matplotlib.pyplot as plt
from skimage.io import imread
from skimage import data_dir
from skimage.transform import radon, iradon
from scipy.ndimage import zoom
from skimage.transform import radon, iradon, rescale
image = imread(data_dir + "/phantom.png", as_grey=True)
image = zoom(image, 0.4)
image = rescale(image, scale=0.4)
plt.figure(figsize=(8, 8.5))
@@ -19,7 +19,6 @@ values, and use the random walker for the segmentation.
.. [1] *Random walks for image segmentation*, Leo Grady, IEEE Trans. Pattern
Anal. Mach. Intell. 2006 Nov; 28(11):1768-83
"""
print __doc__
import numpy as np
from scipy import ndimage
+3 -11
View File
@@ -13,23 +13,15 @@ import numpy as np
from skimage.draw import ellipse
from skimage.morphology import label
from skimage.measure import regionprops
from scipy.ndimage import geometric_transform
from skimage.transform import rotate
ANGLE = 0.2
def rotate(xy):
x, y = xy
out_x = math.cos(ANGLE) * x - math.sin(ANGLE) * y
out_y = math.sin(ANGLE) * x + math.cos(ANGLE) * y
return (out_x, out_y)
image = np.zeros((600, 600), 'int')
image = np.zeros((600, 600))
rr, cc = ellipse(300, 350, 100, 220)
image[rr,cc] = 1
image = geometric_transform(image, rotate)
image = rotate(image, angle=15, order=0)
label_img = label(image)
props = regionprops(label_img, [
+11 -1
View File
@@ -69,6 +69,7 @@ import os
import shutil
import token
import tokenize
import traceback
import numpy as np
import matplotlib
@@ -247,7 +248,16 @@ def write_gallery(gallery_index, src_dir, rst_dir, cfg, depth=0):
gallery_index.write(TOCTREE_TEMPLATE % (sub_dir + '\n '.join(ex_names)))
for src_name in examples:
write_example(src_name, src_dir, rst_dir, cfg)
try:
write_example(src_name, src_dir, rst_dir, cfg)
except Exception:
print "Exception raised while running:"
print "%s in %s" % (src_name, src_dir)
print '~' * 60
traceback.print_exc()
print '~' * 60
continue
link_name = sub_dir.pjoin(src_name)
link_name = link_name.replace(os.path.sep, '_')
+75 -135
View File
@@ -1,17 +1,26 @@
"""
Script to draw skimage logo using Scipy logo as stencil. The easiest
starting point is the `plot_colorized_logo`; the "if-main" demonstrates its use.
starting point is the `plot_colorized_logo`.
Original snake image from pixabay [1]_
.. [1] http://pixabay.com/en/snake-green-toxic-close-yellow-3237/
"""
import numpy as np
import sys
if len(sys.argv) != 2 or sys.argv[1] != '--no-plot':
print "Run with '--no-plot' flag to generate logo silently."
else:
import matplotlib as mpl
mpl.use('Agg')
import matplotlib.pyplot as plt
import scipy.misc
import numpy as np
import skimage.io as sio
import skimage.filter as imfilt
from skimage import img_as_float
from skimage.color import gray2rgb, rgb2gray
from skimage.exposure import rescale_intensity
from skimage.filter import sobel
import scipy_logo
@@ -19,42 +28,21 @@ import scipy_logo
# Utility functions
# =================
def get_edges(img):
edge = np.empty(img.shape)
if len(img.shape) == 3:
for i in range(3):
edge[:, :, i] = imfilt.sobel(img[:, :, i])
else:
edge = imfilt.sobel(img)
edge = rescale_intensity(edge)
return edge
def colorize(image, color, whiten=False):
"""Return colorized image from gray scale image.
def rescale_intensity(img):
i_range = float(img.max() - img.min())
img = (img - img.min()) / i_range * 255
return np.uint8(img)
def colorize(img, color, whiten=False):
"""Return colorized image from gray scale image
Parameters
----------
img : N x M array
grayscale image
color : length-3 sequence of floats
RGB color spec. Float values should be between 0 and 1.
whiten : bool
If True, a color value less than 1 increases the image intensity.
The colorized image has values from ranging between black at the lowest
intensity to `color` at the highest. If `whiten=True`, then the color
ranges from `color` to white.
"""
color = np.asarray(color)[np.newaxis, np.newaxis, :]
img = img[:, :, np.newaxis]
image = image[:, :, np.newaxis]
if whiten:
# truncate and stretch intensity range to enhance contrast
img = np.clip(img, 80, 255)
img = rescale_intensity(img)
return np.uint8(color * (255 - img) + img)
image = rescale_intensity(image, in_range=(0.3, 1))
return color * (1 - image) + image
else:
return np.uint8(img * color)
return image * color
def prepare_axes(ax):
@@ -65,16 +53,6 @@ def prepare_axes(ax):
spine.set_visible(False)
_rgb_stack = np.ones((1, 1, 3), dtype=bool)
def gray2rgb(arr):
"""Return RGB image from a grayscale image.
Expand h x w image to h x w x 3 image where color channels are simply copies
of the grayscale image.
"""
return arr[:, :, np.newaxis] * _rgb_stack
# Logo generating classes
# =======================
@@ -82,21 +60,17 @@ class LogoBase(object):
def __init__(self):
self.logo = scipy_logo.ScipyLogo(radius=self.radius)
self.mask_1 = self.logo.get_mask(self.img.shape, 'upper left')
self.mask_2 = self.logo.get_mask(self.img.shape, 'lower right')
self.edges = get_edges(self.img)
self.mask_1 = self.logo.get_mask(self.image.shape, 'upper left')
self.mask_2 = self.logo.get_mask(self.image.shape, 'lower right')
edges = np.array([sobel(img) for img in self.image.T]).T
# truncate and stretch intensity range to enhance contrast
self.edges = np.clip(self.edges, 0, 100)
self.edges = rescale_intensity(self.edges)
self.edges = rescale_intensity(edges, in_range=(0, 0.4))
def _crop_image(self, img):
def _crop_image(self, image):
w = 2 * self.radius
x, y = self.origin
return img[y:y+w, x:x+w]
def get_canvas(self):
return 255 * np.ones(self.img.shape, dtype=np.uint8)
return image[y:y + w, x:x + w]
def plot_curve(self, **kwargs):
self.logo.plot_snake_curve(**kwargs)
@@ -104,15 +78,13 @@ class LogoBase(object):
class SnakeLogo(LogoBase):
def __init__(self):
self.radius = 250
self.origin = (420, 0)
img = sio.imread('data/snake_pixabay.jpg')
img = self._crop_image(img)
radius = 250
origin = (420, 0)
img = img.astype(float) * 1.1
img[img > 255] = 255
self.img = img.astype(np.uint8)
def __init__(self):
image = sio.imread('data/snake_pixabay.jpg')
image = self._crop_image(image)
self.image = img_as_float(image)
LogoBase.__init__(self)
@@ -120,107 +92,75 @@ class SnakeLogo(LogoBase):
snake_color = SnakeLogo()
snake = SnakeLogo()
# turn RGB image into gray image
snake.img = np.mean(snake.img, axis=2)
snake.edges = np.mean(snake.edges, axis=2)
snake.image = rgb2gray(snake.image)
snake.edges = rgb2gray(snake.edges)
# Demo plotting functions
# =======================
def plot_colorized_logo(logo, color, edges='light', switch=False, whiten=False):
"""Convenience function to plot artificially colored logo.
def plot_colorized_logo(logo, color, edges='light', whiten=False):
"""Convenience function to plot artificially-colored logo.
The upper-left half of the logo is an edge filtered image, while the
lower-right half is unfiltered.
Parameters
----------
logo : subclass of LogoBase
color : length-3 sequence of floats
logo : LogoBase instance
color : length-3 sequence of floats or 2 length-3 sequences
RGB color spec. Float values should be between 0 and 1.
edges : {'light'|'dark'}
Specifies whether Sobel edges are drawn light or dark
switch : bool
If False, the image is drawn on the southeast half of the Scipy curve
and the edge image is drawn on northwest half.
whiten : bool
whiten : bool or 2 bools
If True, a color value less than 1 increases the image intensity.
"""
if not hasattr(color[0], '__iter__'):
color = [color] * 2
color = [color] * 2 # use same color for upper-left & lower-right
if not hasattr(whiten, '__iter__'):
whiten = [whiten] * 2
img = gray2rgb(logo.get_canvas())
whiten = [whiten] * 2 # use same setting for upper-left & lower-right
image = gray2rgb(np.ones_like(logo.image))
mask_img = gray2rgb(logo.mask_2)
mask_edge = gray2rgb(logo.mask_1)
if switch:
mask_img, mask_edge = mask_edge, mask_img
# Compose image with colorized image and edge-image.
if edges == 'dark':
lg_edge = colorize(255 - logo.edges, color[0], whiten=whiten[0])
logo_edge = colorize(1 - logo.edges, color[0], whiten=whiten[0])
else:
lg_edge = colorize(logo.edges, color[0], whiten=whiten[0])
lg_img = colorize(logo.img, color[1], whiten=whiten[1])
img[mask_img] = lg_img[mask_img]
img[mask_edge] = lg_edge[mask_edge]
logo.plot_curve(lw=5, color='w')
plt.imshow(img)
logo_edge = colorize(logo.edges, color[0], whiten=whiten[0])
logo_img = colorize(logo.image, color[1], whiten=whiten[1])
image[mask_img] = logo_img[mask_img]
image[mask_edge] = logo_edge[mask_edge]
def red_light_edges(logo, **kwargs):
plot_colorized_logo(logo, (1, 0, 0), edges='light', **kwargs)
def red_dark_edges(logo, **kwargs):
plot_colorized_logo(logo, (1, 0, 0), edges='dark', **kwargs)
def blue_light_edges(logo, **kwargs):
plot_colorized_logo(logo, (0.35, 0.55, 0.85), edges='light', **kwargs)
def blue_dark_edges(logo, **kwargs):
plot_colorized_logo(logo, (0.35, 0.55, 0.85), edges='dark', **kwargs)
def green_orange_light_edges(logo, **kwargs):
colors = ((0.6, 0.8, 0.3), (1, 0.5, 0.1))
plot_colorized_logo(logo, colors, edges='light', **kwargs)
def green_orange_dark_edges(logo, **kwargs):
colors = ((0.6, 0.8, 0.3), (1, 0.5, 0.1))
plot_colorized_logo(logo, colors, edges='dark', **kwargs)
logo.plot_curve(lw=5, color='w') # plot snake curve on current axes
plt.imshow(image)
if __name__ == '__main__':
import sys
plot = False
if len(sys.argv) < 2 or sys.argv[1] != '--no-plot':
plot = True
print "Run with '--no-plot' flag to generate logo silently."
# Colors to use for the logo:
red = (1, 0, 0)
blue = (0.35, 0.55, 0.85)
green_orange = ((0.6, 0.8, 0.3), (1, 0.5, 0.1))
def plot_all():
plotters = (red_light_edges, red_dark_edges,
blue_light_edges, blue_dark_edges,
green_orange_light_edges, green_orange_dark_edges)
f, axes_array = plt.subplots(nrows=2, ncols=len(plotters))
for plot, ax_col in zip(plotters, axes_array.T):
prepare_axes(ax_col[0])
plot(snake)
prepare_axes(ax_col[1])
plot(snake, whiten=True)
color_list = [red, blue, green_orange]
edge_list = ['light', 'dark']
f, axes = plt.subplots(nrows=len(edge_list), ncols=len(color_list))
for axes_row, edges in zip(axes, edge_list):
for ax, color in zip(axes_row, color_list):
prepare_axes(ax)
plot_colorized_logo(snake, color, edges=edges)
plt.tight_layout()
def plot_snake():
def plot_official_logo():
f, ax = plt.subplots()
prepare_axes(ax)
green_orange_dark_edges(snake, whiten=(False, True))
plot_colorized_logo(snake, green_orange, edges='dark',
whiten=(False, True))
plt.savefig('green_orange_snake.png', bbox_inches='tight')
if plot:
plot_all()
plot_snake()
if plot:
plt.show()
plot_all()
plot_official_logo()
plt.show()
+6 -10
View File
@@ -3,10 +3,11 @@ Code used to trace Scipy logo.
"""
import numpy as np
import matplotlib.pyplot as plt
import skimage.io as imgio
from scipy.misc import lena
import matplotlib.nxutils as nx
from skimage import io
from skimage import data
class SymmetricAnchorPoint(object):
"""Anchor point in a parametric curve with symmetric handles
@@ -185,7 +186,7 @@ class ScipyLogo(object):
def plot_image(self, **kwargs):
ax = kwargs.pop('ax', plt.gca())
img = imgio.imread('data/scipy.png')
img = io.imread('data/scipy.png')
ax.imshow(img, **kwargs)
def get_mask(self, shape, region):
@@ -236,9 +237,7 @@ def plot_snake_overlay():
logo = ScipyLogo((670, 250), 250)
logo.plot_snake_curve()
logo.plot_circle()
img = imgio.imread('data/snake_pixabay.jpg')
#mask = logo.get_mask(img.shape, 'upper left')
#img[mask] = 255
img = io.imread('data/snake_pixabay.jpg')
plt.imshow(img)
@@ -247,9 +246,7 @@ def plot_lena_overlay():
logo = ScipyLogo((300, 300), 180)
logo.plot_snake_curve()
logo.plot_circle()
img = lena()
#mask = logo.get_mask(img.shape, 'upper left')
#img[mask] = 255
img = data.lena()
plt.imshow(img)
@@ -259,4 +256,3 @@ if __name__ == '__main__':
plot_lena_overlay()
plt.show()
+9
View File
@@ -27,6 +27,14 @@ if "%1" == "help" (
goto end
)
for %%x in (html htmlhelp latex qthelp) do (
if "%1" == "%%x" (
md source\api 2>NUL
python tools/build_modref_templates.py
)
)
if "%1" == "clean" (
for /d %%i in (build\*) do rmdir /q /s %%i
del /q /s build\*
@@ -34,6 +42,7 @@ if "%1" == "clean" (
)
if "%1" == "html" (
cd source && python random_gallery.py && python coverage_generator.py && cd ..
%SPHINXBUILD% -b html %ALLSPHINXOPTS% build/html
echo.
echo.Build finished. The HTML pages are in build/html.
+71
View File
@@ -0,0 +1,71 @@
Announcement: scikits-image 0.8.0
=================================
We're happy to announce the 8th version of scikit-image!
scikit-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.
For more information, examples, and documentation, please visit our website:
http://scikit-image.org
New Features
------------
- New rank filter package with many new functions and a very fast underlying
local histogram algorithm, especially for large structuring elements
`skimage.filter.rank.*`
- New function for small object removal
`skimage.morphology.remove_small_objects`
- New circular hough transformation `skimage.transform.hough_circle`
- New function to draw circle perimeter `skimage.draw.circle_perimeter` and
ellipse perimeter `skimage.draw.ellipse_perimeter`
- New dense DAISY feature descriptor `skimage.feature.daisy`
- New bilateral filter `skimage.filter.denoise_bilateral`
- New faster TV denoising filter based on split-Bregman algorithm
`skimage.filter.denoise_tv_bregman`
- New linear hough peak detection `skimage.transform.hough_peaks`
- New Scharr edge detection `skimage.filter.scharr`
- New geometric image scaling as convenience function
`skimage.transform.rescale`
- New theme for documentation and website
- Faster median filter through vectorization `skimage.filter.median_filter`
- Grayscale images supported for SLIC segmentation
- Unified peak detection with more options `skimage.feature.peak_local_max`
- `imread` can read images via URL and knows more formats `skimage.io.imread`
Additionally, this release adds lots of bug fixes, new examples, and
performance enhancements.
Contributors to this release
----------------------------
This release was only possible due to the efforts of many contributors, both
new and old.
- Adam Ginsburg
- Anders Boesen Lindbo Larsen
- Andreas Mueller
- Christoph Gohlke
- Christos Psaltis
- Colin Lea
- François Boulogne
- Jan Margeta
- Johannes Schönberger
- Josh Warner (Mac)
- Juan Nunez-Iglesias
- Luis Pedro Coelho
- Marianne Corvellec
- Matt McCormick
- Nicolas Pinto
- Olivier Debeir
- Paul Ivanov
- Sergey Karayev
- Stefan van der Walt
- Steven Silvester
- Thouis (Ray) Jones
- Tony S Yu
+1 -1
View File
@@ -1,5 +1,5 @@
function insert_version_links() {
var labels = ['dev', '0.7.0', '0.6', '0.5', '0.4', '0.3'];
var labels = ['dev', '0.8.0', '0.7.0', '0.6', '0.5', '0.4', '0.3'];
for (i = 0; i < labels.length; i++){
open_list = '<li>'
+45 -9
View File
@@ -26,9 +26,26 @@ sys.path.append(os.path.join(curpath, '..', 'ext'))
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.pngmath', 'numpydoc',
'sphinx.ext.autosummary', 'plot_directive', 'plot2rst',
'sphinx.ext.autosummary', 'plot2rst',
'sphinx.ext.intersphinx']
# Determine if the matplotlib has a recent enough version of the
# plot_directive, otherwise use the local fork.
try:
from matplotlib.sphinxext import plot_directive
except ImportError:
use_matplotlib_plot_directive = False
else:
try:
use_matplotlib_plot_directive = (plot_directive.__version__ >= 2)
except AttributeError:
use_matplotlib_plot_directive = False
if use_matplotlib_plot_directive:
extensions.append('matplotlib.sphinxext.plot_directive')
else:
extensions.append('plot_directive')
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ -42,8 +59,8 @@ source_suffix = '.txt'
master_doc = 'index'
# General information about the project.
project = u'skimage'
copyright = u'2011, the scikit-image team'
project = 'skimage'
copyright = '2013, the scikit-image team'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -185,13 +202,13 @@ htmlhelp_basename = 'scikitimagedoc'
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('contents', 'scikitimage.tex', u'The Image Scikit Documentation',
u'SciPy Developers', 'manual'),
('contents', 'scikit-image.tex', u'The scikit-image Documentation',
u'scikit-image development team', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
@@ -203,13 +220,32 @@ latex_documents = [
#latex_use_parts = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
latex_preamble = r'''
\usepackage{enumitem}
\setlistdepth{100}
\usepackage{amsmath}
\DeclareUnicodeCharacter{00A0}{\nobreakspace}
% In the parameters section, place a newline after the Parameters header
\usepackage{expdlist}
\let\latexdescription=\description
\def\description{\latexdescription{}{} \breaklabel}
% Make Examples/etc section headers smaller and more compact
\makeatletter
\titleformat{\paragraph}{\normalsize\py@HeaderFamily}%
{\py@TitleColor}{0em}{\py@TitleColor}{\py@NormalColor}
\titlespacing*{\paragraph}{0pt}{1ex}{0pt}
\makeatother
'''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True
latex_use_modindex = False
# -----------------------------------------------------------------------------
# Numpy extensions
@@ -243,7 +279,7 @@ matplotlib.rcParams.update({
"""
plot_include_source = True
plot_formats = [('png', 100)]
plot_formats = [('png', 100), ('pdf', 100)]
plot2rst_index_name = 'README'
plot2rst_rcparams = {'image.cmap' : 'gray',
+1 -1
View File
@@ -17,7 +17,7 @@ MAINTAINER_EMAIL = 'stefan@sun.ac.za'
URL = 'http://scikit-image.org'
LICENSE = 'Modified BSD'
DOWNLOAD_URL = 'http://github.com/scikit-image/scikit-image'
VERSION = '0.8dev'
VERSION = '0.9dev'
PYTHON_VERSION = (2, 5)
DEPENDENCIES = {
'numpy': (1, 6),
+3 -3
View File
@@ -1,6 +1,6 @@
cdef unsigned char point_in_polygon(int nr_verts, double *xp, double *yp,
cdef unsigned char point_in_polygon(Py_ssize_t nr_verts, double *xp, double *yp,
double x, double y)
cdef void points_in_polygon(int nr_verts, double *xp, double *yp,
int nr_points, double *x, double *y,
cdef void points_in_polygon(Py_ssize_t nr_verts, double *xp, double *yp,
Py_ssize_t nr_points, double *x, double *y,
unsigned char *result)
+7 -7
View File
@@ -4,8 +4,8 @@
#cython: wraparound=False
cdef inline unsigned char point_in_polygon(int nr_verts, double *xp, double *yp,
double x, double y):
cdef inline unsigned char point_in_polygon(Py_ssize_t nr_verts, double *xp,
double *yp, double x, double y):
"""Test whether point lies inside a polygon.
Parameters
@@ -17,9 +17,9 @@ cdef inline unsigned char point_in_polygon(int nr_verts, double *xp, double *yp,
x, y : double
Coordinates of point.
"""
cdef int i
cdef Py_ssize_t i
cdef unsigned char c = 0
cdef int j = nr_verts - 1
cdef Py_ssize_t j = nr_verts - 1
for i in range(nr_verts):
if (
(((yp[i] <= y) and (y < yp[j])) or
@@ -31,8 +31,8 @@ cdef inline unsigned char point_in_polygon(int nr_verts, double *xp, double *yp,
return c
cdef void points_in_polygon(int nr_verts, double *xp, double *yp,
int nr_points, double *x, double *y,
cdef void points_in_polygon(Py_ssize_t nr_verts, double *xp, double *yp,
Py_ssize_t nr_points, double *x, double *y,
unsigned char *result):
"""Test whether points lie inside a polygon.
@@ -49,6 +49,6 @@ cdef void points_in_polygon(int nr_verts, double *xp, double *yp,
result : unsigned char array
Test results for each point.
"""
cdef int n
cdef Py_ssize_t n
for n in range(nr_points):
result[n] = point_in_polygon(nr_verts, xp, yp, x[n], y[n])
+10 -10
View File
@@ -1,27 +1,27 @@
cdef double nearest_neighbour_interpolation(double* image, int rows,
int cols, double r,
cdef double nearest_neighbour_interpolation(double* image, Py_ssize_t rows,
Py_ssize_t cols, double r,
double c, char mode,
double cval)
cdef double bilinear_interpolation(double* image, int rows, int cols,
cdef double bilinear_interpolation(double* image, Py_ssize_t rows, Py_ssize_t cols,
double r, double c, char mode,
double cval)
cdef double quadratic_interpolation(double x, double[3] f)
cdef double biquadratic_interpolation(double* image, int rows, int cols,
cdef double biquadratic_interpolation(double* image, Py_ssize_t rows, Py_ssize_t cols,
double r, double c, char mode,
double cval)
cdef double cubic_interpolation(double x, double[4] f)
cdef double bicubic_interpolation(double* image, int rows, int cols,
cdef double bicubic_interpolation(double* image, Py_ssize_t rows, Py_ssize_t cols,
double r, double 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_pixel2d(double* image, Py_ssize_t rows, Py_ssize_t cols, Py_ssize_t r,
Py_ssize_t 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 double get_pixel3d(double* image, Py_ssize_t rows, Py_ssize_t cols, Py_ssize_t dims,
Py_ssize_t r, Py_ssize_t c, Py_ssize_t d, char mode, double cval)
cdef int coord_map(int dim, int coord, char mode)
cdef Py_ssize_t coord_map(Py_ssize_t dim, Py_ssize_t coord, char mode)
+39 -39
View File
@@ -5,12 +5,12 @@
from libc.math cimport ceil, floor
cdef inline int round(double r):
return <int>((r + 0.5) if (r > 0.0) else (r - 0.5))
cdef inline Py_ssize_t round(double r):
return <Py_ssize_t>((r + 0.5) if (r > 0.0) else (r - 0.5))
cdef inline double nearest_neighbour_interpolation(double* image, int rows,
int cols, double r,
cdef inline double nearest_neighbour_interpolation(double* image, Py_ssize_t rows,
Py_ssize_t cols, double r,
double c, char mode,
double cval):
"""Nearest neighbour interpolation at a given position in the image.
@@ -35,13 +35,12 @@ cdef inline double nearest_neighbour_interpolation(double* image, int rows,
"""
return get_pixel2d(image, rows, cols, <int>round(r), <int>round(c),
mode, cval)
return get_pixel2d(image, rows, cols, round(r), round(c), mode, cval)
cdef inline double bilinear_interpolation(double* image, int rows, int cols,
double r, double c, char mode,
double cval):
cdef inline double bilinear_interpolation(double* image, Py_ssize_t rows,
Py_ssize_t cols, double r, double c,
char mode, double cval):
"""Bilinear interpolation at a given position in the image.
Parameters
@@ -64,12 +63,12 @@ cdef inline double bilinear_interpolation(double* image, int rows, int cols,
"""
cdef double dr, dc
cdef int minr, minc, maxr, maxc
cdef Py_ssize_t minr, minc, maxr, maxc
minr = <int>floor(r)
minc = <int>floor(c)
maxr = <int>ceil(r)
maxc = <int>ceil(c)
minr = <Py_ssize_t>floor(r)
minc = <Py_ssize_t>floor(c)
maxr = <Py_ssize_t>ceil(r)
maxc = <Py_ssize_t>ceil(c)
dr = r - minr
dc = c - minc
top = (1 - dc) * get_pixel2d(image, rows, cols, minr, minc, mode, cval) \
@@ -98,9 +97,9 @@ cdef inline double quadratic_interpolation(double x, double[3] f):
return f[1] - 0.25 * (f[0] - f[2]) * x
cdef inline double biquadratic_interpolation(double* image, int rows, int cols,
double r, double c, char mode,
double cval):
cdef inline double biquadratic_interpolation(double* image, Py_ssize_t rows,
Py_ssize_t cols, double r, double c,
char mode, double cval):
"""Biquadratic interpolation at a given position in the image.
Parameters
@@ -123,8 +122,8 @@ cdef inline double biquadratic_interpolation(double* image, int rows, int cols,
"""
cdef int r0 = <int>round(r)
cdef int c0 = <int>round(c)
cdef Py_ssize_t r0 = round(r)
cdef Py_ssize_t c0 = round(c)
if r < 0:
r0 -= 1
if c < 0:
@@ -139,7 +138,7 @@ cdef inline double biquadratic_interpolation(double* image, int rows, int cols,
cdef double fc[3], fr[3]
cdef int pr, pc
cdef Py_ssize_t pr, pc
# row-wise cubic interpolation
for pr in range(r0, r0 + 3):
@@ -174,9 +173,9 @@ cdef inline double cubic_interpolation(double x, double[4] f):
(3.0 * (f[1] - f[2]) + f[3] - f[0])))
cdef inline double bicubic_interpolation(double* image, int rows, int cols,
double r, double c, char mode,
double cval):
cdef inline double bicubic_interpolation(double* image, Py_ssize_t rows,
Py_ssize_t cols, double r, double c,
char mode, double cval):
"""Bicubic interpolation at a given position in the image.
Parameters
@@ -199,8 +198,8 @@ cdef inline double bicubic_interpolation(double* image, int rows, int cols,
"""
cdef int r0 = <int>r - 1
cdef int c0 = <int>c - 1
cdef Py_ssize_t r0 = <Py_ssize_t>r - 1
cdef Py_ssize_t c0 = <Py_ssize_t>c - 1
if r < 0:
r0 -= 1
if c < 0:
@@ -211,7 +210,7 @@ cdef inline double bicubic_interpolation(double* image, int rows, int cols,
cdef double fc[4], fr[4]
cdef int pr, pc
cdef Py_ssize_t pr, pc
# row-wise cubic interpolation
for pr in range(r0, r0 + 4):
@@ -223,8 +222,8 @@ cdef inline double bicubic_interpolation(double* image, int rows, int cols,
return cubic_interpolation(xr, fr)
cdef inline double get_pixel2d(double* image, int rows, int cols, int r, int c,
char mode, double cval):
cdef inline double get_pixel2d(double* image, Py_ssize_t rows, Py_ssize_t cols,
Py_ssize_t r, Py_ssize_t c, char mode, double cval):
"""Get a pixel from the image, taking wrapping mode into consideration.
Parameters
@@ -255,8 +254,9 @@ cdef inline double get_pixel2d(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):
cdef inline double get_pixel3d(double* image, Py_ssize_t rows, Py_ssize_t cols,
Py_ssize_t dims, Py_ssize_t r, Py_ssize_t c, Py_ssize_t d,
char mode, double cval):
"""Get a pixel from the image, taking wrapping mode into consideration.
Parameters
@@ -289,7 +289,7 @@ cdef inline double get_pixel3d(double* image, int rows, int cols, int dims, int
+ d]
cdef inline int coord_map(int dim, int coord, char mode):
cdef inline Py_ssize_t coord_map(Py_ssize_t dim, Py_ssize_t coord, char mode):
"""
Wrap a coordinate, according to a given mode.
@@ -308,20 +308,20 @@ cdef inline int coord_map(int dim, int coord, char mode):
if mode == 'R': # reflect
if coord < 0:
# How many times times does the coordinate wrap?
if <int>(-coord / dim) % 2 != 0:
return dim - <int>(-coord % dim)
if <Py_ssize_t>(-coord / dim) % 2 != 0:
return dim - <Py_ssize_t>(-coord % dim)
else:
return <int>(-coord % dim)
return <Py_ssize_t>(-coord % dim)
elif coord > dim:
if <int>(coord / dim) % 2 != 0:
return <int>(dim - (coord % dim))
if <Py_ssize_t>(coord / dim) % 2 != 0:
return <Py_ssize_t>(dim - (coord % dim))
else:
return <int>(coord % dim)
return <Py_ssize_t>(coord % dim)
elif mode == 'W': # wrap
if coord < 0:
return <int>(dim - (-coord % dim))
return <Py_ssize_t>(dim - (-coord % dim))
elif coord > dim:
return <int>(coord % dim)
return <Py_ssize_t>(coord % dim)
elif mode == 'N': # nearest
if coord < 0:
return 0
+1 -1
View File
@@ -2,4 +2,4 @@ cimport numpy as cnp
cdef float integrate(cnp.ndarray[float, ndim=2, mode="c"] sat,
int r0, int c0, int r1, int c1)
Py_ssize_t r0, Py_ssize_t c0, Py_ssize_t r1, Py_ssize_t c1)
+1 -1
View File
@@ -6,7 +6,7 @@ cimport numpy as cnp
cdef float integrate(cnp.ndarray[float, ndim=2, mode="c"] sat,
int r0, int c0, int r1, int c1):
Py_ssize_t r0, Py_ssize_t c0, Py_ssize_t r1, Py_ssize_t c1):
"""
Using a summed area table / integral image, calculate the sum
over a given window.
+12 -2
View File
@@ -25,9 +25,12 @@ class deprecated(object):
def __call__(self, func):
msg = "Call to deprecated function `%s`." % func.__name__
alt_msg = ''
if self.alt_func is not None:
msg = msg + " Use `%s` instead." % self.alt_func
alt_msg = ' Use `%s` instead.' % self.alt_func
msg = 'Call to deprecated function `%s`.' % func.__name__
msg += alt_msg
@functools.wraps(func)
def wrapped(*args, **kwargs):
@@ -40,4 +43,11 @@ class deprecated(object):
raise DeprecationWarning(msg)
return func(*args, **kwargs)
# modify doc string to display deprecation warning
doc = '**Deprecated function**.' + alt_msg
if wrapped.__doc__ is None:
wrapped.__doc__ = doc
else:
wrapped.__doc__ = doc + '\n\n' + wrapped.__doc__
return wrapped
+110
View File
@@ -0,0 +1,110 @@
/* Intrinsic declarations */
#if defined(__SSE2__)
#include <emmintrin.h>
#elif defined(__MMX__)
#include <mmintrin.h>
#elif defined(__ALTIVEC__)
#include <altivec.h>
#endif
/* Compiler peculiarities */
#if defined(__GNUC__)
#include <stdint.h>
#elif defined(_MSC_VER)
#define inline __inline
typedef unsigned __int16 uint16_t;
#endif
/**
* Add 16 unsigned 16-bit integers using SSE2, MMX or Altivec, if
* available.
*/
#if defined(__SSE2__)
static inline void add16(uint16_t *dest, uint16_t *src)
{
__m128i *d, *s;
d = (__m128i *) dest;
s = (__m128i *) src;
*d = _mm_add_epi16(*d, *s);
d++; s++;
*d = _mm_add_epi16(*d, *s);
}
#elif defined(__MMX__)
static inline void add16(uint16_t *dest, uint16_t *src)
{
__m64 *d, *s;
d = (__m64 *) dest;
s = (__m64 *) src;
*d = _mm_add_pi16(*d, *s);
d++; s++;
*d = _mm_add_pi16(*d, *s);
d++; s++;
*d = _mm_add_pi16(*d, *s);
d++; s++;
*d = _mm_add_pi16(*d, *s);
}
#elif defined(__ALTIVEC__)
static inline void add16(uint16_t *dest, uint16_t *src)
{
vector unsigned short *d, *s;
d = (vector unsigned short *) dest;
s = (vector unsigned short *) src;
*d = vec_add(*d, *s);
d++; s++;
*d = vec_add(*d, *s);
}
#else
static inline void add16(uint16_t *dest, uint16_t *src)
{
int i;
for (i = 0; i < 16; i++) dest[i] += src[i];
}
#endif
/**
* Subtract 16 unsigned 16-bit integers using SSE2, MMX or Altivec, if
* available.
*/
#if defined(__SSE2__)
static inline void sub16(uint16_t *dest, uint16_t *src)
{
__m128i *d, *s;
d = (__m128i *) dest;
s = (__m128i *) src;
*d = _mm_sub_epi16(*d, *s);
d++; s++;
*d = _mm_sub_epi16(*d, *s);
}
#elif defined(__MMX__)
static inline void sub16(uint16_t *dest, uint16_t *src)
{
__m64 *d, *s;
d = (__m64 *) dest;
s = (__m64 *) src;
*d = _mm_sub_pi16(*d, *s);
d++; s++;
*d = _mm_sub_pi16(*d, *s);
d++; s++;
*d = _mm_sub_pi16(*d, *s);
d++; s++;
*d = _mm_sub_pi16(*d, *s);
}
#elif defined(__ALTIVEC__)
static inline void sub16(uint16_t *dest, uint16_t *src)
{
vector unsigned short *d, *s;
d = (vector unsigned short *) dest;
s = (vector unsigned short *) src;
*d = vec_sub(*d, *s);
d++; s++;
*d = vec_sub(*d, *s);
}
#else
static inline void sub16(uint16_t *dest, uint16_t *src)
{
int i;
for (i = 0; i < 16; i++) dest[i] -= src[i];
}
#endif
+278 -1
View File
@@ -45,7 +45,14 @@ from __future__ import division
__all__ = ['convert_colorspace', 'rgb2hsv', 'hsv2rgb', 'rgb2xyz', 'xyz2rgb',
'rgb2rgbcie', 'rgbcie2rgb', 'rgb2grey', 'rgb2gray', 'gray2rgb',
'xyz2lab', 'lab2xyz', 'lab2rgb', 'rgb2lab', 'is_rgb', 'is_gray'
'xyz2lab', 'lab2xyz', 'lab2rgb', 'rgb2lab', 'rgb2hed', 'hed2rgb',
'separate_stains', 'combine_stains', 'rgb_from_hed', 'hed_from_rgb',
'rgb_from_hdx', 'hdx_from_rgb', 'rgb_from_fgx', 'fgx_from_rgb',
'rgb_from_bex', 'bex_from_rgb', 'rgb_from_rbd', 'rbd_from_rgb',
'rgb_from_gdx', 'gdx_from_rgb', 'rgb_from_hax', 'hax_from_rgb',
'rgb_from_bro', 'bro_from_rgb', 'rgb_from_bpx', 'bpx_from_rgb',
'rgb_from_ahx', 'ahx_from_rgb', 'rgb_from_hpx', 'hpx_from_rgb',
'is_rgb', 'is_gray'
]
__docformat__ = "restructuredtext en"
@@ -312,6 +319,90 @@ gray_from_rgb = np.array([[0.2125, 0.7154, 0.0721],
# CIE LAB constants for Observer= 2A, Illuminant= D65
lab_ref_white = np.array([0.95047, 1., 1.08883])
# Haematoxylin-Eosin-DAB colorspace
# From original Ruifrok's paper: A. C. Ruifrok and D. A. Johnston,
# "Quantification of histochemical staining by color deconvolution.,"
# Analytical and quantitative cytology and histology / the International
# Academy of Cytology [and] American Society of Cytology, vol. 23, no. 4,
# pp. 291-9, Aug. 2001.
rgb_from_hed = np.array([[0.65, 0.70, 0.29],
[0.07, 0.99, 0.11],
[0.27, 0.57, 0.78]])
hed_from_rgb = linalg.inv(rgb_from_hed)
# Following matrices are adapted form the Java code written by G.Landini.
# The original code is available at:
# http://www.dentistry.bham.ac.uk/landinig/software/cdeconv/cdeconv.html
# Hematoxylin + DAB
rgb_from_hdx = np.array([[0.650, 0.704, 0.286],
[0.268, 0.570, 0.776],
[0.0, 0.0, 0.0]])
rgb_from_hdx[2, :] = np.cross(rgb_from_hdx[0, :], rgb_from_hdx[1, :])
hdx_from_rgb = linalg.inv(rgb_from_hdx)
# Feulgen + Light Green
rgb_from_fgx = np.array([[0.46420921, 0.83008335, 0.30827187],
[0.94705542, 0.25373821, 0.19650764],
[0.0, 0.0, 0.0]])
rgb_from_fgx[2, :] = np.cross(rgb_from_fgx[0, :], rgb_from_fgx[1, :])
fgx_from_rgb = linalg.inv(rgb_from_fgx)
# Giemsa: Methyl Blue + Eosin
rgb_from_bex = np.array([[0.834750233, 0.513556283, 0.196330403],
[0.092789, 0.954111, 0.283111],
[0.0, 0.0, 0.0]])
rgb_from_bex[2, :] = np.cross(rgb_from_bex[0, :], rgb_from_bex[1, :])
bex_from_rgb = linalg.inv(rgb_from_bex)
# FastRed + FastBlue + DAB
rgb_from_rbd = np.array([[0.21393921, 0.85112669, 0.47794022],
[0.74890292, 0.60624161, 0.26731082],
[0.268, 0.570, 0.776]])
rbd_from_rgb = linalg.inv(rgb_from_rbd)
# Methyl Green + DAB
rgb_from_gdx = np.array([[0.98003, 0.144316, 0.133146],
[0.268, 0.570, 0.776],
[0.0, 0.0, 0.0]])
rgb_from_gdx[2, :] = np.cross(rgb_from_gdx[0, :], rgb_from_gdx[1, :])
gdx_from_rgb = linalg.inv(rgb_from_gdx)
# Hematoxylin + AEC
rgb_from_hax = np.array([[0.650, 0.704, 0.286],
[0.2743, 0.6796, 0.6803],
[0.0, 0.0, 0.0]])
rgb_from_hax[2, :] = np.cross(rgb_from_hax[0, :], rgb_from_hax[1, :])
hax_from_rgb = linalg.inv(rgb_from_hax)
# Blue matrix Anilline Blue + Red matrix Azocarmine + Orange matrix Orange-G
rgb_from_bro = np.array([[0.853033, 0.508733, 0.112656],
[0.09289875, 0.8662008, 0.49098468],
[0.10732849, 0.36765403, 0.9237484]])
bro_from_rgb = linalg.inv(rgb_from_bro)
# Methyl Blue + Ponceau Fuchsin
rgb_from_bpx = np.array([[0.7995107, 0.5913521, 0.10528667],
[0.09997159, 0.73738605, 0.6680326],
[0.0, 0.0, 0.0]])
rgb_from_bpx[2, :] = np.cross(rgb_from_bpx[0, :], rgb_from_bpx[1, :])
bpx_from_rgb = linalg.inv(rgb_from_bpx)
# Alcian Blue + Hematoxylin
rgb_from_ahx = np.array([[0.874622, 0.457711, 0.158256],
[0.552556, 0.7544, 0.353744],
[0.0, 0.0, 0.0]])
rgb_from_ahx[2, :] = np.cross(rgb_from_ahx[0, :], rgb_from_ahx[1, :])
ahx_from_rgb = linalg.inv(rgb_from_ahx)
# Hematoxylin + PAS
rgb_from_hpx = np.array([[0.644211, 0.716556, 0.266844],
[0.175411, 0.972178, 0.154589],
[0.0, 0.0, 0.0]])
rgb_from_hpx[2, :] = np.cross(rgb_from_hpx[0, :], rgb_from_hpx[1, :])
hpx_from_rgb = linalg.inv(rgb_from_hpx)
#-------------------------------------------------------------
# The conversion functions that make use of the matrices above
#-------------------------------------------------------------
@@ -721,3 +812,189 @@ def lab2rgb(lab):
This function uses lab2xyz and xyz2rgb.
"""
return xyz2rgb(lab2xyz(lab))
def rgb2hed(rgb):
"""RGB to Haematoxylin-Eosin-DAB (HED) color space conversion.
Parameters
----------
rgb : array_like
The image in RGB format, in a 3-D array of shape (.., .., 3).
Returns
-------
out : ndarray
The image in HED format, in a 3-D array of shape (.., .., 3).
Raises
------
ValueError
If `rgb` is not a 3-D array of shape (.., .., 3).
References
----------
.. [1] A. C. Ruifrok and D. A. Johnston, "Quantification of histochemical
staining by color deconvolution.," Analytical and quantitative
cytology and histology / the International Academy of Cytology [and]
American Society of Cytology, vol. 23, no. 4, pp. 291-9, Aug. 2001.
Examples
--------
>>> from skimage import data
>>> from skimage.color import rgb2hed
>>> ihc = data.immunohistochemistry()
>>> ihc_hed = rgb2hed(ihc)
"""
return separate_stains(rgb, hed_from_rgb)
def hed2rgb(hed):
"""Haematoxylin-Eosin-DAB (HED) to RGB color space conversion.
Parameters
----------
hed : array_like
The image in the HED color space, in a 3-D array of shape (.., .., 3).
Returns
-------
out : ndarray
The image in RGB, in a 3-D array of shape (.., .., 3).
Raises
------
ValueError
If `hed` is not a 3-D array of shape (.., .., 3).
References
----------
.. [1] A. C. Ruifrok and D. A. Johnston, "Quantification of histochemical
staining by color deconvolution.," Analytical and quantitative
cytology and histology / the International Academy of Cytology [and]
American Society of Cytology, vol. 23, no. 4, pp. 291-9, Aug. 2001.
Examples
--------
>>> from skimage import data
>>> from skimage.color import rgb2hed, hed2rgb
>>> ihc = data.immunohistochemistry()
>>> ihc_hed = rgb2hed(ihc)
>>> ihc_rgb = hed2rgb(ihc_hed)
"""
return combine_stains(hed, rgb_from_hed)
def separate_stains(rgb, conv_matrix):
"""RGB to stain color space conversion.
Parameters
----------
rgb : array_like
The image in RGB format, in a 3-D array of shape (.., .., 3).
conv_matrix: ndarray
The stain separation matrix as described by G. Landini [1]_.
Returns
-------
out : ndarray
The image in stain color space, in a 3-D array of shape (.., .., 3).
Raises
------
ValueError
If `rgb` is not a 3-D array of shape (.., .., 3).
Notes
-----
Stain separation matrices available in the ``color`` module and their
respective colorspace:
* ``hed_from_rgb``: Hematoxylin + Eosin + DAB
* ``hdx_from_rgb``: Hematoxylin + DAB
* ``fgx_from_rgb``: Feulgen + Light Green
* ``bex_from_rgb``: Giemsa stain : Methyl Blue + Eosin
* ``rbd_from_rgb``: FastRed + FastBlue + DAB
* ``gdx_from_rgb``: Methyl Green + DAB
* ``hax_from_rgb``: Hematoxylin + AEC
* ``bro_from_rgb``: Blue matrix Anilline Blue + Red matrix Azocarmine\
+ Orange matrix Orange-G
* ``bpx_from_rgb``: Methyl Blue + Ponceau Fuchsin
* ``ahx_from_rgb``: Alcian Blue + Hematoxylin
* ``hpx_from_rgb``: Hematoxylin + PAS
References
----------
.. [1] http://www.dentistry.bham.ac.uk/landinig/software/cdeconv/cdeconv.html
Examples
--------
>>> from skimage import data
>>> from skimage.color import separate_stains, hdx_from_rgb
>>> ihc = data.immunohistochemistry()
>>> ihc_hdx = separate_stains(ihc, hdx_from_rgb)
"""
rgb = dtype.img_as_float(rgb) + 2
stains = np.dot(np.reshape(-np.log(rgb), (-1, 3)), conv_matrix)
return np.reshape(stains, rgb.shape)
def combine_stains(stains, conv_matrix):
"""Stain to RGB color space conversion.
Parameters
----------
stains : array_like
The image in stain color space, in a 3-D array of shape (.., .., 3).
conv_matrix: ndarray
The stain separation matrix as described by G. Landini [1]_.
Returns
-------
out : ndarray
The image in RGB format, in a 3-D array of shape (.., .., 3).
Raises
------
ValueError
If `stains` is not a 3-D array of shape (.., .., 3).
Notes
-----
Stain combination matrices available in the ``color`` module and their
respective colorspace:
* ``rgb_from_hed``: Hematoxylin + Eosin + DAB
* ``rgb_from_hdx``: Hematoxylin + DAB
* ``rgb_from_fgx``: Feulgen + Light Green
* ``rgb_from_bex``: Giemsa stain : Methyl Blue + Eosin
* ``rgb_from_rbd``: FastRed + FastBlue + DAB
* ``rgb_from_gdx``: Methyl Green + DAB
* ``rgb_from_hax``: Hematoxylin + AEC
* ``rgb_from_bro``: Blue matrix Anilline Blue + Red matrix Azocarmine\
+ Orange matrix Orange-G
* ``rgb_from_bpx``: Methyl Blue + Ponceau Fuchsin
* ``rgb_from_ahx``: Alcian Blue + Hematoxylin
* ``rgb_from_hpx``: Hematoxylin + PAS
References
----------
.. [1] http://www.dentistry.bham.ac.uk/landinig/software/cdeconv/cdeconv.html
Examples
--------
>>> from skimage import data
>>> from skimage.color import (separate_stains, combine_stains,
... hdx_from_rgb, rgb_from_hdx)
>>> ihc = data.immunohistochemistry()
>>> ihc_hdx = separate_stains(ihc, hdx_from_rgb)
>>> ihc_rgb = combine_stains(ihc_hdx, rgb_from_hdx)
"""
from ..exposure import rescale_intensity
stains = dtype.img_as_float(stains)
logrgb2 = np.dot(-np.reshape(stains, (-1, 3)), conv_matrix)
rgb2 = np.exp(logrgb2)
return rescale_intensity(np.reshape(rgb2 - 2, stains.shape), in_range=(-1, 1))
+30 -1
View File
@@ -16,11 +16,14 @@ import os.path
import numpy as np
from numpy.testing import *
from skimage import img_as_float
from skimage import img_as_float, img_as_ubyte
from skimage.io import imread
from skimage.color import (
rgb2hsv, hsv2rgb,
rgb2xyz, xyz2rgb,
rgb2hed, hed2rgb,
separate_stains,
combine_stains,
rgb2rgbcie, rgbcie2rgb,
convert_colorspace,
rgb2grey, gray2rgb,
@@ -121,6 +124,32 @@ class TestColorconv(TestCase):
img_rgb = img_as_float(self.img_rgb)
assert_array_almost_equal(xyz2rgb(rgb2xyz(img_rgb)), img_rgb)
# RGB<->HED roundtrip with ubyte image
def test_hed_rgb_roundtrip(self):
img_rgb = self.img_rgb
assert_equal(img_as_ubyte(hed2rgb(rgb2hed(img_rgb))), img_rgb)
# RGB<->HED roundtrip with float image
def test_hed_rgb_float_roundtrip(self):
img_rgb = img_as_float(self.img_rgb)
assert_array_almost_equal(hed2rgb(rgb2hed(img_rgb)), img_rgb)
# RGB<->HDX roundtrip with ubyte image
def test_hdx_rgb_roundtrip(self):
from skimage.color.colorconv import hdx_from_rgb, rgb_from_hdx
img_rgb = self.img_rgb
conv = combine_stains(separate_stains(img_rgb, hdx_from_rgb),
rgb_from_hdx)
assert_equal(img_as_ubyte(conv), img_rgb)
# RGB<->HDX roundtrip with ubyte image
def test_hdx_rgb_roundtrip(self):
from skimage.color.colorconv import hdx_from_rgb, rgb_from_hdx
img_rgb = img_as_float(self.img_rgb)
conv = combine_stains(separate_stains(img_rgb, hdx_from_rgb),
rgb_from_hdx)
assert_array_almost_equal(conv, img_rgb)
# RGB to RGB CIE
def test_rgb2rgbcie_conversion(self):
gt = np.array([[[ 0.1488856 , 0.18288098, 0.19277574],
+16
View File
@@ -127,3 +127,19 @@ def clock():
"""
return load("clock_motion.png")
def immunohistochemistry():
"""Immunohistochemical (IHC) staining with hematoxylin counterstaining.
This picture shows colonic glands where the IHC expression of FHL2 protein
is revealed with DAB. Hematoxylin counterstaining is applied to enhance the
negative parts of the tissue.
This image was acquired at the Center for Microscopy And Molecular Imaging
(CMMI).
No known copyright restrictions.
"""
return load("ihc.jpg")
Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

+59 -47
View File
@@ -2,15 +2,15 @@
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
import math
import numpy as np
cimport numpy as cnp
from libc.math cimport sqrt
cimport numpy as np
cimport cython
from skimage._shared.geometry cimport point_in_polygon
def line(int y, int x, int y2, int x2):
def line(Py_ssize_t y, Py_ssize_t x, Py_ssize_t y2, Py_ssize_t x2):
"""Generate line pixel coordinates.
Parameters
@@ -29,12 +29,12 @@ def line(int y, int x, int y2, int x2):
"""
cdef np.ndarray[np.int32_t, ndim=1, mode="c"] rr, cc
cdef cnp.ndarray[cnp.intp_t, ndim=1, mode="c"] rr, cc
cdef int steep = 0
cdef int dx = abs(x2 - x)
cdef int dy = abs(y2 - y)
cdef int sx, sy, d, i
cdef char steep = 0
cdef Py_ssize_t dx = abs(x2 - x)
cdef Py_ssize_t dy = abs(y2 - y)
cdef Py_ssize_t sx, sy, d, i
if (x2 - x) > 0:
sx = 1
@@ -51,8 +51,8 @@ def line(int y, int x, int y2, int x2):
sx, sy = sy, sx
d = (2 * dy) - dx
rr = np.zeros(int(dx) + 1, dtype=np.int32)
cc = np.zeros(int(dx) + 1, dtype=np.int32)
rr = np.zeros(int(dx) + 1, dtype=np.intp)
cc = np.zeros(int(dx) + 1, dtype=np.intp)
for i in range(dx):
if steep:
@@ -96,27 +96,27 @@ def polygon(y, x, shape=None):
"""
cdef int nr_verts = x.shape[0]
cdef int minr = <int>max(0, y.min())
cdef int maxr = <int>math.ceil(y.max())
cdef int minc = <int>max(0, x.min())
cdef int maxc = <int>math.ceil(x.max())
cdef Py_ssize_t nr_verts = x.shape[0]
cdef Py_ssize_t minr = int(max(0, y.min()))
cdef Py_ssize_t maxr = int(math.ceil(y.max()))
cdef Py_ssize_t minc = int(max(0, x.min()))
cdef Py_ssize_t maxc = int(math.ceil(x.max()))
# make sure output coordinates do not exceed image size
if shape is not None:
maxr = min(shape[0] - 1, maxr)
maxc = min(shape[1] - 1, maxc)
cdef int r, c
cdef Py_ssize_t r, c
#: make contigous arrays for r, c coordinates
cdef np.ndarray contiguous_rdata, contiguous_cdata
# make contigous arrays for r, c coordinates
cdef cnp.ndarray contiguous_rdata, contiguous_cdata
contiguous_rdata = np.ascontiguousarray(y, 'double')
contiguous_cdata = np.ascontiguousarray(x, 'double')
cdef np.double_t* rptr = <np.double_t*>contiguous_rdata.data
cdef np.double_t* cptr = <np.double_t*>contiguous_cdata.data
cdef cnp.double_t* rptr = <cnp.double_t*>contiguous_rdata.data
cdef cnp.double_t* cptr = <cnp.double_t*>contiguous_cdata.data
#: output coordinate arrays
# output coordinate arrays
cdef list rr = list()
cdef list cc = list()
@@ -126,7 +126,7 @@ def polygon(y, x, shape=None):
rr.append(r)
cc.append(c)
return np.array(rr), np.array(cc)
return np.array(rr, dtype=np.intp), np.array(cc, dtype=np.intp)
def ellipse(double cy, double cx, double yradius, double xradius, shape=None):
@@ -138,6 +138,10 @@ def ellipse(double cy, double cx, double yradius, double xradius, shape=None):
Centre coordinate of ellipse.
yradius, xradius : double
Minor and major semi-axes. ``(x/xradius)**2 + (y/yradius)**2 = 1``.
shape : tuple, optional
image shape which is used to determine maximum extents of output pixel
coordinates. This is useful for ellipses which exceed the image size.
By default the full extents of the ellipse are used.
Returns
-------
@@ -148,19 +152,19 @@ def ellipse(double cy, double cx, double yradius, double xradius, shape=None):
"""
cdef int minr = <int>max(0, cy - yradius)
cdef int maxr = <int>math.ceil(cy + yradius)
cdef int minc = <int>max(0, cx - xradius)
cdef int maxc = <int>math.ceil(cx + xradius)
cdef Py_ssize_t minr = int(max(0, cy - yradius))
cdef Py_ssize_t maxr = int(math.ceil(cy + yradius))
cdef Py_ssize_t minc = int(max(0, cx - xradius))
cdef Py_ssize_t maxc = int(math.ceil(cx + xradius))
# make sure output coordinates do not exceed image size
if shape is not None:
maxr = min(shape[0] - 1, maxr)
maxc = min(shape[1] - 1, maxc)
cdef int r, c
cdef Py_ssize_t r, c
#: output coordinate arrays
# output coordinate arrays
cdef list rr = list()
cdef list cc = list()
@@ -170,7 +174,7 @@ def ellipse(double cy, double cx, double yradius, double xradius, shape=None):
rr.append(r)
cc.append(c)
return np.array(rr), np.array(cc)
return np.array(rr, dtype=np.intp), np.array(cc, dtype=np.intp)
def circle(double cy, double cx, double radius, shape=None):
@@ -182,6 +186,10 @@ def circle(double cy, double cx, double radius, shape=None):
Centre coordinate of circle.
radius: double
Radius of circle.
shape : tuple, optional
image shape which is used to determine maximum extents of output pixel
coordinates. This is useful for circles which exceed the image size.
By default the full extents of the circle are used.
Returns
-------
@@ -189,13 +197,16 @@ def circle(double cy, double cx, double radius, shape=None):
Pixel coordinates of circle.
May be used to directly index into an array, e.g.
``img[rr, cc] = 1``.
Notes
-----
This function is a wrapper for skimage.draw.ellipse()
"""
return ellipse(cy, cx, radius, radius, shape)
def circle_perimeter(int cy, int cx, int radius, method='bresenham'):
def circle_perimeter(Py_ssize_t cy, Py_ssize_t cx, Py_ssize_t radius,
method='bresenham'):
"""Generate circle perimeter coordinates.
Parameters
@@ -234,9 +245,9 @@ def circle_perimeter(int cy, int cx, int radius, method='bresenham'):
cdef list rr = list()
cdef list cc = list()
cdef int x = 0
cdef int y = radius
cdef int d = 0
cdef Py_ssize_t x = 0
cdef Py_ssize_t y = radius
cdef Py_ssize_t d = 0
cdef char cmethod
if method == 'bresenham':
d = 3 - 2 * radius
@@ -270,10 +281,11 @@ def circle_perimeter(int cy, int cx, int radius, method='bresenham'):
y = y - 1
x = x + 1
return np.array(rr) + cy, np.array(cc) + cx
return np.array(rr, dtype=np.intp) + cy, np.array(cc, dtype=np.intp) + cx
def ellipse_perimeter(int cy, int cx, int yradius, int xradius):
def ellipse_perimeter(Py_ssize_t cy, Py_ssize_t cx, Py_ssize_t yradius,
Py_ssize_t xradius):
"""Generate ellipse perimeter coordinates.
Parameters
@@ -302,8 +314,8 @@ def ellipse_perimeter(int cy, int cx, int yradius, int xradius):
return np.array(cy), np.array(cx)
# a and b are xradius an yradius compute 2a^2 and 2b^2
cdef int twoasquared = 2 * xradius**2
cdef int twobsquared = 2 * yradius**2
cdef Py_ssize_t twoasquared = 2 * xradius**2
cdef Py_ssize_t twobsquared = 2 * yradius**2
# Pixels
cdef list px = list()
@@ -311,14 +323,14 @@ def ellipse_perimeter(int cy, int cx, int yradius, int xradius):
# First set of points:
# start at the top
cdef int x = xradius
cdef int y = 0
cdef Py_ssize_t x = xradius
cdef Py_ssize_t y = 0
cdef int err = 0
cdef int xstop = twobsquared * xradius
cdef int ystop = 0
cdef int xchange = yradius * yradius * (1 - 2 * xradius)
cdef int ychange = xradius * xradius
cdef Py_ssize_t err = 0
cdef Py_ssize_t xstop = twobsquared * xradius
cdef Py_ssize_t ystop = 0
cdef Py_ssize_t xchange = yradius * yradius * (1 - 2 * xradius)
cdef Py_ssize_t ychange = xradius * xradius
while xstop > ystop:
px.extend([x, -x, -x, x])
@@ -356,7 +368,7 @@ def ellipse_perimeter(int cy, int cx, int yradius, int xradius):
err += ychange
ychange += twobsquared
return np.array(py) + cy, np.array(px) + cx
return np.array(py, dtype=np.intp) + cy, np.array(px, dtype=np.intp) + cx
def set_color(img, coords, color):
+7 -6
View File
@@ -259,6 +259,8 @@ def map_histogram(hist, min_val, max_val, n_pixels):
It does so by cumulating the input histogram.
Parameters
----------
hist : ndarray
Clipped histogram.
min_val : int
@@ -301,12 +303,11 @@ def interpolate(image, xslice, yslice,
out : ndarray
Original image with the subregion replaced.
Note
----
This function calculates the new greylevel assignments of pixels
within a submatrix of the image.
This is done by a bilinear interpolation between four different
mappings in order to eliminate boundary artifacts.
Notes
-----
This function calculates the new greylevel assignments of pixels within
a submatrix of the image. This is done by a bilinear interpolation between
four different mappings in order to eliminate boundary artifacts.
"""
norm = xslice.size * yslice.size # Normalization factor
# interpolation weight matrices
+1 -1
View File
@@ -81,7 +81,7 @@ def cumulative_distribution(image, nbins=256):
@deprecated('equalize_hist')
def equalize(image, nbins=256):
equalize_hist(image, nbins)
return equalize_hist(image, nbins)
def equalize_hist(image, nbins=256):
+20 -14
View File
@@ -53,30 +53,35 @@ def daisy(img, step=4, radius=15, rings=3, histograms=8, orientations=8,
the spatial smoothing of the center histogram and the last sigma value
defines the spatial smoothing of the outermost ring. Specifying sigmas
overrides the following parameter.
``rings = len(sigmas)-1``
``rings = len(sigmas) - 1``
ring_radii : 1D array of int, optional
Radius (in pixels) for each ring. Specifying ring_radii overrides the
following two parameters.
| ``rings = len(ring_radii)``
| ``radius = ring_radii[-1]``
``rings = len(ring_radii)``
``radius = ring_radii[-1]``
If both sigmas and ring_radii are given, they must satisfy the
following predicate since no radius is needed for the center
histogram.
``len(ring_radii) == len(sigmas)+1``
``len(ring_radii) == len(sigmas) + 1``
visualize : bool, optional
Generate a visualization of the DAISY descriptors
Returns
-------
descs : array
Grid of DAISY descriptors for the given image as an array
dimensionality (P, Q, R) where
| ``P = ceil((M-radius*2)/step)``
| ``Q = ceil((N-radius*2)/step)``
| ``R = (rings*histograms + 1)*orientations``
``P = ceil((M - radius*2) / step)``
``Q = ceil((N - radius*2) / step)``
``R = (rings * histograms + 1) * orientations``
descs_img : (M, N, 3) array (only if visualize==True)
Visualization of the DAISY descriptors.
@@ -180,7 +185,7 @@ def daisy(img, step=4, radius=15, rings=3, histograms=8, orientations=8,
color = (1, 0, 0)
desc_y = i * step + radius
desc_x = j * step + radius
coords = draw.circle_perimeter(desc_y, desc_x, sigmas[0])
coords = draw.circle_perimeter(desc_y, desc_x, int(sigmas[0]))
draw.set_color(descs_img, coords, color)
max_bin = np.max(descs[i, j, :])
for o_num, o in enumerate(orientation_angles):
@@ -188,8 +193,8 @@ def daisy(img, step=4, radius=15, rings=3, histograms=8, orientations=8,
bin_size = descs[i, j, o_num] / max_bin
dy = sigmas[0] * bin_size * sin(o)
dx = sigmas[0] * bin_size * cos(o)
coords = draw.line(desc_y, desc_x, desc_y + dy,
desc_x + dx)
coords = draw.line(desc_y, desc_x, int(desc_y + dy),
int(desc_x + dx))
draw.set_color(descs_img, coords, color)
for r_num, r in enumerate(ring_radii):
color_offset = float(1 + r_num) / rings
@@ -199,7 +204,7 @@ def daisy(img, step=4, radius=15, rings=3, histograms=8, orientations=8,
hist_y = desc_y + int(round(r * sin(t)))
hist_x = desc_x + int(round(r * cos(t)))
coords = draw.circle_perimeter(hist_y, hist_x,
sigmas[r_num + 1])
int(sigmas[r_num + 1]))
draw.set_color(descs_img, coords, color)
for o_num, o in enumerate(orientation_angles):
# Draw histogram bins
@@ -209,8 +214,9 @@ def daisy(img, step=4, radius=15, rings=3, histograms=8, orientations=8,
bin_size /= max_bin
dy = sigmas[r_num + 1] * bin_size * sin(o)
dx = sigmas[r_num + 1] * bin_size * cos(o)
coords = draw.line(hist_y, hist_x, hist_y + dy,
hist_x + dx)
coords = draw.line(hist_y, hist_x,
int(hist_y + dy),
int(hist_x + dx))
draw.set_color(descs_img, coords, color)
return descs, descs_img
else:
+4 -2
View File
@@ -142,8 +142,10 @@ def hog(image, orientations=9, pixels_per_cell=(8, 8),
centre = tuple([y * cy + cy // 2, x * cx + cx // 2])
dx = radius * cos(float(o) / orientations * np.pi)
dy = radius * sin(float(o) / orientations * np.pi)
rr, cc = draw.bresenham(centre[0] - dx, centre[1] - dy,
centre[0] + dx, centre[1] + dy)
rr, cc = draw.bresenham(int(centre[0] - dx),
int(centre[1] - dy),
int(centre[0] + dx),
int(centre[1] + dy))
hog_image[rr, cc] += orientation_histogram[y, x, o]
"""
+34 -23
View File
@@ -1,3 +1,8 @@
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
"""
Template matching using normalized cross-correlation.
@@ -30,24 +35,31 @@ the image window *before* squaring.)
.. [2] J. P. Lewis, "Fast Normalized Cross-Correlation", Industrial Light and
Magic.
"""
import cython
cimport numpy as np
import numpy as np
from scipy.signal import fftconvolve
from skimage.transform import integral
cimport numpy as cnp
from libc.math cimport sqrt, fabs
from skimage._shared.transform cimport integrate
@cython.boundscheck(False)
def match_template(np.ndarray[float, ndim=2, mode="c"] image,
np.ndarray[float, ndim=2, mode="c"] template):
cdef np.ndarray[float, ndim=2, mode="c"] corr
cdef np.ndarray[float, ndim=2, mode="c"] image_sat
cdef np.ndarray[float, ndim=2, mode="c"] image_sqr_sat
from skimage.transform import integral
def match_template(cnp.ndarray[float, ndim=2, mode="c"] image,
cnp.ndarray[float, ndim=2, mode="c"] template):
cdef cnp.ndarray[float, ndim=2, mode="c"] corr
cdef cnp.ndarray[float, ndim=2, mode="c"] image_sat
cdef cnp.ndarray[float, ndim=2, mode="c"] image_sqr_sat
cdef float template_mean = np.mean(template)
cdef float template_ssd
cdef float inv_area
cdef Py_ssize_t r, c, r_end, c_end
cdef Py_ssize_t template_rows = template.shape[0]
cdef Py_ssize_t template_cols = template.shape[1]
cdef float den, window_sqr_sum, window_mean_sqr, window_sum
image_sat = integral.integral_image(image)
image_sqr_sat = integral.integral_image(image**2)
@@ -63,24 +75,23 @@ def match_template(np.ndarray[float, ndim=2, mode="c"] image,
mode="valid"),
dtype=np.float32)
cdef int i, j
cdef float den, window_sqr_sum, window_mean_sqr, window_sum,
# move window through convolution results, normalizing in the process
for i in range(corr.shape[0]):
for j in range(corr.shape[1]):
# subtract 1 because `i_end` and `j_end` are used for indexing into
# summed-area table, instead of slicing windows of the image.
i_end = i + template.shape[0] - 1
j_end = j + template.shape[1] - 1
window_sum = integrate(image_sat, i, j, i_end, j_end)
# move window through convolution results, normalizing in the process
for r in range(corr.shape[0]):
for c in range(corr.shape[1]):
# subtract 1 because `i_end` and `c_end` are used for indexing into
# summed-area table, instead of slicing windows of the image.
r_end = r + template_rows - 1
c_end = c + template_cols - 1
window_sum = integrate(image_sat, r, c, r_end, c_end)
window_mean_sqr = window_sum * window_sum * inv_area
window_sqr_sum = integrate(image_sqr_sat, i, j, i_end, j_end)
window_sqr_sum = integrate(image_sqr_sat, r, c, r_end, c_end)
if window_sqr_sum <= window_mean_sqr:
corr[i, j] = 0
corr[r, c] = 0
continue
den = sqrt((window_sqr_sum - window_mean_sqr) * template_ssd)
corr[i, j] /= den
return corr
corr[r, c] /= den
return corr
+28 -26
View File
@@ -3,21 +3,20 @@
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
cimport numpy as np
cimport numpy as cnp
from libc.math cimport sin, cos, abs
from skimage._shared.interpolation cimport bilinear_interpolation
def _glcm_loop(np.ndarray[dtype=np.uint8_t, ndim=2,
negative_indices=False, mode='c'] image,
np.ndarray[dtype=np.float64_t, ndim=1,
negative_indices=False, mode='c'] distances,
np.ndarray[dtype=np.float64_t, ndim=1,
negative_indices=False, mode='c'] angles,
def _glcm_loop(cnp.ndarray[dtype=cnp.uint8_t, ndim=2,
negative_indices=False, mode='c'] image,
cnp.ndarray[dtype=cnp.float64_t, ndim=1,
negative_indices=False, mode='c'] distances,
cnp.ndarray[dtype=cnp.float64_t, ndim=1,
negative_indices=False, mode='c'] angles,
int levels,
np.ndarray[dtype=np.uint32_t, ndim=4,
negative_indices=False, mode='c'] out
):
cnp.ndarray[dtype=cnp.uint32_t, ndim=4,
negative_indices=False, mode='c'] out):
"""Perform co-occurrence matrix accumulation.
Parameters
@@ -37,23 +36,26 @@ def _glcm_loop(np.ndarray[dtype=np.uint8_t, ndim=2,
the results of the GLCM computation.
"""
cdef:
np.int32_t a_inx, d_idx
np.int32_t r, c, rows, cols, row, col
np.int32_t i, j
Py_ssize_t a_idx, d_idx, r, c, rows, cols, row, col
cnp.uint8_t i, j
cnp.float64_t angle, distance
rows = image.shape[0]
cols = image.shape[1]
for a_idx, angle in enumerate(angles):
for d_idx, distance in enumerate(distances):
for a_idx in range(len(angles)):
angle = angles[a_idx]
for d_idx in range(len(distances)):
distance = distances[d_idx]
for r in range(rows):
for c in range(cols):
i = image[r, c]
# compute the location of the offset pixel
row = r + <int>(sin(angle) * distance + 0.5)
col = c + <int>(cos(angle) * distance + 0.5);
col = c + <int>(cos(angle) * distance + 0.5)
# make sure the offset is within bounds
if row >= 0 and row < rows and \
@@ -79,7 +81,7 @@ cdef inline int _bit_rotate_right(int value, int length):
return (value >> 1) | ((value & 1) << (length - 1))
def _local_binary_pattern(np.ndarray[double, ndim=2] image,
def _local_binary_pattern(cnp.ndarray[double, ndim=2] image,
int P, float R, char method='D'):
"""Gray scale and rotation invariant LBP (Local Binary Patterns).
@@ -109,25 +111,25 @@ def _local_binary_pattern(np.ndarray[double, ndim=2] image,
"""
# texture weights
cdef np.ndarray[int, ndim=1] weights = 2 ** np.arange(P, dtype=np.int32)
cdef cnp.ndarray[int, ndim=1] weights = 2 ** np.arange(P, dtype=np.int32)
# local position of texture elements
rp = - R * np.sin(2 * np.pi * np.arange(P, dtype=np.double) / P)
cp = R * np.cos(2 * np.pi * np.arange(P, dtype=np.double) / P)
cdef np.ndarray[double, ndim=2] coords = np.round(np.vstack([rp, cp]).T, 5)
cdef cnp.ndarray[double, ndim=2] coords = np.round(np.vstack([rp, cp]).T, 5)
# pre allocate arrays for computation
cdef np.ndarray[double, ndim=1] texture = np.zeros(P, np.double)
cdef np.ndarray[char, ndim=1] signed_texture = np.zeros(P, np.int8)
cdef np.ndarray[int, ndim=1] rotation_chain = np.zeros(P, np.int32)
cdef cnp.ndarray[double, ndim=1] texture = np.zeros(P, np.double)
cdef cnp.ndarray[char, ndim=1] signed_texture = np.zeros(P, np.int8)
cdef cnp.ndarray[int, ndim=1] rotation_chain = np.zeros(P, np.int32)
output_shape = (image.shape[0], image.shape[1])
cdef np.ndarray[double, ndim=2] output = np.zeros(output_shape, np.double)
cdef cnp.ndarray[double, ndim=2] output = np.zeros(output_shape, np.double)
cdef int rows = image.shape[0]
cdef int cols = image.shape[1]
cdef Py_ssize_t rows = image.shape[0]
cdef Py_ssize_t cols = image.shape[1]
cdef double lbp
cdef int r, c, changes, i
cdef Py_ssize_t r, c, changes, i
for r in range(image.shape[0]):
for c in range(image.shape[1]):
for i in range(P):
+14 -14
View File
@@ -136,11 +136,11 @@ def corner_harris(image, method='k', k=0.05, eps=1e-6, sigma=1):
References
----------
..[1] http://kiwi.cs.dal.ca/~dparks/CornerDetection/harris.htm
..[2] http://en.wikipedia.org/wiki/Corner_detection
.. [1] http://kiwi.cs.dal.ca/~dparks/CornerDetection/harris.htm
.. [2] http://en.wikipedia.org/wiki/Corner_detection
Examples
-------
--------
>>> from skimage.feature import corner_harris, corner_peaks
>>> square = np.zeros([10, 10])
>>> square[2:8, 2:8] = 1
@@ -206,11 +206,11 @@ def corner_shi_tomasi(image, sigma=1):
References
----------
..[1] http://kiwi.cs.dal.ca/~dparks/CornerDetection/harris.htm
..[2] http://en.wikipedia.org/wiki/Corner_detection
.. [1] http://kiwi.cs.dal.ca/~dparks/CornerDetection/harris.htm
.. [2] http://en.wikipedia.org/wiki/Corner_detection
Examples
-------
--------
>>> from skimage.feature import corner_shi_tomasi, corner_peaks
>>> square = np.zeros([10, 10])
>>> square[2:8, 2:8] = 1
@@ -272,12 +272,12 @@ def corner_foerstner(image, sigma=1):
References
----------
..[1] http://www.ipb.uni-bonn.de/uploads/tx_ikgpublication/\
foerstner87.fast.pdf
..[2] http://en.wikipedia.org/wiki/Corner_detection
.. [1] http://www.ipb.uni-bonn.de/uploads/tx_ikgpublication/\
foerstner87.fast.pdf
.. [2] http://en.wikipedia.org/wiki/Corner_detection
Examples
-------
--------
>>> from skimage.feature import corner_foerstner, corner_peaks
>>> square = np.zeros([10, 10])
>>> square[2:8, 2:8] = 1
@@ -338,9 +338,9 @@ def corner_subpix(image, corners, window_size=11, alpha=0.99):
References
----------
..[1] http://www.ipb.uni-bonn.de/uploads/tx_ikgpublication/\
foerstner87.fast.pdf
..[2] http://en.wikipedia.org/wiki/Corner_detection
.. [1] http://www.ipb.uni-bonn.de/uploads/tx_ikgpublication/\
foerstner87.fast.pdf
.. [2] http://en.wikipedia.org/wiki/Corner_detection
"""
@@ -489,7 +489,7 @@ def corner_peaks(image, min_distance=10, threshold_abs=0, threshold_rel=0.1,
threshold_abs=threshold_abs,
threshold_rel=threshold_rel,
exclude_border=exclude_border,
indices=False, num_peaks=np.inf,
indices=False, num_peaks=num_peaks,
footprint=footprint, labels=labels)
if min_distance > 0:
coords = np.transpose(peaks.nonzero())
+5 -5
View File
@@ -10,7 +10,7 @@ from skimage.color import rgb2grey
from skimage.util import img_as_float
def corner_moravec(image, int window_size=1):
def corner_moravec(image, Py_ssize_t window_size=1):
"""Compute Moravec corner measure response image.
This is one of the simplest corner detectors and is comparatively fast but
@@ -34,7 +34,7 @@ def corner_moravec(image, int window_size=1):
..[2] http://en.wikipedia.org/wiki/Corner_detection
Examples
-------
--------
>>> from skimage.feature import moravec, peak_local_max
>>> square = np.zeros([7, 7])
>>> square[3, 3] = 1
@@ -56,8 +56,8 @@ def corner_moravec(image, int window_size=1):
[ 0., 0., 0., 0., 0., 0., 0.]])
"""
cdef int rows = image.shape[0]
cdef int cols = image.shape[1]
cdef Py_ssize_t rows = image.shape[0]
cdef Py_ssize_t cols = image.shape[1]
cdef cnp.ndarray[dtype=cnp.double_t, ndim=2, mode='c'] cimage, out
@@ -71,7 +71,7 @@ def corner_moravec(image, int window_size=1):
cdef double* out_data = <double*>out.data
cdef double msum, min_msum
cdef int r, c, br, bc, mr, mc, a, b
cdef Py_ssize_t r, c, br, bc, mr, mc, a, b
for r in range(2 * window_size, rows - 2 * window_size):
for c in range(2 * window_size, cols - 2 * window_size):
min_msum = DBL_MAX
+4 -3
View File
@@ -50,9 +50,10 @@ def peak_local_max(image, min_distance=10, threshold_abs=0, threshold_rel=0.1,
Returns
-------
output : (N, 2) array or ndarray of bools
If `indices = True` : (row, column) coordinates of peaks.
If `indices = False` : Boolean array shaped like `image`,
with peaks represented by True values.
* If `indices = True` : (row, column) coordinates of peaks.
* If `indices = False` : Boolean array shaped like `image`, with peaks
represented by True values.
Notes
-----
+13
View File
@@ -100,6 +100,19 @@ def test_subpix():
assert_array_equal(subpix[0], (24.5, 24.5))
def test_num_peaks():
"""For a bunch of different values of num_peaks, check that
peak_local_max returns exactly the right amount of peaks. Test
is run on Lena in order to produce a sufficient number of corners"""
lena_corners = corner_harris(data.lena())
for i in range(20):
n = np.random.random_integers(20)
results = peak_local_max(lena_corners, num_peaks=n)
assert (results.shape[0] == n)
def test_corner_peaks():
response = np.zeros((5, 5))
response[2:4, 2:4] = 1
+1 -1
View File
@@ -102,7 +102,7 @@ def test_hog_orientations_circle():
width = height = 100
image = np.zeros((height, width))
rr, cc = draw.circle(height/2, width/2, width/3)
rr, cc = draw.circle(int(height / 2), int(width / 2), int(width / 3))
image[rr, cc] = 100
image = ndimage.gaussian_filter(image, 2)
+173 -184
View File
@@ -10,14 +10,20 @@ Copyright (c) 2009-2011 Broad Institute
All rights reserved.
Original author: Lee Kamentsky
'''
import numpy as np
cimport numpy as np
cimport numpy as cnp
cimport cython
from libc.stdlib cimport malloc, free
from libc.string cimport memset
np.import_array()
cdef extern from "../_shared/vectorized_ops.h":
void add16(cnp.uint16_t *dest, cnp.uint16_t *src)
void sub16(cnp.uint16_t *dest, cnp.uint16_t *src)
##############################################################################
#
@@ -39,7 +45,7 @@ np.import_array()
DTYPE_UINT32 = np.uint32
DTYPE_BOOL = np.bool
ctypedef np.uint16_t pixel_count_t
ctypedef cnp.uint16_t pixel_count_t
###########
#
@@ -54,15 +60,15 @@ ctypedef np.uint16_t pixel_count_t
###########
cdef struct HistogramPiece:
np.uint16_t coarse[16]
np.uint16_t fine[256]
cnp.uint16_t coarse[16]
cnp.uint16_t fine[256]
cdef struct Histogram:
HistogramPiece top_left # top-left corner
HistogramPiece top_right # top-right corner
HistogramPiece edge # leading/trailing edge
HistogramPiece bottom_left # bottom-left corner
HistogramPiece bottom_right # bottom-right corner
HistogramPiece top_left # top-left corner
HistogramPiece top_right # top-right corner
HistogramPiece edge # leading/trailing edge
HistogramPiece bottom_left # bottom-left corner
HistogramPiece bottom_right # bottom-right corner
# The pixel count has the number of pixels histogrammed in
# each of the five compartments for this position. This changes
@@ -80,27 +86,28 @@ cdef struct PixelCount:
# relative offsets from the octagon center
#
cdef struct SCoord:
np.int32_t stride # add the stride to the memory location
np.int32_t x
np.int32_t y
Py_ssize_t stride # add the stride to the memory location
Py_ssize_t x
Py_ssize_t y
cdef struct Histograms:
void *memory # pointer to the allocated memory
Histogram *histogram # pointer to the histogram memory
HistogramPiece accumulator # running histogram (32-byte aligned)
void *memory # pointer to the unaligned allocated memory
Histogram *histogram # pointer to the histogram memory (aligned)
PixelCount *pixel_count # pointer to the pixel count memory
np.uint8_t *data # pointer to the image data
np.uint8_t *mask # pointer to the image mask
np.uint8_t *output # pointer to the output array
np.int32_t column_count # number of columns represented by this
cnp.uint8_t *data # pointer to the image data
cnp.uint8_t *mask # pointer to the image mask
cnp.uint8_t *output # pointer to the output array
Py_ssize_t column_count # number of columns represented by this
# structure
np.int32_t stripe_length # number of columns including "radius" before
Py_ssize_t stripe_length # number of columns including "radius" before
# and after
np.int32_t row_count # number of rows available in image
np.int32_t current_column # the column being processed
np.int32_t current_row # the row being processed
np.int32_t current_stride # offset in data and mask to current location
np.int32_t radius # the "radius" of the octagon
np.int32_t a_2 # 1/2 of the length of a side of the octagon
Py_ssize_t row_count # number of rows available in image
Py_ssize_t current_column # the column being processed
Py_ssize_t current_row # the row being processed
Py_ssize_t current_stride # offset in data and mask to current location
Py_ssize_t radius # the "radius" of the octagon
Py_ssize_t a_2 # 1/2 of the length of a side of the octagon
#
#
# The strides are the offsets in the array to the points that need to
@@ -123,83 +130,80 @@ cdef struct Histograms:
#
# x -->
#
SCoord last_top_left # (-) left side of octagon's top - 1 row
SCoord top_left # (+) -1 row from trailing edge top
SCoord last_top_right # (-) right side of octagon's top - 1 col - 1 row
SCoord top_right # (+) -1 col -1 row from leading edge top
SCoord last_leading_edge # (-) leading edge (right) top stride - 1 row
SCoord leading_edge # (+) leading edge bottom stride
SCoord last_bottom_right # (-) leading edge bottom - 1 col
SCoord bottom_right # (+) right side of octagon's bottom - 1 col
SCoord last_bottom_left # (-) trailing edge bottom - 1 col
SCoord bottom_left # (+) left side of octagon's bottom - 1 col
SCoord last_top_left # (-) left side of octagon's top - 1 row
SCoord top_left # (+) -1 row from trailing edge top
SCoord last_top_right # (-) right side of octagon's top - 1 col - 1 row
SCoord top_right # (+) -1 col -1 row from leading edge top
SCoord last_leading_edge # (-) leading edge (right) top stride - 1 row
SCoord leading_edge # (+) leading edge bottom stride
SCoord last_bottom_right # (-) leading edge bottom - 1 col
SCoord bottom_right # (+) right side of octagon's bottom - 1 col
SCoord last_bottom_left # (-) trailing edge bottom - 1 col
SCoord bottom_left # (+) left side of octagon's bottom - 1 col
np.int32_t row_stride # stride between one row and the next
np.int32_t col_stride # stride between one column and the next
# The accumulator holds the running histogram
#
HistogramPiece accumulator
Py_ssize_t row_stride # stride between one row and the next
Py_ssize_t col_stride # stride between one column and the next
#
# The running count of pixels in the accumulator
#
np.uint32_t accumulator_count
Py_ssize_t accumulator_count
#
# The percent of pixels within the octagon whose value is
# less than or equal to the median-filtered value (e.g. for
# median, this is 50, for lower quartile it's 25)
#
np.int32_t percent
Py_ssize_t percent
#
# last_update_column keeps track of the column # of the last update
# to the fine histogram accumulator. Short-term, the median
# stays in one coarse block so only one fine histogram might
# need to be updated
#
np.int32_t last_update_column[16]
Py_ssize_t last_update_column[16]
############################################################################
#
# allocate_histograms - allocates the Histograms structure for the run
#
############################################################################
cdef Histograms *allocate_histograms(np.int32_t rows,
np.int32_t columns,
np.int32_t row_stride,
np.int32_t col_stride,
np.int32_t radius,
np.int32_t percent,
np.uint8_t *data,
np.uint8_t *mask,
np.uint8_t *output):
cdef Histograms *allocate_histograms(Py_ssize_t rows,
Py_ssize_t columns,
Py_ssize_t row_stride,
Py_ssize_t col_stride,
Py_ssize_t radius,
Py_ssize_t percent,
cnp.uint8_t *data,
cnp.uint8_t *mask,
cnp.uint8_t *output):
cdef:
unsigned int adjusted_stripe_length = columns + 2*radius + 1
unsigned int memory_size
Py_ssize_t adjusted_stripe_length = columns + 2*radius + 1
Py_ssize_t memory_size
void *ptr
Histograms *ph
size_t roundoff
int a
Py_ssize_t roundoff
Py_ssize_t a
SCoord *psc
memory_size = (adjusted_stripe_length *
(sizeof(Histogram) + sizeof(PixelCount))+
sizeof(Histograms)+32)
(sizeof(Histogram) + sizeof(PixelCount)) +
sizeof(Histograms) + 64)
ptr = malloc(memory_size)
memset(ptr, 0, memory_size)
ph = <Histograms *>ptr
# align ph.accumulator to 32-byte boundary
roundoff = (<Py_ssize_t> ptr + 31) % 32
ph = <Histograms *> (<Py_ssize_t> ptr + 31 - roundoff)
if not ptr:
return ph
ph.memory = ptr
ptr = <void *>(ph+1)
ph.pixel_count = <PixelCount *>ptr
ptr = <void *>(ph.pixel_count + adjusted_stripe_length)
ptr = <void *> (ph + 1)
ph.pixel_count = <PixelCount *> ptr
ptr = <void *> (ph.pixel_count + adjusted_stripe_length)
#
# Align histogram memory to a 32-byte boundary
#
roundoff = <size_t>ptr
roundoff += 31
roundoff -= roundoff % 32
ptr = <void *>roundoff
ph.histogram = <Histogram *>ptr
roundoff = (<Py_ssize_t> ptr + 31) % 32
ptr = <void *> (<Py_ssize_t> ptr + 31 - roundoff)
ph.histogram = <Histogram *> ptr
#
# Fill in the statistical things we keep around
#
@@ -228,7 +232,7 @@ cdef Histograms *allocate_histograms(np.int32_t rows,
# a_2 is the offset from the center to each of the octagon
# corners
#
a = <int>(<np.float64_t>radius * 2.0 / 2.414213)
a = <Py_ssize_t>(<cnp.float64_t>radius * 2.0 / 2.414213)
a_2 = a / 2
if a_2 == 0:
a_2 = 1
@@ -322,34 +326,18 @@ cdef void set_stride(Histograms *ph, SCoord *psc):
# a column that is "radius" to the left.
#
############################################################################
cdef inline np.int32_t tl_br_colidx(Histograms *ph, np.int32_t colidx):
cdef inline Py_ssize_t tl_br_colidx(Histograms *ph, Py_ssize_t colidx):
return (colidx + 3*ph.radius + ph.current_row) % ph.stripe_length
cdef inline np.int32_t tr_bl_colidx(Histograms *ph, np.int32_t colidx):
cdef inline Py_ssize_t tr_bl_colidx(Histograms *ph, Py_ssize_t colidx):
return (colidx + 3*ph.radius + ph.row_count-ph.current_row) % \
ph.stripe_length
cdef inline np.int32_t leading_edge_colidx(Histograms *ph, np.int32_t colidx):
cdef inline Py_ssize_t leading_edge_colidx(Histograms *ph, Py_ssize_t colidx):
return (colidx + 5*ph.radius) % ph.stripe_length
cdef inline np.int32_t trailing_edge_colidx(Histograms *ph, np.int32_t colidx):
cdef inline Py_ssize_t trailing_edge_colidx(Histograms *ph, Py_ssize_t colidx):
return (colidx + 3*ph.radius - 1) % ph.stripe_length
#
# add16 - add 16 consecutive integers
#
# Add an array of 16 16-bit integers to an accumulator of 16 16-bit integers
#
# TO_DO - optimize using SIMD instructions
#
cdef inline void add16(np.uint16_t *dest, np.uint16_t *src):
cdef int i
for i in range(16):
dest[i] += src[i]
cdef inline void sub16(np.uint16_t *dest, np.uint16_t *src):
cdef int i
for i in range(16):
dest[i] -= src[i]
############################################################################
#
@@ -360,9 +348,8 @@ cdef inline void sub16(np.uint16_t *dest, np.uint16_t *src):
# colidx - the index of the column to add
#
############################################################################
cdef inline void accumulate_coarse_histogram(Histograms *ph, np.int32_t colidx):
cdef:
int offset
cdef inline void accumulate_coarse_histogram(Histograms *ph, Py_ssize_t colidx):
cdef Py_ssize_t offset
offset = tr_bl_colidx(ph, colidx)
if ph.pixel_count[offset].top_right > 0:
@@ -383,9 +370,8 @@ cdef inline void accumulate_coarse_histogram(Histograms *ph, np.int32_t colidx):
# for a given column
#
############################################################################
cdef inline void deaccumulate_coarse_histogram(Histograms *ph, np.int32_t colidx):
cdef:
int offset
cdef inline void deaccumulate_coarse_histogram(Histograms *ph, Py_ssize_t colidx):
cdef Py_ssize_t offset
#
# The trailing diagonals don't appear until here
#
@@ -414,11 +400,11 @@ cdef inline void deaccumulate_coarse_histogram(Histograms *ph, np.int32_t colidx
#
############################################################################
cdef inline void accumulate_fine_histogram(Histograms *ph,
np.int32_t colidx,
np.uint32_t fineidx):
Py_ssize_t colidx,
Py_ssize_t fineidx):
cdef:
int fineoffset = fineidx * 16
int offset
Py_ssize_t fineoffset = fineidx * 16
Py_ssize_t offset
offset = tr_bl_colidx(ph, colidx)
add16(ph.accumulator.fine + fineoffset,
@@ -438,11 +424,11 @@ cdef inline void accumulate_fine_histogram(Histograms *ph,
#
############################################################################
cdef inline void deaccumulate_fine_histogram(Histograms *ph,
np.int32_t colidx,
np.uint32_t fineidx):
Py_ssize_t colidx,
Py_ssize_t fineidx):
cdef:
int fineoffset = fineidx * 16
int offset
Py_ssize_t fineoffset = fineidx * 16
Py_ssize_t offset
#
# The trailing diagonals don't appear until here
@@ -470,10 +456,7 @@ cdef inline void deaccumulate_fine_histogram(Histograms *ph,
############################################################################
cdef inline void accumulate(Histograms *ph):
cdef:
int i
int j
np.int32_t accumulator
cdef cnp.int32_t accumulator
accumulate_coarse_histogram(ph, ph.current_column)
deaccumulate_coarse_histogram(ph, ph.current_column)
@@ -497,11 +480,11 @@ cdef inline void accumulate(Histograms *ph):
# to choose remains to be done.
############################################################################
cdef inline void update_fine(Histograms *ph, int fineidx):
cdef inline void update_fine(Histograms *ph, Py_ssize_t fineidx):
cdef:
int first_update_column = ph.last_update_column[fineidx]+1
int update_limit = ph.current_column+1
int i
Py_ssize_t first_update_column = ph.last_update_column[fineidx]+1
Py_ssize_t update_limit = ph.current_column+1
Py_ssize_t i
for i in range(first_update_column, update_limit):
accumulate_fine_histogram(ph, i, fineidx)
@@ -526,23 +509,23 @@ cdef inline void update_histogram(Histograms *ph,
SCoord *last_coord,
SCoord *coord):
cdef:
np.int32_t current_column = ph.current_column
np.int32_t current_row = ph.current_row
np.int32_t current_stride = ph.current_stride
np.int32_t column_count = ph.column_count
np.int32_t row_count = ph.row_count
np.uint8_t value
np.int32_t stride
np.int32_t x
np.int32_t y
Py_ssize_t current_column = ph.current_column
Py_ssize_t current_row = ph.current_row
Py_ssize_t current_stride = ph.current_stride
Py_ssize_t column_count = ph.column_count
Py_ssize_t row_count = ph.row_count
cnp.uint8_t value
Py_ssize_t stride
Py_ssize_t x
Py_ssize_t y
x = last_coord.x + current_column
y = last_coord.y + current_row
stride = current_stride+last_coord.stride
if (x >= 0 and x < column_count and
y >= 0 and y < row_count and
ph.mask[stride]):
if (x >= 0 and x < column_count and \
y >= 0 and y < row_count and \
ph.mask[stride]):
value = ph.data[stride]
pixel_count[0] -= 1
hist_piece.fine[value] -= 1
@@ -552,9 +535,9 @@ cdef inline void update_histogram(Histograms *ph,
y = coord.y + current_row
stride = current_stride + coord.stride
if (x >= 0 and x < column_count and
y >= 0 and y < row_count and
ph.mask[stride]):
if (x >= 0 and x < column_count and \
y >= 0 and y < row_count and \
ph.mask[stride]):
value = ph.data[stride]
pixel_count[0] += 1
hist_piece.fine[value] += 1
@@ -567,21 +550,21 @@ cdef inline void update_histogram(Histograms *ph,
############################################################################
cdef inline void update_current_location(Histograms *ph):
cdef:
np.int32_t current_column = ph.current_column
np.int32_t radius = ph.radius
np.int32_t top_left_off = tl_br_colidx(ph, current_column)
np.int32_t top_right_off = tr_bl_colidx(ph, current_column)
np.int32_t bottom_left_off = tr_bl_colidx(ph, current_column)
np.int32_t bottom_right_off = tl_br_colidx(ph, current_column)
np.int32_t leading_edge_off = leading_edge_colidx(ph, current_column)
np.int32_t *coarse_histogram
np.int32_t *fine_histogram
np.int32_t last_xoff
np.int32_t last_yoff
np.int32_t last_stride
np.int32_t xoff
np.int32_t yoff
np.int32_t stride
Py_ssize_t current_column = ph.current_column
Py_ssize_t radius = ph.radius
Py_ssize_t top_left_off = tl_br_colidx(ph, current_column)
Py_ssize_t top_right_off = tr_bl_colidx(ph, current_column)
Py_ssize_t bottom_left_off = tr_bl_colidx(ph, current_column)
Py_ssize_t bottom_right_off = tl_br_colidx(ph, current_column)
Py_ssize_t leading_edge_off = leading_edge_colidx(ph, current_column)
cnp.int32_t *coarse_histogram
cnp.int32_t *fine_histogram
Py_ssize_t last_xoff
Py_ssize_t last_yoff
Py_ssize_t last_stride
Py_ssize_t xoff
Py_ssize_t yoff
Py_ssize_t stride
update_histogram(ph, &ph.histogram[top_left_off].top_left,
&ph.pixel_count[top_left_off].top_left,
@@ -614,18 +597,20 @@ cdef inline void update_current_location(Histograms *ph):
#
############################################################################
cdef inline np.uint8_t find_median(Histograms *ph):
cdef inline cnp.uint8_t find_median(Histograms *ph):
cdef:
np.uint32_t pixels_below # of pixels below the median
int i
int j
int k
np.uint32_t accumulator
Py_ssize_t pixels_below # of pixels below the median
Py_ssize_t i
Py_ssize_t j
Py_ssize_t k
cnp.uint32_t accumulator
if ph.accumulator_count == 0:
return 0
pixels_below = ((ph.accumulator_count * ph.percent + 50)
/ 100) # +50 for roundoff
# +50 for roundoff
pixels_below = (ph.accumulator_count * ph.percent + 50) / 100
if pixels_below > 0:
pixels_below -= 1
@@ -637,10 +622,10 @@ cdef inline np.uint8_t find_median(Histograms *ph):
accumulator -= ph.accumulator.coarse[i]
update_fine(ph, i)
for j in range(i*16,(i+1)*16):
for j in range(i*16, (i + 1)*16):
accumulator += ph.accumulator.fine[j]
if accumulator > pixels_below:
return <np.uint8_t> j
return <cnp.uint8_t>j
return 0
@@ -659,30 +644,30 @@ cdef inline np.uint8_t find_median(Histograms *ph):
# output - array to be filled with filtered pixels
#
############################################################################
cdef int c_median_filter(np.int32_t rows,
np.int32_t columns,
np.int32_t row_stride,
np.int32_t col_stride,
np.int32_t radius,
np.int32_t percent,
np.uint8_t *data,
np.uint8_t *mask,
np.uint8_t *output):
cdef int c_median_filter(Py_ssize_t rows,
Py_ssize_t columns,
Py_ssize_t row_stride,
Py_ssize_t col_stride,
Py_ssize_t radius,
Py_ssize_t percent,
cnp.uint8_t *data,
cnp.uint8_t *mask,
cnp.uint8_t *output):
cdef:
Histograms *ph
Histogram *phistogram
int row
int col
int i
np.int32_t top_left_off
np.int32_t top_right_off
np.int32_t bottom_left_off
np.int32_t bottom_right_off
Py_ssize_t row
Py_ssize_t col
Py_ssize_t i
Py_ssize_t top_left_off
Py_ssize_t top_right_off
Py_ssize_t bottom_left_off
Py_ssize_t bottom_right_off
ph = allocate_histograms(rows, columns, row_stride, col_stride,
radius, percent, data, mask, output)
if not ph:
return 1
return 1
for row in range(-radius, rows):
#
@@ -709,7 +694,7 @@ cdef int c_median_filter(np.int32_t rows,
#
# Initialize the accumulator (octagon histogram) to zero
#
memset(&ph.accumulator, 0, sizeof(ph.accumulator))
memset(&(ph.accumulator), 0, sizeof(ph.accumulator))
ph.accumulator_count = 0
for i in range(16):
ph.last_update_column[i] = -radius-1
@@ -721,7 +706,7 @@ cdef int c_median_filter(np.int32_t rows,
# Update locations and coarse accumulator for the octagon
# for points before 0
#
for col in range(-radius, 0 if row >=0 else columns+radius):
for col in range(-radius, 0 if row >= 0 else columns+radius):
ph.current_column = col
ph.current_stride = row * row_stride + col * col_stride
update_current_location(ph)
@@ -742,16 +727,18 @@ cdef int c_median_filter(np.int32_t rows,
ph.current_stride = row * row_stride + col * col_stride
update_current_location(ph)
free_histograms(ph)
return 0
def median_filter(
np.ndarray[dtype=np.uint8_t, ndim=2, negative_indices=False, mode='c'] data,
np.ndarray[dtype=np.uint8_t, ndim=2, negative_indices=False, mode='c'] mask,
np.ndarray[dtype=np.uint8_t, ndim=2, negative_indices=False, mode='c'] output,
int radius,
np.int32_t percent):
def median_filter(cnp.ndarray[dtype=cnp.uint8_t, ndim=2,
negative_indices=False, mode='c'] data,
cnp.ndarray[dtype=cnp.uint8_t, ndim=2,
negative_indices=False, mode='c'] mask,
cnp.ndarray[dtype=cnp.uint8_t, ndim=2,
negative_indices=False, mode='c'] output,
int radius,
cnp.int32_t percent):
"""Median filter with octagon shape and masking.
Parameters
@@ -773,10 +760,10 @@ def median_filter(
"""
if percent < 0:
raise ValueError('Median filter percent = %d is less than zero' % \
raise ValueError('Median filter percent = %d is less than zero' %
percent)
if percent > 100:
raise ValueError('Median filter percent = %d is greater than 100' % \
raise ValueError('Median filter percent = %d is greater than 100' %
percent)
if data.shape[0] != mask.shape[0] or data.shape[1] != mask.shape[1]:
raise ValueError('Data shape (%d, %d) is not mask shape (%d, %d)' %
@@ -786,10 +773,12 @@ def median_filter(
raise ValueError('Data shape (%d, %d) is not output shape (%d, %d)' %
(data.shape[0], data.shape[1],
output.shape[0], output.shape[1]))
if c_median_filter(data.shape[0], data.shape[1],
data.strides[0], data.strides[1],
if c_median_filter(<cnp.int32_t>data.shape[0],
<cnp.int32_t>data.shape[1],
<cnp.int32_t>data.strides[0],
<cnp.int32_t>data.strides[1],
radius, percent,
<np.uint8_t *>data.data,
<np.uint8_t *>mask.data,
<np.uint8_t *>output.data):
<cnp.uint8_t*>data.data,
<cnp.uint8_t*>mask.data,
<cnp.uint8_t*>output.data):
raise MemoryError('Failed to allocate scratchpad memory')
+3 -3
View File
@@ -32,7 +32,7 @@ def _denoise_tv_chambolle_3d(im, weight=100, eps=2.e-4, n_iter_max=200):
Rudin, Osher and Fatemi algorithm.
Examples
---------
--------
>>> x, y, z = np.ogrid[0:40, 0:40, 0:40]
>>> mask = (x - 22)**2 + (y - 20)**2 + (z - 17)**2 < 8**2
>>> mask = mask.astype(np.float)
@@ -123,7 +123,7 @@ def _denoise_tv_chambolle_2d(im, weight=50, eps=2.e-4, n_iter_max=200):
Springer, 2004, 20, 89-97.
Examples
---------
--------
>>> from skimage import color, data
>>> lena = color.rgb2gray(data.lena())
>>> lena += 0.5 * lena.std() * np.random.randn(*lena.shape)
@@ -221,7 +221,7 @@ def denoise_tv_chambolle(im, weight=50, eps=2.e-4, n_iter_max=200,
Springer, 2004, 20, 89-97.
Examples
---------
--------
2D example on Lena image:
>>> from skimage import color, data
+5 -5
View File
@@ -17,7 +17,7 @@ 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* _compute_color_lut(Py_ssize_t bins, double sigma, double max_value):
cdef:
double* color_lut = <double*>malloc(bins * sizeof(double))
@@ -29,7 +29,7 @@ cdef double* _compute_color_lut(int bins, double sigma, double max_value):
return color_lut
cdef double* _compute_range_lut(int win_size, double sigma):
cdef double* _compute_range_lut(Py_ssize_t win_size, double sigma):
cdef:
double* range_lut = <double*>malloc(win_size**2 * sizeof(double))
@@ -45,9 +45,9 @@ cdef double* _compute_range_lut(int win_size, double sigma):
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):
def denoise_bilateral(image, Py_ssize_t win_size=5, sigma_range=None,
double sigma_spatial=1, Py_ssize_t bins=10000,
mode='constant', double cval=0):
"""Denoise image using bilateral filter.
This is an edge-preserving and noise reducing denoising filter. It averages
+11 -8
View File
@@ -1,4 +1,7 @@
cimport numpy as np
cimport numpy as cnp
ctypedef cnp.uint16_t dtype_t
cdef int int_max(int a, int b)
@@ -6,12 +9,12 @@ cdef int int_min(int a, int b)
# 16-bit core kernel receives extra information about data bitdepth
cdef void _core16(np.uint16_t kernel(Py_ssize_t *, float, np.uint16_t,
Py_ssize_t, Py_ssize_t, Py_ssize_t, float,
float, Py_ssize_t, Py_ssize_t),
np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask,
np.ndarray[np.uint16_t, ndim=2] out,
cdef void _core16(dtype_t kernel(Py_ssize_t *, float, dtype_t,
Py_ssize_t, Py_ssize_t, Py_ssize_t, float,
float, Py_ssize_t, Py_ssize_t),
cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask,
cnp.ndarray[dtype_t, ndim=2] out,
char shift_x, char shift_y, Py_ssize_t bitdepth,
float p0, float p1, Py_ssize_t s0, Py_ssize_t s1) except *
+14 -13
View File
@@ -4,7 +4,8 @@
#cython: wraparound=False
import numpy as np
cimport numpy as np
cimport numpy as cnp
from libc.stdlib cimport malloc, free
from _core8 cimport is_in_mask
@@ -18,24 +19,24 @@ cdef inline int int_min(int a, int b):
cdef inline void histogram_increment(Py_ssize_t * histo, float * pop,
np.uint16_t value):
dtype_t value):
histo[value] += 1
pop[0] += 1
cdef inline void histogram_decrement(Py_ssize_t * histo, float * pop,
np.uint16_t value):
dtype_t value):
histo[value] -= 1
pop[0] -= 1
cdef void _core16(np.uint16_t kernel(Py_ssize_t *, float, np.uint16_t,
Py_ssize_t, Py_ssize_t, Py_ssize_t, float,
float, Py_ssize_t, Py_ssize_t),
np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask,
np.ndarray[np.uint16_t, ndim=2] out,
cdef void _core16(dtype_t kernel(Py_ssize_t *, float, dtype_t,
Py_ssize_t, Py_ssize_t, Py_ssize_t, float,
float, Py_ssize_t, Py_ssize_t),
cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask,
cnp.ndarray[dtype_t, ndim=2] out,
char shift_x, char shift_y, Py_ssize_t bitdepth,
float p0, float p1, Py_ssize_t s0, Py_ssize_t s1) except *:
"""Compute histogram for each pixel neighborhood, apply kernel function and
@@ -67,9 +68,9 @@ cdef void _core16(np.uint16_t kernel(Py_ssize_t *, float, np.uint16_t,
assert (image < maxbin).all()
# define pointers to the data
cdef np.uint16_t * out_data = <np.uint16_t * >out.data
cdef np.uint16_t * image_data = <np.uint16_t * >image.data
cdef np.uint8_t * mask_data = <np.uint8_t * >mask.data
cdef dtype_t * out_data = <dtype_t * >out.data
cdef dtype_t * image_data = <dtype_t * >image.data
cdef cnp.uint8_t * mask_data = <cnp.uint8_t * >mask.data
# define local variable types
cdef Py_ssize_t r, c, rr, cc, s, value, local_max, i, even_row
+15 -12
View File
@@ -1,22 +1,25 @@
cimport numpy as np
cimport numpy as cnp
cdef np.uint8_t uint8_max(np.uint8_t a, np.uint8_t b)
cdef np.uint8_t uint8_min(np.uint8_t a, np.uint8_t b)
ctypedef cnp.uint8_t dtype_t
cdef np.uint8_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols,
Py_ssize_t r, Py_ssize_t c,
np.uint8_t * mask)
cdef dtype_t uint8_max(dtype_t a, dtype_t b)
cdef dtype_t uint8_min(dtype_t a, dtype_t b)
cdef dtype_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols,
Py_ssize_t r, Py_ssize_t c,
dtype_t * mask)
# 8-bit core kernel receives extra information about data inferior and superior
# percentiles
cdef void _core8(np.uint8_t kernel(Py_ssize_t *, float, np.uint8_t, float,
float, Py_ssize_t, Py_ssize_t),
np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask,
np.ndarray[np.uint8_t, ndim=2] out,
cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float,
float, Py_ssize_t, Py_ssize_t),
cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask,
cnp.ndarray[dtype_t, ndim=2] out,
char shift_x, char shift_y, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1) except *
+18 -17
View File
@@ -4,33 +4,34 @@
#cython: wraparound=False
import numpy as np
cimport numpy as np
cimport numpy as cnp
from libc.stdlib cimport malloc, free
cdef inline np.uint8_t uint8_max(np.uint8_t a, np.uint8_t b):
cdef inline dtype_t uint8_max(dtype_t a, dtype_t b):
return a if a >= b else b
cdef inline np.uint8_t uint8_min(np.uint8_t a, np.uint8_t b):
cdef inline dtype_t uint8_min(dtype_t a, dtype_t b):
return a if a <= b else b
cdef inline void histogram_increment(Py_ssize_t * histo, float * pop,
np.uint8_t value):
dtype_t value):
histo[value] += 1
pop[0] += 1
cdef inline void histogram_decrement(Py_ssize_t * histo, float * pop,
np.uint8_t value):
dtype_t value):
histo[value] -= 1
pop[0] -= 1
cdef inline np.uint8_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols,
Py_ssize_t r, Py_ssize_t c,
np.uint8_t * mask):
cdef inline dtype_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols,
Py_ssize_t r, Py_ssize_t c,
dtype_t * mask):
"""Check whether given coordinate is within image and mask is true."""
if r < 0 or r > rows - 1 or c < 0 or c > cols - 1:
return 0
@@ -41,12 +42,12 @@ cdef inline np.uint8_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols,
return 0
cdef void _core8(np.uint8_t kernel(Py_ssize_t *, float, np.uint8_t, float,
float, Py_ssize_t, Py_ssize_t),
np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask,
np.ndarray[np.uint8_t, ndim=2] out,
cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float,
float, Py_ssize_t, Py_ssize_t),
cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask,
cnp.ndarray[dtype_t, ndim=2] out,
char shift_x, char shift_y, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1) except *:
"""Compute histogram for each pixel neighborhood, apply kernel function and
@@ -69,9 +70,9 @@ cdef void _core8(np.uint8_t kernel(Py_ssize_t *, float, np.uint8_t, float,
# define pointers to the data
cdef np.uint8_t * out_data = <np.uint8_t * >out.data
cdef np.uint8_t * image_data = <np.uint8_t * >image.data
cdef np.uint8_t * mask_data = <np.uint8_t * >mask.data
cdef dtype_t * out_data = <dtype_t * >out.data
cdef dtype_t * image_data = <dtype_t * >image.data
cdef dtype_t * mask_data = <dtype_t * >mask.data
# define local variable types
cdef Py_ssize_t r, c, rr, cc, s, value, local_max, i, even_row
+177 -175
View File
@@ -3,9 +3,8 @@
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
cimport numpy as np
from libc.math cimport log2
cimport numpy as cnp
from libc.math cimport log
from skimage.filter.rank._core16 cimport _core16
@@ -14,11 +13,14 @@ from skimage.filter.rank._core16 cimport _core16
# -----------------------------------------------------------------
cdef inline np.uint16_t kernel_autolevel(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
ctypedef cnp.uint16_t dtype_t
cdef inline dtype_t kernel_autolevel(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i, imin, imax, delta
if pop:
@@ -32,16 +34,16 @@ cdef inline np.uint16_t kernel_autolevel(Py_ssize_t * histo, float pop,
break
delta = imax - imin
if delta > 0:
return < np.uint16_t > (1. * (maxbin - 1) * (g - imin) / delta)
return <dtype_t>(1. * (maxbin - 1) * (g - imin) / delta)
else:
return < np.uint16_t > (imax - imin)
return <dtype_t>(imax - imin)
cdef inline np.uint16_t kernel_bottomhat(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_bottomhat(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
if pop:
@@ -49,15 +51,15 @@ cdef inline np.uint16_t kernel_bottomhat(Py_ssize_t * histo, float pop,
if histo[i]:
break
return < np.uint16_t > (g - i)
return <dtype_t>(g - i)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_equalize(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_equalize(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef float sum = 0.
@@ -67,16 +69,16 @@ cdef inline np.uint16_t kernel_equalize(Py_ssize_t * histo, float pop,
if i >= g:
break
return < np.uint16_t > (((maxbin - 1) * sum) / pop)
return <dtype_t>(((maxbin - 1) * sum) / pop)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_gradient(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_gradient(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i, imin, imax
if pop:
@@ -88,66 +90,66 @@ cdef inline np.uint16_t kernel_gradient(Py_ssize_t * histo, float pop,
if histo[i]:
imin = i
break
return < np.uint16_t > (imax - imin)
return <dtype_t>(imax - imin)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_maximum(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_maximum(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
if pop:
for i in range(maxbin - 1, -1, -1):
if histo[i]:
return < np.uint16_t > (i)
return <dtype_t>(i)
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_mean(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_mean(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef float mean = 0.
if pop:
for i in range(maxbin):
mean += histo[i] * i
return < np.uint16_t > (mean / pop)
return <dtype_t>(mean / pop)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_meansubstraction(Py_ssize_t * histo,
float pop,
np.uint16_t g,
Py_ssize_t bitdepth,
Py_ssize_t maxbin,
Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_meansubstraction(Py_ssize_t * histo,
float pop,
dtype_t g,
Py_ssize_t bitdepth,
Py_ssize_t maxbin,
Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef float mean = 0.
if pop:
for i in range(maxbin):
mean += histo[i] * i
return < np.uint16_t > ((g - mean / pop) / 2. + (midbin - 1))
return <dtype_t>((g - mean / pop) / 2. + (midbin - 1))
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_median(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_median(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef float sum = pop / 2.0
@@ -156,31 +158,31 @@ cdef inline np.uint16_t kernel_median(Py_ssize_t * histo, float pop,
if histo[i]:
sum -= histo[i]
if sum < 0:
return < np.uint16_t > (i)
return <dtype_t>(i)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_minimum(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_minimum(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
if pop:
for i in range(maxbin):
if histo[i]:
return < np.uint16_t > (i)
return <dtype_t>(i)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_modal(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_modal(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t hmax = 0, imax = 0
if pop:
@@ -188,19 +190,19 @@ cdef inline np.uint16_t kernel_modal(Py_ssize_t * histo, float pop,
if histo[i] > hmax:
hmax = histo[i]
imax = i
return < np.uint16_t > (imax)
return <dtype_t>(imax)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_morph_contr_enh(Py_ssize_t * histo,
float pop,
np.uint16_t g,
Py_ssize_t bitdepth,
Py_ssize_t maxbin,
Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t * histo,
float pop,
dtype_t g,
Py_ssize_t bitdepth,
Py_ssize_t maxbin,
Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i, imin, imax
if pop:
@@ -213,42 +215,42 @@ cdef inline np.uint16_t kernel_morph_contr_enh(Py_ssize_t * histo,
imin = i
break
if imax - g < g - imin:
return < np.uint16_t > (imax)
return <dtype_t>(imax)
else:
return < np.uint16_t > (imin)
return <dtype_t>(imin)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_pop(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
return < np.uint16_t > (pop)
cdef inline dtype_t kernel_pop(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
return <dtype_t>(pop)
cdef inline np.uint16_t kernel_threshold(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_threshold(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef float mean = 0.
if pop:
for i in range(maxbin):
mean += histo[i] * i
return < np.uint16_t > (g > (mean / pop))
return <dtype_t>(g > (mean / pop))
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_tophat(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_tophat(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
if pop:
@@ -256,15 +258,15 @@ cdef inline np.uint16_t kernel_tophat(Py_ssize_t * histo, float pop,
if histo[i]:
break
return < np.uint16_t > (i - g)
return <dtype_t>(i - g)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_entropy(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_entropy(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef float e, p
@@ -274,147 +276,147 @@ cdef inline np.uint16_t kernel_entropy(Py_ssize_t * histo, float pop,
for i in range(maxbin):
p = histo[i] / pop
if p > 0:
e -= p * log2(p)
e -= p * log(p) / 0.6931471805599453
return < np.uint16_t > e * 1000
return <dtype_t>e * 1000
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
# -----------------------------------------------------------------
# python wrappers
# -----------------------------------------------------------------
def autolevel(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def autolevel(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
_core16(kernel_autolevel, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def bottomhat(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def bottomhat(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
_core16(kernel_bottomhat, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def equalize(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def equalize(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
_core16(kernel_equalize, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def gradient(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def gradient(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
_core16(kernel_gradient, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def maximum(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def maximum(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
_core16(kernel_maximum, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def mean(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def mean(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
_core16(kernel_mean, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def meansubstraction(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def meansubstraction(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
_core16(kernel_meansubstraction, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def median(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def median(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
_core16(kernel_median, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def minimum(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def minimum(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
_core16(kernel_minimum, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def morph_contr_enh(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def morph_contr_enh(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
_core16(kernel_morph_contr_enh, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def modal(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def modal(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
_core16(kernel_modal, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def pop(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def pop(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
_core16(kernel_pop, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def threshold(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def threshold(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
_core16(kernel_threshold, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def tophat(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def tophat(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
_core16(kernel_tophat, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def entropy(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def entropy(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
_core16(kernel_entropy, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
+27 -25
View File
@@ -3,8 +3,7 @@
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
cimport numpy as np
cimport numpy as cnp
from skimage.filter.rank._core16 cimport _core16
@@ -13,11 +12,14 @@ from skimage.filter.rank._core16 cimport _core16
# -----------------------------------------------------------------
cdef inline np.uint16_t kernel_mean(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
ctypedef cnp.uint16_t dtype_t
cdef inline dtype_t kernel_mean(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, bilat_pop = 0
cdef float mean = 0.
@@ -28,18 +30,18 @@ cdef inline np.uint16_t kernel_mean(Py_ssize_t * histo, float pop,
bilat_pop += histo[i]
mean += histo[i] * i
if bilat_pop:
return < np.uint16_t > (mean / bilat_pop)
return <dtype_t>(mean / bilat_pop)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_pop(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_pop(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, bilat_pop = 0
@@ -47,9 +49,9 @@ cdef inline np.uint16_t kernel_pop(Py_ssize_t * histo, float pop,
for i in range(maxbin):
if (g > (i - s0)) and (g < (i + s1)):
bilat_pop += histo[i]
return < np.uint16_t > (bilat_pop)
return <dtype_t>(bilat_pop)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
# -----------------------------------------------------------------
@@ -57,10 +59,10 @@ cdef inline np.uint16_t kernel_pop(Py_ssize_t * histo, float pop,
# -----------------------------------------------------------------
def mean(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def mean(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8, int s0=1, int s1=1):
"""average greylevel (clipped on uint8)
"""
@@ -68,10 +70,10 @@ def mean(np.ndarray[np.uint16_t, ndim=2] image,
bitdepth, 0., 0., s0, s1)
def pop(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def pop(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8, int s0=1, int s1=1):
"""returns the number of actual pixels of the structuring element inside
the mask
+106 -103
View File
@@ -3,8 +3,7 @@
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
cimport numpy as np
cimport numpy as cnp
from skimage.filter.rank._core16 cimport _core16, int_min, int_max
@@ -13,11 +12,14 @@ from skimage.filter.rank._core16 cimport _core16, int_min, int_max
# -----------------------------------------------------------------
cdef inline np.uint16_t kernel_autolevel(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
ctypedef cnp.uint16_t dtype_t
cdef inline dtype_t kernel_autolevel(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, imin, imax, sum, delta
@@ -38,19 +40,20 @@ cdef inline np.uint16_t kernel_autolevel(Py_ssize_t * histo, float pop,
delta = imax - imin
if delta > 0:
return < np.uint16_t > (1.0 * (maxbin - 1)
* (int_min(int_max(imin, g), imax) - imin) / delta)
return <dtype_t>(1.0 * (maxbin - 1)
* (int_min(int_max(imin, g), imax)
- imin) / delta)
else:
return < np.uint16_t > (imax - imin)
return <dtype_t>(imax - imin)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_gradient(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_gradient(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, imin, imax, sum, delta
@@ -69,16 +72,16 @@ cdef inline np.uint16_t kernel_gradient(Py_ssize_t * histo, float pop,
imax = i
break
return < np.uint16_t > (imax - imin)
return <dtype_t>(imax - imin)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_mean(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_mean(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, sum, mean, n
@@ -93,21 +96,21 @@ cdef inline np.uint16_t kernel_mean(Py_ssize_t * histo, float pop,
mean += histo[i] * i
if n > 0:
return < np.uint16_t > (1.0 * mean / n)
return <dtype_t>(1.0 * mean / n)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_mean_substraction(Py_ssize_t * histo,
float pop,
np.uint16_t g,
Py_ssize_t bitdepth,
Py_ssize_t maxbin,
Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_mean_substraction(Py_ssize_t * histo,
float pop,
dtype_t g,
Py_ssize_t bitdepth,
Py_ssize_t maxbin,
Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, sum, mean, n
@@ -121,21 +124,21 @@ cdef inline np.uint16_t kernel_mean_substraction(Py_ssize_t * histo,
n += histo[i]
mean += histo[i] * i
if n > 0:
return < np.uint16_t > ((g - (mean / n)) * .5 + midbin)
return <dtype_t>((g - (mean / n)) * .5 + midbin)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_morph_contr_enh(Py_ssize_t * histo,
float pop,
np.uint16_t g,
Py_ssize_t bitdepth,
Py_ssize_t maxbin,
Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t * histo,
float pop,
dtype_t g,
Py_ssize_t bitdepth,
Py_ssize_t maxbin,
Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, imin, imax, sum, delta
@@ -154,22 +157,22 @@ cdef inline np.uint16_t kernel_morph_contr_enh(Py_ssize_t * histo,
imax = i
break
if g > imax:
return < np.uint16_t > imax
return <dtype_t>imax
if g < imin:
return < np.uint16_t > imin
return <dtype_t>imin
if imax - g < g - imin:
return < np.uint16_t > imax
return <dtype_t>imax
else:
return < np.uint16_t > imin
return <dtype_t>imin
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_percentile(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_percentile(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i
cdef float sum = 0.
@@ -180,16 +183,16 @@ cdef inline np.uint16_t kernel_percentile(Py_ssize_t * histo, float pop,
if sum >= p0 * pop:
break
return < np.uint16_t > (i)
return <dtype_t>(i)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_pop(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_pop(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, sum, n
@@ -200,16 +203,16 @@ cdef inline np.uint16_t kernel_pop(Py_ssize_t * histo, float pop,
sum += histo[i]
if (sum >= p0 * pop) and (sum <= p1 * pop):
n += histo[i]
return < np.uint16_t > (n)
return <dtype_t>(n)
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
cdef inline np.uint16_t kernel_threshold(Py_ssize_t * histo, float pop,
np.uint16_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_threshold(Py_ssize_t * histo, float pop,
dtype_t g, Py_ssize_t bitdepth,
Py_ssize_t maxbin, Py_ssize_t midbin,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i
cdef float sum = 0.
@@ -220,9 +223,9 @@ cdef inline np.uint16_t kernel_threshold(Py_ssize_t * histo, float pop,
if sum >= p0 * pop:
break
return < np.uint16_t > ((maxbin - 1) * (g >= i))
return <dtype_t>((maxbin - 1) * (g >= i))
else:
return < np.uint16_t > (0)
return <dtype_t>(0)
# -----------------------------------------------------------------
@@ -230,10 +233,10 @@ cdef inline np.uint16_t kernel_threshold(Py_ssize_t * histo, float pop,
# -----------------------------------------------------------------
def autolevel(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def autolevel(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8,
float p0=0., float p1=0.):
"""bottom hat
@@ -242,10 +245,10 @@ def autolevel(np.ndarray[np.uint16_t, ndim=2] image,
bitdepth, p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def gradient(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def gradient(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8,
float p0=0., float p1=0.):
"""return p0,p1 percentile gradient
@@ -254,10 +257,10 @@ def gradient(np.ndarray[np.uint16_t, ndim=2] image,
bitdepth, p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def mean(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def mean(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8,
float p0=0., float p1=0.):
"""return mean between [p0 and p1] percentiles
@@ -266,10 +269,10 @@ def mean(np.ndarray[np.uint16_t, ndim=2] image,
bitdepth, p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def mean_substraction(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def mean_substraction(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8,
float p0=0., float p1=0.):
"""return original - mean between [p0 and p1] percentiles *.5 +127
@@ -279,10 +282,10 @@ def mean_substraction(np.ndarray[np.uint16_t, ndim=2] image,
bitdepth, p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def morph_contr_enh(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def morph_contr_enh(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8,
float p0=0., float p1=0.):
"""reforce contrast using percentiles
@@ -291,10 +294,10 @@ def morph_contr_enh(np.ndarray[np.uint16_t, ndim=2] image,
bitdepth, p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def percentile(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def percentile(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8,
float p0=0., float p1=0.):
"""return p0 percentile
@@ -303,10 +306,10 @@ def percentile(np.ndarray[np.uint16_t, ndim=2] image,
bitdepth, p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def pop(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def pop(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8,
float p0=0., float p1=0.):
"""return nb of pixels between [p0 and p1]
@@ -315,10 +318,10 @@ def pop(np.ndarray[np.uint16_t, ndim=2] image,
bitdepth, p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def threshold(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
def threshold(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[cnp.uint8_t, ndim=2] selem,
cnp.ndarray[cnp.uint8_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8,
float p0=0., float p1=0.):
"""return (maxbin-1) if g > percentile p0
+161 -159
View File
@@ -3,9 +3,8 @@
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
cimport numpy as np
from libc.math cimport log2
cimport numpy as cnp
from libc.math cimport log
from skimage.filter.rank._core8 cimport _core8
@@ -14,9 +13,12 @@ from skimage.filter.rank._core8 cimport _core8
# -----------------------------------------------------------------
cdef inline np.uint8_t kernel_autolevel(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
ctypedef cnp.uint8_t dtype_t
cdef inline dtype_t kernel_autolevel(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i, imin, imax, delta
@@ -31,16 +33,16 @@ cdef inline np.uint8_t kernel_autolevel(Py_ssize_t * histo, float pop,
break
delta = imax - imin
if delta > 0:
return < np.uint8_t > (255. * (g - imin) / delta)
return <dtype_t>(255. * (g - imin) / delta)
else:
return < np.uint8_t > (imax - imin)
return <dtype_t>(imax - imin)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_bottomhat(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_bottomhat(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
@@ -49,14 +51,14 @@ cdef inline np.uint8_t kernel_bottomhat(Py_ssize_t * histo, float pop,
if histo[i]:
break
return < np.uint8_t > (g - i)
return <dtype_t>(g - i)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_equalize(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_equalize(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef float sum = 0.
@@ -67,14 +69,14 @@ cdef inline np.uint8_t kernel_equalize(Py_ssize_t * histo, float pop,
if i >= g:
break
return < np.uint8_t > ((255 * sum) / pop)
return <dtype_t>((255 * sum) / pop)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_gradient(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_gradient(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i, imin, imax
@@ -87,28 +89,28 @@ cdef inline np.uint8_t kernel_gradient(Py_ssize_t * histo, float pop,
if histo[i]:
imin = i
break
return < np.uint8_t > (imax - imin)
return <dtype_t>(imax - imin)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_maximum(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_maximum(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
if pop:
for i in range(255, -1, -1):
if histo[i]:
return < np.uint8_t > (i)
return <dtype_t>(i)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_mean(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_mean(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef float mean = 0.
@@ -116,14 +118,14 @@ cdef inline np.uint8_t kernel_mean(Py_ssize_t * histo, float pop,
if pop:
for i in range(256):
mean += histo[i] * i
return < np.uint8_t > (mean / pop)
return <dtype_t>(mean / pop)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_meansubstraction(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_meansubstraction(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef float mean = 0.
@@ -131,14 +133,14 @@ cdef inline np.uint8_t kernel_meansubstraction(Py_ssize_t * histo, float pop,
if pop:
for i in range(256):
mean += histo[i] * i
return < np.uint8_t > ((g - mean / pop) / 2. + 127)
return <dtype_t>((g - mean / pop) / 2. + 127)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_median(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_median(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef float sum = pop / 2.0
@@ -148,28 +150,28 @@ cdef inline np.uint8_t kernel_median(Py_ssize_t * histo, float pop,
if histo[i]:
sum -= histo[i]
if sum < 0:
return < np.uint8_t > (i)
return <dtype_t>(i)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_minimum(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_minimum(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
if pop:
for i in range(256):
if histo[i]:
return < np.uint8_t > (i)
return <dtype_t>(i)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_modal(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_modal(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t hmax = 0, imax = 0
@@ -178,14 +180,14 @@ cdef inline np.uint8_t kernel_modal(Py_ssize_t * histo, float pop,
if histo[i] > hmax:
hmax = histo[i]
imax = i
return < np.uint8_t > (imax)
return <dtype_t>(imax)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_morph_contr_enh(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i, imin, imax
@@ -199,23 +201,23 @@ cdef inline np.uint8_t kernel_morph_contr_enh(Py_ssize_t * histo, float pop,
imin = i
break
if imax - g < g - imin:
return < np.uint8_t > (imax)
return <dtype_t>(imax)
else:
return < np.uint8_t > (imin)
return <dtype_t>(imin)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_pop(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_pop(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
return < np.uint8_t > (pop)
return <dtype_t>(pop)
cdef inline np.uint8_t kernel_threshold(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_threshold(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef float mean = 0.
@@ -223,14 +225,14 @@ cdef inline np.uint8_t kernel_threshold(Py_ssize_t * histo, float pop,
if pop:
for i in range(256):
mean += histo[i] * i
return < np.uint8_t > (g > (mean / pop))
return <dtype_t>(g > (mean / pop))
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_tophat(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_tophat(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
@@ -239,20 +241,20 @@ cdef inline np.uint8_t kernel_tophat(Py_ssize_t * histo, float pop,
if histo[i]:
break
return < np.uint8_t > (i - g)
return <dtype_t>(i - g)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_noise_filter(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_noise_filter(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef Py_ssize_t min_i
# early stop if at least one pixel of the neighborhood has the same g
if histo[g] > 0:
return < np.uint8_t > 0
return <dtype_t>0
for i in range(g, -1, -1):
if histo[i]:
@@ -262,14 +264,14 @@ cdef inline np.uint8_t kernel_noise_filter(Py_ssize_t * histo, float pop,
if histo[i]:
break
if i - g < min_i:
return < np.uint8_t > (i - g)
return <dtype_t>(i - g)
else:
return < np.uint8_t > min_i
return <dtype_t>min_i
cdef inline np.uint8_t kernel_entropy(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_entropy(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef float e, p
@@ -279,15 +281,15 @@ cdef inline np.uint8_t kernel_entropy(Py_ssize_t * histo, float pop,
for i in range(256):
p = histo[i] / pop
if p > 0:
e -= p * log2(p)
e -= p * log(p) / 0.6931471805599453
return < np.uint8_t > e * 10
return <dtype_t>e * 10
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_otsu(Py_ssize_t * histo, float pop, np.uint8_t g,
float p0, float p1, Py_ssize_t s0,
Py_ssize_t s1):
cdef inline dtype_t kernel_otsu(Py_ssize_t * histo, float pop, dtype_t g,
float p0, float p1, Py_ssize_t s0,
Py_ssize_t s1):
cdef Py_ssize_t i
cdef Py_ssize_t max_i
cdef float P, mu1, mu2, q1, new_q1, sigma_b, max_sigma_b
@@ -299,7 +301,7 @@ cdef inline np.uint8_t kernel_otsu(Py_ssize_t * histo, float pop, np.uint8_t g,
mu += histo[i] * i
mu = (mu / pop)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
# maximizing the between class variance
max_i = 0
@@ -319,7 +321,7 @@ cdef inline np.uint8_t kernel_otsu(Py_ssize_t * histo, float pop, np.uint8_t g,
max_i = i
q1 = new_q1
return < np.uint8_t > max_i
return <dtype_t>max_i
# -----------------------------------------------------------------
@@ -328,154 +330,154 @@ cdef inline np.uint8_t kernel_otsu(Py_ssize_t * histo, float pop, np.uint8_t g,
# -----------------------------------------------------------------
def autolevel(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def autolevel(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
_core8(kernel_autolevel, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def bottomhat(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def bottomhat(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
_core8(kernel_bottomhat, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def equalize(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def equalize(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
_core8(kernel_equalize, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def gradient(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def gradient(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
_core8(kernel_gradient, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def maximum(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def maximum(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
_core8(kernel_maximum, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def mean(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def mean(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
_core8(kernel_mean, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def meansubstraction(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def meansubstraction(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
_core8(kernel_meansubstraction, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def median(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def median(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
_core8(kernel_median, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def minimum(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def minimum(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
_core8(kernel_minimum, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def morph_contr_enh(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def morph_contr_enh(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
_core8(kernel_morph_contr_enh, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def modal(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def modal(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
_core8(kernel_modal, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def pop(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def pop(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
_core8(kernel_pop, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def threshold(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def threshold(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
_core8(kernel_threshold, image, selem, mask, out, shift_x, shift_y, 0, 0,
<Py_ssize_t>0, <Py_ssize_t>0)
def tophat(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def tophat(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
_core8(kernel_tophat, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def noise_filter(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def noise_filter(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
_core8(kernel_noise_filter, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def entropy(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def entropy(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
_core8(kernel_entropy, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def otsu(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def otsu(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
_core8(kernel_otsu, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
+86 -84
View File
@@ -3,8 +3,7 @@
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
cimport numpy as np
cimport numpy as cnp
from skimage.filter.rank._core8 cimport _core8, uint8_max, uint8_min
@@ -13,9 +12,12 @@ from skimage.filter.rank._core8 cimport _core8, uint8_max, uint8_min
# -----------------------------------------------------------------
cdef inline np.uint8_t kernel_autolevel(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
ctypedef cnp.uint8_t dtype_t
cdef inline dtype_t kernel_autolevel(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, imin, imax, sum, delta
if pop:
@@ -37,17 +39,17 @@ cdef inline np.uint8_t kernel_autolevel(Py_ssize_t * histo, float pop,
break
delta = imax - imin
if delta > 0:
return < np.uint8_t > (255
* (uint8_min(uint8_max(imin, g), imax) - imin) / delta)
return <dtype_t>(255 * (uint8_min(uint8_max(imin, g), imax)
- imin) / delta)
else:
return < np.uint8_t > (imax - imin)
return <dtype_t>(imax - imin)
else:
return < np.uint8_t > (128)
return <dtype_t>(128)
cdef inline np.uint8_t kernel_gradient(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_gradient(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, imin, imax, sum, delta
if pop:
@@ -65,14 +67,14 @@ cdef inline np.uint8_t kernel_gradient(Py_ssize_t * histo, float pop,
imax = i
break
return < np.uint8_t > (imax - imin)
return <dtype_t>(imax - imin)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_mean(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_mean(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, sum, mean, n
if pop:
@@ -85,18 +87,18 @@ cdef inline np.uint8_t kernel_mean(Py_ssize_t * histo, float pop,
n += histo[i]
mean += histo[i] * i
if n > 0:
return < np.uint8_t > (1.0 * mean / n)
return <dtype_t>(1.0 * mean / n)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_mean_substraction(Py_ssize_t * histo,
float pop,
np.uint8_t g,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_mean_substraction(Py_ssize_t * histo,
float pop,
dtype_t g,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, sum, mean, n
if pop:
@@ -109,17 +111,17 @@ cdef inline np.uint8_t kernel_mean_substraction(Py_ssize_t * histo,
n += histo[i]
mean += histo[i] * i
if n > 0:
return < np.uint8_t > ((g - (mean / n)) * .5 + 127)
return <dtype_t>((g - (mean / n)) * .5 + 127)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_morph_contr_enh(Py_ssize_t * histo,
float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t * histo,
float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, imin, imax, sum, delta
if pop:
@@ -137,20 +139,20 @@ cdef inline np.uint8_t kernel_morph_contr_enh(Py_ssize_t * histo,
imax = i
break
if g > imax:
return < np.uint8_t > imax
return <dtype_t>imax
if g < imin:
return < np.uint8_t > imin
return <dtype_t>imin
if imax - g < g - imin:
return < np.uint8_t > imax
return <dtype_t>imax
else:
return < np.uint8_t > imin
return <dtype_t>imin
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_percentile(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_percentile(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i
cdef float sum = 0.
@@ -160,14 +162,14 @@ cdef inline np.uint8_t kernel_percentile(Py_ssize_t * histo, float pop,
if sum >= p0 * pop:
break
return < np.uint8_t > (i)
return <dtype_t>(i)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_pop(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_pop(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, sum, n
if pop:
@@ -177,14 +179,14 @@ cdef inline np.uint8_t kernel_pop(Py_ssize_t * histo, float pop,
sum += histo[i]
if (sum >= p0 * pop) and (sum <= p1 * pop):
n += histo[i]
return < np.uint8_t > (n)
return <dtype_t>(n)
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
cdef inline np.uint8_t kernel_threshold(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline dtype_t kernel_threshold(Py_ssize_t * histo, float pop,
dtype_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i
cdef float sum = 0.
@@ -194,9 +196,9 @@ cdef inline np.uint8_t kernel_threshold(Py_ssize_t * histo, float pop,
if sum >= p0 * pop:
break
return < np.uint8_t > (255 * (g >= i))
return <dtype_t>(255 * (g >= i))
else:
return < np.uint8_t > (0)
return <dtype_t>(0)
# -----------------------------------------------------------------
@@ -204,10 +206,10 @@ cdef inline np.uint8_t kernel_threshold(Py_ssize_t * histo, float pop,
# -----------------------------------------------------------------
def autolevel(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def autolevel(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, float p0=0., float p1=0.):
"""autolevel
"""
@@ -215,10 +217,10 @@ def autolevel(np.ndarray[np.uint8_t, ndim=2] image,
<Py_ssize_t>0, <Py_ssize_t>0)
def gradient(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def gradient(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, float p0=0., float p1=0.):
"""return p0,p1 percentile gradient
"""
@@ -226,10 +228,10 @@ def gradient(np.ndarray[np.uint8_t, ndim=2] image,
<Py_ssize_t>0, <Py_ssize_t>0)
def mean(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def mean(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, float p0=0., float p1=0.):
"""return mean between [p0 and p1] percentiles
"""
@@ -237,10 +239,10 @@ def mean(np.ndarray[np.uint8_t, ndim=2] image,
<Py_ssize_t>0, <Py_ssize_t>0)
def mean_substraction(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def mean_substraction(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, float p0=0., float p1=0.):
"""return original - mean between [p0 and p1] percentiles *.5 +127
"""
@@ -248,10 +250,10 @@ def mean_substraction(np.ndarray[np.uint8_t, ndim=2] image,
p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def morph_contr_enh(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def morph_contr_enh(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, float p0=0., float p1=0.):
"""reforce contrast using percentiles
"""
@@ -259,10 +261,10 @@ def morph_contr_enh(np.ndarray[np.uint8_t, ndim=2] image,
p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def percentile(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def percentile(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, float p0=0., float p1=0.):
"""return p0 percentile
"""
@@ -270,10 +272,10 @@ def percentile(np.ndarray[np.uint8_t, ndim=2] image,
p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def pop(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def pop(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, float p0=0., float p1=0.):
"""return nb of pixels between [p0 and p1]
"""
@@ -281,10 +283,10 @@ def pop(np.ndarray[np.uint8_t, ndim=2] image,
<Py_ssize_t>0, <Py_ssize_t>0)
def threshold(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
def threshold(cnp.ndarray[dtype_t, ndim=2] image,
cnp.ndarray[dtype_t, ndim=2] selem,
cnp.ndarray[dtype_t, ndim=2] mask=None,
cnp.ndarray[dtype_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, float p0=0., float p1=0.):
"""return 255 if g > percentile p0
"""
+19 -18
View File
@@ -3,8 +3,8 @@
The local histogram is computed using a sliding window similar to the method
described in [1]_.
Input image can be 8-bit or 16-bit with a value < 4096 (i.e. 12 bit), 8-bit
images are casted in 16-bit the number of histogram bins is determined from the
Input image must be 16-bit with a value < 4096 (i.e. 12 bit),
the number of histogram bins is determined from the
maximum value present in the image.
The pixel neighborhood is defined by:
@@ -89,9 +89,8 @@ def bilateral_mean(image, selem, out=None, mask=None, shift_x=False,
Parameters
----------
image : ndarray
Image array (uint8 array or uint16). If image is uint16, as the
algorithm uses max. 12bit histogram, an exception will be raised if
image has a value > 4095
Image array (uint16). As the algorithm uses max. 12bit histogram,
an exception will be raised if image has a value > 4095
selem : ndarray
The neighborhood expressed as a 2-D array of 1's and 0's.
out : ndarray
@@ -108,7 +107,7 @@ def bilateral_mean(image, selem, out=None, mask=None, shift_x=False,
Returns
-------
out : uint16 array (uint8 image are casted to uint16)
out : uint16 array
The result of the local bilateral mean.
See also
@@ -118,17 +117,15 @@ def bilateral_mean(image, selem, out=None, mask=None, shift_x=False,
Notes
-----
* input image can be 8-bit or 16-bit with a value < 4096 (i.e. 12 bit)
* 8-bit images are casted in 16-bit
* input image are 16-bit only
Examples
--------
>>> from skimage import data
>>> from skimage.morphology import disk
>>> from skimage.filter.rank import bilateral_mean
>>> # Load test image
>>> ima = data.camera()
>>> # Load test image / cast to uint16
>>> ima = data.camera().astype(np.uint16)
>>> # bilateral filtering of cameraman image using a flat kernel
>>> bilat_ima = bilateral_mean(ima, disk(20), s0=10,s1=10)
"""
@@ -146,9 +143,8 @@ def bilateral_pop(image, selem, out=None, mask=None, shift_x=False,
Parameters
----------
image : ndarray
Image array (uint8 array or uint16). If image is uint16, as the
algorithm uses max. 12bit histogram, an exception will be raised if
image has a value > 4095
Image array (uint16). As the algorithm uses max. 12bit histogram,
an exception will be raised if image has a value > 4095
selem : ndarray
The neighborhood expressed as a 2-D array of 1's and 0's.
out : ndarray
@@ -165,20 +161,25 @@ def bilateral_pop(image, selem, out=None, mask=None, shift_x=False,
Returns
-------
out : uint16 array (uint8 image are casted to uint16)
out : uint16 array
the local number of pixels inside the bilateral neighborhood
Notes
-----
* input image are 16-bit only
Examples
--------
>>> # Local mean
>>> from skimage.morphology import square
>>> import skimage.filter.rank as rank
>>> ima8 = 255 * np.array([[0, 0, 0, 0, 0],
>>> ima16 = 255 * np.array([[0, 0, 0, 0, 0],
... [0, 1, 1, 1, 0],
... [0, 1, 1, 1, 0],
... [0, 1, 1, 1, 0],
... [0, 0, 0, 0, 0]], dtype=np.uint8)
>>> rank.bilateral_pop(ima8, square(3), s0=10,s1=10)
... [0, 0, 0, 0, 0]], dtype=np.uint16)
>>> rank.bilateral_pop(ima16, square(3), s0=10,s1=10)
array([[3, 4, 3, 4, 3],
[4, 4, 6, 4, 4],
[3, 6, 9, 6, 3],
+11 -9
View File
@@ -648,12 +648,12 @@ def noise_filter(image, selem, out=None, mask=None, shift_x=False,
References
----------
.. [Hashimoto12] N. Hashimoto et al. Referenceless image quality evaluation
for whole slide imaging. J Pathol Inform 2012;3:9.
for whole slide imaging. J Pathol Inform 2012;3:9.
Returns
-------
out : uint8 array or uint16 array (same as input image)
The image noise .
The image noise.
"""
@@ -669,7 +669,7 @@ def noise_filter(image, selem, out=None, mask=None, shift_x=False,
def entropy(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
"""Returns the entropy [wiki_entropy]_ computed locally. Entropy is computed
"""Returns the entropy [1]_ computed locally. Entropy is computed
using base 2 logarithm i.e. the filter returns the minimum number of
bits needed to encode local greylevel distribution.
@@ -698,7 +698,7 @@ def entropy(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
References
----------
.. [wiki_entropy] http://en.wikipedia.org/wiki/Entropy_(information_theory)
.. [1] http://en.wikipedia.org/wiki/Entropy_(information_theory)
Examples
--------
@@ -726,9 +726,7 @@ def otsu(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
Parameters
----------
image : ndarray
Image array (uint8 array or uint16). If image is uint16, the algorithm
uses max. 12bit histogram, an exception will be raised if image has a
value > 4095.
Image array (uint8 array).
selem : ndarray
The neighborhood expressed as a 2-D array of 1's and 0's.
out : ndarray
@@ -743,20 +741,24 @@ def otsu(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
Returns
-------
out : uint8 array or uint16 array (same as input image)
out : uint8 array
Otsu's threshold values
References
----------
.. [otsu] http://en.wikipedia.org/wiki/Otsu's_method
Notes
-----
* input image are 8-bit only
Examples
--------
>>> # Local entropy
>>> from skimage import data
>>> from skimage.filter.rank import otsu
>>> from skimage.morphology import disk
>>> # defining a 8- and a 16-bit test images
>>> # defining a 8-bit test images
>>> a8 = data.camera()
>>> loc_otsu = otsu(a8, disk(5))
>>> thresh_image = a8 >= loc_otsu
+11 -11
View File
@@ -26,34 +26,34 @@ def configuration(parent_package='', top_path=None):
cython(['rank/bilateral_rank.pyx'], working_path=base_path)
config.add_extension('_ctmf', sources=['_ctmf.c'],
include_dirs=[get_numpy_include_dirs()])
include_dirs=[get_numpy_include_dirs()])
config.add_extension('_denoise_cy', sources=['_denoise_cy.c'],
include_dirs=[get_numpy_include_dirs(), '../_shared'])
config.add_extension('rank/_core8', sources=['rank/_core8.c'],
config.add_extension('rank._core8', sources=['rank/_core8.c'],
include_dirs=[get_numpy_include_dirs()])
config.add_extension('rank/_core16', sources=['rank/_core16.c'],
config.add_extension('rank._core16', sources=['rank/_core16.c'],
include_dirs=[get_numpy_include_dirs()])
config.add_extension('rank/_crank8', sources=['rank/_crank8.c'],
config.add_extension('rank._crank8', sources=['rank/_crank8.c'],
include_dirs=[get_numpy_include_dirs()])
config.add_extension(
'rank/_crank8_percentiles', sources=['rank/_crank8_percentiles.c'],
'rank._crank8_percentiles', sources=['rank/_crank8_percentiles.c'],
include_dirs=[get_numpy_include_dirs()])
config.add_extension('rank/_crank16', sources=['rank/_crank16.c'],
config.add_extension('rank._crank16', sources=['rank/_crank16.c'],
include_dirs=[get_numpy_include_dirs()])
config.add_extension(
'rank/_crank16_percentiles', sources=['rank/_crank16_percentiles.c'],
'rank._crank16_percentiles', sources=['rank/_crank16_percentiles.c'],
include_dirs=[get_numpy_include_dirs()])
config.add_extension(
'rank/_crank16_bilateral', sources=['rank/_crank16_bilateral.c'],
'rank._crank16_bilateral', sources=['rank/_crank16_bilateral.c'],
include_dirs=[get_numpy_include_dirs()])
config.add_extension(
'rank/rank', sources=['rank/rank.c'],
'rank.rank', sources=['rank/rank.c'],
include_dirs=[get_numpy_include_dirs()])
config.add_extension(
'rank/percentile_rank', sources=['rank/percentile_rank.c'],
'rank.percentile_rank', sources=['rank/percentile_rank.c'],
include_dirs=[get_numpy_include_dirs()])
config.add_extension(
'rank/bilateral_rank', sources=['rank/bilateral_rank.c'],
'rank.bilateral_rank', sources=['rank/bilateral_rank.c'],
include_dirs=[get_numpy_include_dirs()])
return config
+4 -4
View File
@@ -4,11 +4,11 @@ other cython modules can "cimport mcp" and subclass it.
"""
cimport heap
cimport numpy as np
cimport numpy as cnp
ctypedef heap.BOOL_T BOOL_T
ctypedef unsigned char DIM_T
ctypedef np.float64_t FLOAT_T
ctypedef unsigned char DIM_T
ctypedef cnp.float64_t FLOAT_T
cdef class MCP:
cdef heap.FastUpdateBinaryHeap costs_heap
@@ -23,7 +23,7 @@ cdef class MCP:
cdef object flat_offsets
cdef object offset_lengths
cdef BOOL_T dirty
cdef BOOL_T use_start_cost
cdef BOOL_T use_start_cost
# if use_start_cost is true, the cost of the starting element is added to
# the cost of the path. Set to true by default in the base class...
+24 -24
View File
@@ -1,5 +1,7 @@
# -*- python -*-
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
"""Cython implementation of Dijkstra's minimum cost path algorithm,
for use with data on a n-dimensional lattice.
@@ -32,19 +34,19 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
import cython
cimport numpy as np
import numpy as np
cimport heap
import heap
ctypedef np.int8_t OFFSET_T
cimport numpy as cnp
cimport heap
ctypedef cnp.int8_t OFFSET_T
OFFSET_D = np.int8
ctypedef np.int16_t OFFSETS_INDEX_T
ctypedef cnp.int16_t OFFSETS_INDEX_T
OFFSETS_INDEX_D = np.int16
ctypedef np.int8_t EDGE_T
ctypedef cnp.int8_t EDGE_T
EDGE_D = np.int8
ctypedef np.intp_t INDEX_T
ctypedef cnp.intp_t INDEX_T
INDEX_D = np.intp
FLOAT_D = np.float64
@@ -317,7 +319,6 @@ cdef class MCP:
FLOAT_T new_cost, FLOAT_T offset_length):
return new_cost
@cython.boundscheck(False)
def find_costs(self, starts, ends=None, find_all_ends=True):
"""
Find the minimum-cost path from the given starting points.
@@ -366,7 +367,7 @@ cdef class MCP:
cdef BOOL_T use_ends = 0
cdef INDEX_T num_ends
cdef BOOL_T all_ends = find_all_ends
cdef np.ndarray[INDEX_T, ndim=1] flat_ends
cdef cnp.ndarray[INDEX_T, ndim=1] flat_ends
starts = _normalize_indices(starts, self.costs_shape)
if starts is None:
raise ValueError('start points must all be within the costs array')
@@ -385,18 +386,18 @@ cdef class MCP:
# lookup and array-ify object attributes for fast use
cdef heap.FastUpdateBinaryHeap costs_heap = self.costs_heap
cdef np.ndarray[FLOAT_T, ndim=1] flat_costs = self.flat_costs
cdef np.ndarray[FLOAT_T, ndim=1] flat_cumulative_costs = \
cdef cnp.ndarray[FLOAT_T, ndim=1] flat_costs = self.flat_costs
cdef cnp.ndarray[FLOAT_T, ndim=1] flat_cumulative_costs = \
self.flat_cumulative_costs
cdef np.ndarray[OFFSETS_INDEX_T, ndim=1] traceback_offsets = \
cdef cnp.ndarray[OFFSETS_INDEX_T, ndim=1] traceback_offsets = \
self.traceback_offsets
cdef np.ndarray[EDGE_T, ndim=2] flat_pos_edge_map = \
cdef cnp.ndarray[EDGE_T, ndim=2] flat_pos_edge_map = \
self.flat_pos_edge_map
cdef np.ndarray[EDGE_T, ndim=2] flat_neg_edge_map = \
cdef cnp.ndarray[EDGE_T, ndim=2] flat_neg_edge_map = \
self.flat_neg_edge_map
cdef np.ndarray[OFFSET_T, ndim=2] offsets = self.offsets
cdef np.ndarray[INDEX_T, ndim=1] flat_offsets = self.flat_offsets
cdef np.ndarray[FLOAT_T, ndim=1] offset_lengths = self.offset_lengths
cdef cnp.ndarray[OFFSET_T, ndim=2] offsets = self.offsets
cdef cnp.ndarray[INDEX_T, ndim=1] flat_offsets = self.flat_offsets
cdef cnp.ndarray[FLOAT_T, ndim=1] offset_lengths = self.offset_lengths
cdef DIM_T dim = self.dim
cdef int num_offsets = len(flat_offsets)
@@ -514,7 +515,6 @@ cdef class MCP:
self.dirty = 1
return cumulative_costs, traceback
@cython.boundscheck(False)
def traceback(self, end):
"""traceback(end)
@@ -555,12 +555,12 @@ cdef class MCP:
raise ValueError('no minimum-cost path was found '
'to the specified end point')
cdef np.ndarray[INDEX_T, ndim=1] position = \
cdef cnp.ndarray[INDEX_T, ndim=1] position = \
np.array(ends[0], dtype=INDEX_D)
cdef np.ndarray[OFFSETS_INDEX_T, ndim=1] traceback_offsets = \
cdef cnp.ndarray[OFFSETS_INDEX_T, ndim=1] traceback_offsets = \
self.traceback_offsets
cdef np.ndarray[OFFSET_T, ndim=2] offsets = self.offsets
cdef np.ndarray[INDEX_T, ndim=1] flat_offsets = self.flat_offsets
cdef cnp.ndarray[OFFSET_T, ndim=2] offsets = self.offsets
cdef cnp.ndarray[INDEX_T, ndim=1] flat_offsets = self.flat_offsets
cdef OFFSETS_INDEX_T offset
cdef DIM_T d
+6 -7
View File
@@ -1,7 +1,7 @@
""" This is the definition file for heap.pyx.
It contains the definitions of the heap classes, such that
other cython modules can "cimport heap" and thus use the
C versions of pop(), push(), and value_of(): pop_fast(), push_fast() and
C versions of pop(), push(), and value_of(): pop_fast(), push_fast() and
value_of_fast()
"""
@@ -14,16 +14,16 @@ ctypedef unsigned char LEVELS_T
cdef class BinaryHeap:
cdef readonly INDEX_T count
cdef readonly LEVELS_T levels, min_levels
cdef readonly LEVELS_T levels, min_levels
cdef VALUE_T *_values
cdef REFERENCE_T *_references
cdef REFERENCE_T _popped_ref
cdef void _add_or_remove_level(self, LEVELS_T add_or_remove)
cdef void _update(self)
cdef void _update_one(self, INDEX_T i)
cdef void _remove(self, INDEX_T i)
cdef INDEX_T push_fast(self, VALUE_T value, REFERENCE_T reference)
cdef VALUE_T pop_fast(self)
@@ -32,8 +32,7 @@ cdef class FastUpdateBinaryHeap(BinaryHeap):
cdef INDEX_T *_crossref
cdef BOOL_T _invalid_ref
cdef BOOL_T _pushed
cdef VALUE_T value_of_fast(self, REFERENCE_T reference)
cdef INDEX_T push_if_lower_fast(self, VALUE_T value,
cdef INDEX_T push_if_lower_fast(self, VALUE_T value,
REFERENCE_T reference)
+66 -73
View File
@@ -1,4 +1,7 @@
# -*- python -*-
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
"""Colour Mixer
@@ -9,15 +12,14 @@ one.
"""
import cython
import numpy as np
cimport numpy as np
cimport numpy as cnp
from libc.math cimport exp, pow
@cython.boundscheck(False)
def add(np.ndarray[np.uint8_t, ndim=3] img,
np.ndarray[np.uint8_t, ndim=3] stateimg,
int channel, int amount):
def add(cnp.ndarray[cnp.uint8_t, ndim=3] img,
cnp.ndarray[cnp.uint8_t, ndim=3] stateimg,
Py_ssize_t channel, Py_ssize_t amount):
"""Add a given amount to a colour channel of `stateimg`, and
store the result in `img`. Overflow is clipped.
@@ -33,38 +35,37 @@ def add(np.ndarray[np.uint8_t, ndim=3] img,
Value to add.
"""
cdef int height = img.shape[0]
cdef int width = img.shape[1]
cdef int k = channel
cdef int n = amount
cdef Py_ssize_t height = img.shape[0]
cdef Py_ssize_t width = img.shape[1]
cdef Py_ssize_t k = channel
cdef Py_ssize_t n = amount
cdef np.int16_t op_result
cdef cnp.int16_t op_result
cdef np.uint8_t lut[256]
cdef cnp.uint8_t lut[256]
cdef int i, j, l
cdef Py_ssize_t i, j, l
with nogil:
for l from 0 <= l < 256:
op_result = <np.int16_t>(l + n)
op_result = <cnp.int16_t>(l + n)
if op_result > 255:
op_result = 255
elif op_result < 0:
op_result = 0
else:
pass
lut[l] = <np.uint8_t>op_result
lut[l] = <cnp.uint8_t>op_result
for i from 0 <= i < height:
for j from 0 <= j < width:
img[i, j, k] = lut[stateimg[i,j,k]]
@cython.boundscheck(False)
def multiply(np.ndarray[np.uint8_t, ndim=3] img,
np.ndarray[np.uint8_t, ndim=3] stateimg,
int channel, float amount):
def multiply(cnp.ndarray[cnp.uint8_t, ndim=3] img,
cnp.ndarray[cnp.uint8_t, ndim=3] stateimg,
Py_ssize_t channel, float amount):
"""Multiply a colour channel of `stateimg` by a certain amount, and
store the result in `img`. Overflow is clipped.
@@ -80,16 +81,16 @@ def multiply(np.ndarray[np.uint8_t, ndim=3] img,
Multiplication factor.
"""
cdef int height = img.shape[0]
cdef int width = img.shape[1]
cdef int k = channel
cdef Py_ssize_t height = img.shape[0]
cdef Py_ssize_t width = img.shape[1]
cdef Py_ssize_t k = channel
cdef float n = amount
cdef float op_result
cdef np.uint8_t lut[256]
cdef cnp.uint8_t lut[256]
cdef int i, j, l
cdef Py_ssize_t i, j, l
with nogil:
@@ -101,17 +102,16 @@ def multiply(np.ndarray[np.uint8_t, ndim=3] img,
op_result = 0
else:
pass
lut[l] = <np.uint8_t>op_result
lut[l] = <cnp.uint8_t>op_result
for i from 0 <= i < height:
for j from 0 <= j < width:
img[i,j,k] = lut[stateimg[i,j,k]]
@cython.boundscheck(False)
def brightness(np.ndarray[np.uint8_t, ndim=3] img,
np.ndarray[np.uint8_t, ndim=3] stateimg,
float factor, int offset):
def brightness(cnp.ndarray[cnp.uint8_t, ndim=3] img,
cnp.ndarray[cnp.uint8_t, ndim=3] stateimg,
float factor, Py_ssize_t offset):
"""Modify the brightness of an image.
'factor' is multiplied to all channels, which are
then added by 'amount'. Overflow is clipped.
@@ -129,13 +129,13 @@ def brightness(np.ndarray[np.uint8_t, ndim=3] img,
"""
cdef int height = img.shape[0]
cdef int width = img.shape[1]
cdef Py_ssize_t height = img.shape[0]
cdef Py_ssize_t width = img.shape[1]
cdef float op_result
cdef np.uint8_t lut[256]
cdef cnp.uint8_t lut[256]
cdef int i, j, k
cdef Py_ssize_t i, j, k
with nogil:
for k from 0 <= k < 256:
@@ -146,7 +146,7 @@ def brightness(np.ndarray[np.uint8_t, ndim=3] img,
op_result = 0
else:
pass
lut[k] = <np.uint8_t>op_result
lut[k] = <cnp.uint8_t>op_result
for i from 0 <= i < height:
for j from 0 <= j < width:
@@ -155,27 +155,25 @@ def brightness(np.ndarray[np.uint8_t, ndim=3] img,
img[i,j,2] = lut[stateimg[i,j,2]]
@cython.boundscheck(False)
@cython.cdivision(True)
def sigmoid_gamma(np.ndarray[np.uint8_t, ndim=3] img,
np.ndarray[np.uint8_t, ndim=3] stateimg,
def sigmoid_gamma(cnp.ndarray[cnp.uint8_t, ndim=3] img,
cnp.ndarray[cnp.uint8_t, ndim=3] stateimg,
float alpha, float beta):
cdef int height = img.shape[0]
cdef int width = img.shape[1]
cdef Py_ssize_t height = img.shape[0]
cdef Py_ssize_t width = img.shape[1]
cdef int i, j, k
cdef Py_ssize_t i, j, k
cdef float c1 = 1 / (1 + exp(beta))
cdef float c2 = 1 / (1 + exp(beta - alpha)) - c1
cdef np.uint8_t lut[256]
cdef cnp.uint8_t lut[256]
with nogil:
# compute the lut
for k from 0 <= k < 256:
lut[k] = <np.uint8_t>(((1 / (1 + exp(beta - (k / 255.) * alpha)))
lut[k] = <cnp.uint8_t>(((1 / (1 + exp(beta - (k / 255.) * alpha)))
- c1) * 255 / c2)
for i from 0 <= i < height:
for j from 0 <= j < width:
@@ -184,17 +182,16 @@ def sigmoid_gamma(np.ndarray[np.uint8_t, ndim=3] img,
img[i,j,2] = lut[stateimg[i,j,2]]
@cython.boundscheck(False)
def gamma(np.ndarray[np.uint8_t, ndim=3] img,
np.ndarray[np.uint8_t, ndim=3] stateimg,
def gamma(cnp.ndarray[cnp.uint8_t, ndim=3] img,
cnp.ndarray[cnp.uint8_t, ndim=3] stateimg,
float gamma):
cdef int height = img.shape[0]
cdef int width = img.shape[1]
cdef Py_ssize_t height = img.shape[0]
cdef Py_ssize_t width = img.shape[1]
cdef np.uint8_t lut[256]
cdef cnp.uint8_t lut[256]
cdef int i, j, k
cdef Py_ssize_t i, j, k
if gamma == 0:
gamma = 0.00000000000000000001
@@ -204,7 +201,7 @@ def gamma(np.ndarray[np.uint8_t, ndim=3] img,
# compute the lut
for k from 0 <= k < 256:
lut[k] = <np.uint8_t>((pow((k / 255.), gamma) * 255))
lut[k] = <cnp.uint8_t>((pow((k / 255.), gamma) * 255))
for i from 0 <= i < height:
for j from 0 <= j < width:
@@ -213,7 +210,6 @@ def gamma(np.ndarray[np.uint8_t, ndim=3] img,
img[i,j,2] = lut[stateimg[i,j,2]]
@cython.cdivision(True)
cdef void rgb_2_hsv(float* RGB, float* HSV) nogil:
cdef float R, G, B, H, S, V, MAX, MIN
R = RGB[0]
@@ -277,11 +273,10 @@ cdef void rgb_2_hsv(float* RGB, float* HSV) nogil:
HSV[2] = V
@cython.cdivision(True)
cdef void hsv_2_rgb(float* HSV, float* RGB) nogil:
cdef float H, S, V
cdef float f, p, q, t, r, g, b
cdef int hi
cdef Py_ssize_t hi
H = HSV[0]
S = HSV[1]
@@ -422,9 +417,8 @@ def py_rgb_2_hsv(R, G, B):
return (H, S, V)
@cython.boundscheck(False)
def hsv_add(np.ndarray[np.uint8_t, ndim=3] img,
np.ndarray[np.uint8_t, ndim=3] stateimg,
def hsv_add(cnp.ndarray[cnp.uint8_t, ndim=3] img,
cnp.ndarray[cnp.uint8_t, ndim=3] stateimg,
float h_amt, float s_amt, float v_amt):
"""Modify the image color by specifying additive HSV Values.
@@ -455,13 +449,13 @@ def hsv_add(np.ndarray[np.uint8_t, ndim=3] img,
"""
cdef int height = img.shape[0]
cdef int width = img.shape[1]
cdef Py_ssize_t height = img.shape[0]
cdef Py_ssize_t width = img.shape[1]
cdef float HSV[3]
cdef float RGB[3]
cdef int i, j
cdef Py_ssize_t i, j
with nogil:
for i from 0 <= i < height:
@@ -483,14 +477,13 @@ def hsv_add(np.ndarray[np.uint8_t, ndim=3] img,
RGB[1] *= 255
RGB[2] *= 255
img[i, j, 0] = <np.uint8_t>RGB[0]
img[i, j, 1] = <np.uint8_t>RGB[1]
img[i, j, 2] = <np.uint8_t>RGB[2]
img[i, j, 0] = <cnp.uint8_t>RGB[0]
img[i, j, 1] = <cnp.uint8_t>RGB[1]
img[i, j, 2] = <cnp.uint8_t>RGB[2]
@cython.boundscheck(False)
def hsv_multiply(np.ndarray[np.uint8_t, ndim=3] img,
np.ndarray[np.uint8_t, ndim=3] stateimg,
def hsv_multiply(cnp.ndarray[cnp.uint8_t, ndim=3] img,
cnp.ndarray[cnp.uint8_t, ndim=3] stateimg,
float h_amt, float s_amt, float v_amt):
"""Modify the image color by specifying multiplicative HSV Values.
@@ -525,13 +518,13 @@ def hsv_multiply(np.ndarray[np.uint8_t, ndim=3] img,
"""
cdef int height = img.shape[0]
cdef int width = img.shape[1]
cdef Py_ssize_t height = img.shape[0]
cdef Py_ssize_t width = img.shape[1]
cdef float HSV[3]
cdef float RGB[3]
cdef int i, j
cdef Py_ssize_t i, j
with nogil:
for i from 0 <= i < height:
@@ -553,6 +546,6 @@ def hsv_multiply(np.ndarray[np.uint8_t, ndim=3] img,
RGB[1] *= 255
RGB[2] *= 255
img[i, j, 0] = <np.uint8_t>RGB[0]
img[i, j, 1] = <np.uint8_t>RGB[1]
img[i, j, 2] = <np.uint8_t>RGB[2]
img[i, j, 0] = <cnp.uint8_t>RGB[0]
img[i, j, 1] = <cnp.uint8_t>RGB[1]
img[i, j, 2] = <cnp.uint8_t>RGB[2]
+7 -8
View File
@@ -1,7 +1,10 @@
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
cimport numpy as np
import cython
cimport numpy as cnp
cdef inline float tri_max(float a, float b, float c):
@@ -18,8 +21,7 @@ cdef inline float tri_max(float a, float b, float c):
return c
@cython.boundscheck(False)
def histograms(np.ndarray[np.uint8_t, ndim=3] img, int nbins):
def histograms(cnp.ndarray[cnp.uint8_t, ndim=3] img, int nbins):
'''Calculate the channel histograms of the current image.
Parameters
@@ -39,10 +41,7 @@ def histograms(np.ndarray[np.uint8_t, ndim=3] img, int nbins):
'''
cdef int width = img.shape[1]
cdef int height = img.shape[0]
cdef np.ndarray[np.int32_t, ndim=1] r
cdef np.ndarray[np.int32_t, ndim=1] g
cdef np.ndarray[np.int32_t, ndim=1] b
cdef np.ndarray[np.int32_t, ndim=1] v
cdef cnp.ndarray[cnp.int32_t, ndim=1] r, g, b, v
r = np.zeros((nbins,), dtype=np.int32)
g = np.zeros((nbins,), dtype=np.int32)
+3
View File
@@ -0,0 +1,3 @@
[simpleitk]
description = Image reading and writing via SimpleITK
provides = imread, imsave
+21
View File
@@ -0,0 +1,21 @@
__all__ = ['imread', 'imsave']
try:
import SimpleITK as sitk
except ImportError:
raise ImportError("SimpleITK could not be found. "
"Please try "
" easy_install SimpleITK "
"or refer to "
" http://simpleitk.org/ "
"for further instructions.")
def imread(fname):
sitk_img = sitk.ReadImage(fname)
return sitk.GetArrayFromImage(sitk_img)
def imsave(fname, arr):
sitk_img = sitk.GetImageFromArray(arr, isVector=True)
sitk.WriteImage(sitk_img, fname)
+1
View File
@@ -105,6 +105,7 @@ class MultiImage(object):
The two frames in this image can be shown with matplotlib:
.. plot:: show_collection.py
"""
def __init__(self, filename, conserve_memory=True, dtype=None):
"""Load a multi-img."""
+93
View File
@@ -0,0 +1,93 @@
import os.path
import numpy as np
from numpy.testing import *
from numpy.testing.decorators import skipif
from tempfile import NamedTemporaryFile
from skimage import data_dir
from skimage.io import imread, imsave, use_plugin, reset_plugins
try:
import SimpleITK as sitk
use_plugin('simpleitk')
except ImportError:
sitk_available = False
else:
sitk_available = True
def teardown():
reset_plugins()
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 sitk is used.
"""
try:
use_plugin('simpleitk')
except ImportError:
pass
@skipif(not sitk_available)
def test_imread_flatten():
# a color image is flattened
img = imread(os.path.join(data_dir, 'color.png'), flatten=True)
assert img.ndim == 2
assert img.dtype == np.float64
img = imread(os.path.join(data_dir, 'camera.png'), flatten=True)
# check that flattening does not occur for an image that is grey already.
assert np.sctype2char(img.dtype) in np.typecodes['AllInteger']
@skipif(not sitk_available)
def test_bilevel():
expected = np.zeros((10, 10))
expected[::2] = 255
img = imread(os.path.join(data_dir, 'checker_bilevel.png'))
assert_array_equal(img, expected)
@skipif(not sitk_available)
def test_imread_uint16():
expected = np.load(os.path.join(data_dir, 'chessboard_GRAY_U8.npy'))
img = imread(os.path.join(data_dir, 'chessboard_GRAY_U16.tif'))
assert np.issubdtype(img.dtype, np.uint16)
assert_array_almost_equal(img, expected)
@skipif(not sitk_available)
def test_imread_uint16_big_endian():
expected = np.load(os.path.join(data_dir, 'chessboard_GRAY_U8.npy'))
img = imread(os.path.join(data_dir, 'chessboard_GRAY_U16B.tif'))
assert_array_almost_equal(img, expected)
class TestSave:
def roundtrip(self, dtype, x):
f = NamedTemporaryFile(suffix='.mha')
fname = f.name
f.close()
imsave(fname, x)
y = imread(fname)
assert_array_almost_equal(x, y)
@skipif(not sitk_available)
def test_imsave_roundtrip(self):
for shape in [(10, 10), (10, 10, 3), (10, 10, 4)]:
for dtype in (np.uint8, np.uint16, np.float32, np.float64):
x = np.ones(shape, dtype=dtype) * np.random.random(shape)
if np.issubdtype(dtype, float):
yield self.roundtrip, dtype, x
else:
x = (x * 255).astype(dtype)
yield self.roundtrip, dtype, x
if __name__ == "__main__":
run_module_suite()
+13 -11
View File
@@ -1,10 +1,11 @@
# -*- python -*-
# cython: cdivision=True
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
cimport numpy as np
np.import_array()
cimport numpy as cnp
cdef inline double _get_fraction(double from_value, double to_value,
double level):
@@ -13,8 +14,8 @@ cdef inline double _get_fraction(double from_value, double to_value,
return ((level - from_value) / (to_value - from_value))
def iterate_and_store(np.ndarray[double, ndim=2] array,
double level, int vertex_connect_high):
def iterate_and_store(cnp.ndarray[double, ndim=2] array,
double level, Py_ssize_t vertex_connect_high):
"""Iterate across the given array in a marching-squares fashion,
looking for segments that cross 'level'. If such a segment is
found, its coordinates are added to a growing list of segments,
@@ -27,7 +28,7 @@ def iterate_and_store(np.ndarray[double, ndim=2] array,
raise ValueError("Input array must be at least 2x2.")
cdef list arc_list = []
cdef int n
cdef Py_ssize_t n
# The plan is to iterate a 2x2 square across the input array. This means
# that the upper-left corner of the square needs to iterate across a
@@ -39,17 +40,18 @@ def iterate_and_store(np.ndarray[double, ndim=2] array,
# index varies the fastest).
# Current coords start at 0,0.
cdef int[2] coords
cdef Py_ssize_t[2] coords
coords[0] = 0
coords[1] = 0
# Calculate the number of iterations we'll need
cdef int num_square_steps = (array.shape[0] - 1) * (array.shape[1] - 1)
cdef Py_ssize_t num_square_steps = (array.shape[0] - 1) \
* (array.shape[1] - 1)
cdef unsigned char square_case = 0
cdef tuple top, bottom, left, right
cdef double ul, ur, ll, lr
cdef int r0, r1, c0, c1
cdef Py_ssize_t r0, r1, c0, c1
for n in range(num_square_steps):
# There are sixteen different possible square types, diagramed below.
+16 -12
View File
@@ -1,14 +1,16 @@
#cython: boundscheck=False
#cython: wraparound=False
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
cimport numpy as np
cimport numpy as cnp
def central_moments(np.ndarray[np.double_t, ndim=2] array, double cr, double cc,
int order):
cdef int p, q, r, c
cdef np.ndarray[np.double_t, ndim=2] mu
def central_moments(cnp.ndarray[cnp.double_t, ndim=2] array, double cr,
double cc, int order):
cdef Py_ssize_t p, q, r, c
cdef cnp.ndarray[cnp.double_t, ndim=2] mu
mu = np.zeros((order + 1, order + 1), 'double')
for p in range(order + 1):
for q in range(order + 1):
@@ -17,9 +19,10 @@ def central_moments(np.ndarray[np.double_t, ndim=2] array, double cr, double cc,
mu[p,q] += array[r,c] * (r - cr) ** q * (c - cc) ** p
return mu
def normalized_moments(np.ndarray[np.double_t, ndim=2] mu, int order):
cdef int p, q
cdef np.ndarray[np.double_t, ndim=2] nu
def normalized_moments(cnp.ndarray[cnp.double_t, ndim=2] mu, int order):
cdef Py_ssize_t p, q
cdef cnp.ndarray[cnp.double_t, ndim=2] nu
nu = np.zeros((order + 1, order + 1), 'double')
for p in range(order + 1):
for q in range(order + 1):
@@ -29,8 +32,9 @@ def normalized_moments(np.ndarray[np.double_t, ndim=2] mu, int order):
nu[p,q] = np.nan
return nu
def hu_moments(np.ndarray[np.double_t, ndim=2] nu):
cdef np.ndarray[np.double_t, ndim=1] hu = np.zeros((7,), 'double')
def hu_moments(cnp.ndarray[cnp.double_t, ndim=2] nu):
cdef cnp.ndarray[cnp.double_t, ndim=1] hu = np.zeros((7,), 'double')
cdef double t0 = nu[3,0] + nu[1,2]
cdef double t1 = nu[2,1] + nu[0,3]
cdef double q0 = t0 * t0
+3 -3
View File
@@ -49,7 +49,7 @@ def test_bbox():
def test_central_moments():
mu = regionprops(SAMPLE, ['CentralMoments'])[0]['CentralMoments']
#: determined with OpenCV
# determined with OpenCV
assert_almost_equal(mu[0,2], 436.00000000000045)
# different from OpenCV results, bug in OpenCV
assert_almost_equal(mu[0,3], -737.333333333333)
@@ -198,7 +198,7 @@ def test_minor_axis_length():
def test_moments():
m = regionprops(SAMPLE, ['Moments'])[0]['Moments']
#: determined with OpenCV
# determined with OpenCV
assert_almost_equal(m[0,0], 72.0)
assert_almost_equal(m[0,1], 408.0)
assert_almost_equal(m[0,2], 2748.0)
@@ -213,7 +213,7 @@ def test_moments():
def test_normalized_moments():
nu = regionprops(SAMPLE, ['NormalizedMoments'])[0]['NormalizedMoments']
#: determined with OpenCV
# determined with OpenCV
assert_almost_equal(nu[0,2], 0.08410493827160502)
assert_almost_equal(nu[1,1], -0.016846707818929982)
assert_almost_equal(nu[1,2], -0.002899800614433943)
+1
View File
@@ -7,3 +7,4 @@ from .watershed import watershed, is_local_maximum
from ._skeletonize import skeletonize, medial_axis
from .convex_hull import convex_hull_image
from .greyreconstruct import reconstruction
from .misc import remove_small_objects
+35 -34
View File
@@ -1,9 +1,13 @@
# -*- python -*-
cimport numpy as np
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
def possible_hull(np.ndarray[dtype=np.uint8_t, ndim=2, mode="c"] img):
cimport numpy as cnp
def possible_hull(cnp.ndarray[dtype=cnp.uint8_t, ndim=2, mode="c"] img):
"""Return positions of pixels that possibly belong to the convex hull.
Parameters
@@ -13,47 +17,44 @@ def possible_hull(np.ndarray[dtype=np.uint8_t, ndim=2, mode="c"] img):
Returns
-------
coords : ndarray (N, 2)
coords : ndarray (cols, 2)
The ``(row, column)`` coordinates of all pixels that possibly belong to
the convex hull.
"""
cdef int i, j, k
cdef unsigned int M, N
M = img.shape[0]
N = img.shape[1]
cdef Py_ssize_t r, c
cdef Py_ssize_t rows = img.shape[0]
cdef Py_ssize_t cols = img.shape[1]
# Output: M storage slots for left boundary pixels
# N storage slots for top boundary pixels
# M storage slots for right boundary pixels
# N storage slots for bottom boundary pixels
cdef np.ndarray[dtype=np.int_t, ndim=2] nonzero = \
np.ones((2 * (M + N), 2), dtype=np.int)
nonzero *= -1
# Output: rows storage slots for left boundary pixels
# cols storage slots for top boundary pixels
# rows storage slots for right boundary pixels
# cols storage slots for bottom boundary pixels
cdef cnp.ndarray[dtype=cnp.intp_t, ndim=2] nonzero = \
np.ones((2 * (rows + cols), 2), dtype=np.intp)
nonzero *= -1
k = 0
for i in range(M):
for j in range(N):
if img[i, j] != 0:
for r in range(rows):
for c in range(cols):
if img[r, c] != 0:
# Left check
if nonzero[i, 1] == -1:
nonzero[i, 0] = i
nonzero[i, 1] = j
if nonzero[r, 1] == -1:
nonzero[r, 0] = r
nonzero[r, 1] = c
# Right check
elif nonzero[M + N + i, 1] < j:
nonzero[M + N + i, 0] = i
nonzero[M + N + i, 1] = j
elif nonzero[rows + cols + r, 1] < c:
nonzero[rows + cols + r, 0] = r
nonzero[rows + cols + r, 1] = c
# Top check
if nonzero[M + j, 1] == -1:
nonzero[M + j, 0] = i
nonzero[M + j, 1] = j
if nonzero[rows + c, 1] == -1:
nonzero[rows + c, 0] = r
nonzero[rows + c, 1] = c
# Bottom check
elif nonzero[2 * M + N + j, 0] < i:
nonzero[2 * M + N + j, 0] = i
nonzero[2 * M + N + j, 1] = j
elif nonzero[2 * rows + cols + c, 0] < r:
nonzero[2 * rows + cols + c, 0] = r
nonzero[2 * rows + cols + c, 1] = c
return nonzero[nonzero[:, 0] != -1]
+19 -15
View File
@@ -1,7 +1,10 @@
# -*- python -*-
cimport numpy as np
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
cimport numpy as cnp
from skimage._shared.geometry cimport point_in_polygon, points_in_polygon
@@ -26,23 +29,24 @@ def grid_points_inside_poly(shape, verts):
True where the grid falls inside the polygon.
"""
cdef np.ndarray[np.double_t, ndim=1, mode="c"] vx, vy
cdef cnp.ndarray[cnp.double_t, ndim=1, mode="c"] vx, vy
verts = np.asarray(verts)
vx = verts[:, 0].astype(np.double)
vy = verts[:, 1].astype(np.double)
cdef int V = vx.shape[0]
cdef Py_ssize_t V = vx.shape[0]
cdef int M = shape[0]
cdef int N = shape[1]
cdef int m, n
cdef Py_ssize_t M = shape[0]
cdef Py_ssize_t N = shape[1]
cdef Py_ssize_t m, n
cdef np.ndarray[dtype=np.uint8_t, ndim=2, mode="c"] out = \
cdef cnp.ndarray[dtype=cnp.uint8_t, ndim=2, mode="c"] out = \
np.zeros((M, N), dtype=np.uint8)
for m in range(M):
for n in range(N):
out[m, n] = point_in_polygon(V, <double*>vx.data, <double*>vy.data, m, n)
out[m, n] = point_in_polygon(V, <double*>vx.data, <double*>vy.data,
m, n)
return out.view(bool)
@@ -64,7 +68,7 @@ def points_inside_poly(points, verts):
True if corresponding point is inside the polygon.
"""
cdef np.ndarray[np.double_t, ndim=1, mode="c"] x, y, vx, vy
cdef cnp.ndarray[cnp.double_t, ndim=1, mode="c"] x, y, vx, vy
points = np.asarray(points)
verts = np.asarray(verts)
@@ -75,12 +79,12 @@ def points_inside_poly(points, verts):
vx = verts[:, 0].astype(np.double)
vy = verts[:, 1].astype(np.double)
cdef np.ndarray[np.uint8_t, ndim=1] out = \
np.zeros(x.shape[0], dtype=np.uint8)
cdef cnp.ndarray[cnp.uint8_t, ndim=1] out = \
np.zeros(x.shape[0], dtype=np.uint8)
points_in_polygon(vx.shape[0], <double*>vx.data, <double*>vy.data,
x.shape[0], <double*>x.data, <double*>y.data,
<unsigned char*>out.data)
x.shape[0], <double*>x.data, <double*>y.data,
<unsigned char*>out.data)
return out.astype(bool)
+2 -2
View File
@@ -277,8 +277,8 @@ def medial_axis(image, mask=None, return_distance=False):
i, j = np.mgrid[0:image.shape[0], 0:image.shape[1]]
result = masked_image.copy()
distance = distance[result]
i = np.ascontiguousarray(i[result], np.int32)
j = np.ascontiguousarray(j[result], np.int32)
i = np.ascontiguousarray(i[result], np.intp)
j = np.ascontiguousarray(j[result], np.intp)
result = np.ascontiguousarray(result, np.uint8)
# Determine the order in which pixels are processed.
+42 -37
View File
@@ -1,3 +1,8 @@
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
'''
Originally part of CellProfiler, code licensed under both GPL and BSD licenses.
Website: http://www.cellprofiler.org
@@ -10,21 +15,20 @@ Original author: Lee Kamentsky
'''
import numpy as np
cimport numpy as np
cimport cython
cimport numpy as cnp
@cython.boundscheck(False)
def _skeletonize_loop(np.ndarray[dtype=np.uint8_t, ndim=2,
negative_indices=False, mode='c'] result,
np.ndarray[dtype=np.int32_t, ndim=1,
negative_indices=False, mode='c'] i,
np.ndarray[dtype=np.int32_t, ndim=1,
negative_indices=False, mode='c'] j,
np.ndarray[dtype=np.int32_t, ndim=1,
negative_indices=False, mode='c'] order,
np.ndarray[dtype=np.uint8_t, ndim=1,
negative_indices=False, mode='c'] table):
def _skeletonize_loop(cnp.ndarray[dtype=cnp.uint8_t, ndim=2,
negative_indices=False, mode='c'] result,
cnp.ndarray[dtype=cnp.intp_t, ndim=1,
negative_indices=False, mode='c'] i,
cnp.ndarray[dtype=cnp.intp_t, ndim=1,
negative_indices=False, mode='c'] j,
cnp.ndarray[dtype=cnp.int32_t, ndim=1,
negative_indices=False, mode='c'] order,
cnp.ndarray[dtype=cnp.uint8_t, ndim=1,
negative_indices=False, mode='c'] table):
"""
Inner loop of skeletonize function
@@ -37,13 +41,13 @@ def _skeletonize_loop(np.ndarray[dtype=np.uint8_t, ndim=2,
i, j : ndarrays
The coordinates of each foreground pixel in the image
order : ndarray
The index of each pixel, in the order of processing (order[0] is
the first pixel to process, etc.)
table : ndarray
The 512-element lookup table of values after transformation
The 512-element lookup table of values after transformation
(whether to keep or not each configuration in a binary 3x3 array)
Notes
@@ -55,15 +59,15 @@ def _skeletonize_loop(np.ndarray[dtype=np.uint8_t, ndim=2,
the quench-line of the brushfire will be evaluated later than a
point closer to the edge.
Note that the neighbourhood of a pixel may evolve before the loop
arrives at this pixel. This is why it is possible to compute the
Note that the neighbourhood of a pixel may evolve before the loop
arrives at this pixel. This is why it is possible to compute the
skeleton in only one pass, thanks to an adapted ordering of the
pixels.
"""
cdef:
np.int32_t accumulator
np.int32_t index, order_index
np.int32_t ii, jj
cnp.int32_t accumulator
Py_ssize_t index, order_index
Py_ssize_t ii, jj
for index in range(order.shape[0]):
accumulator = 16
@@ -92,9 +96,10 @@ def _skeletonize_loop(np.ndarray[dtype=np.uint8_t, ndim=2,
# Assign the value of table corresponding to the configuration
result[ii, jj] = table[accumulator]
@cython.boundscheck(False)
def _table_lookup_index(np.ndarray[dtype=np.uint8_t, ndim=2,
negative_indices=False, mode='c'] image):
def _table_lookup_index(cnp.ndarray[dtype=cnp.uint8_t, ndim=2,
negative_indices=False, mode='c'] image):
"""
Return an index into a table per pixel of a binary image
@@ -110,27 +115,27 @@ def _table_lookup_index(np.ndarray[dtype=np.uint8_t, ndim=2,
256 128 64
32 16 8
4 2 1
but this runs about twice as fast because of inlining and the
hardwired kernel.
"""
cdef:
np.ndarray[dtype=np.int32_t, ndim=2,
negative_indices=False, mode='c'] indexer
np.int32_t *p_indexer
np.uint8_t *p_image
np.int32_t i_stride
np.int32_t i_shape
np.int32_t j_shape
np.int32_t i
np.int32_t j
np.int32_t offset
cnp.ndarray[dtype=cnp.int32_t, ndim=2,
negative_indices=False, mode='c'] indexer
cnp.int32_t *p_indexer
cnp.uint8_t *p_image
Py_ssize_t i_stride
Py_ssize_t i_shape
Py_ssize_t j_shape
Py_ssize_t i
Py_ssize_t j
Py_ssize_t offset
i_shape = image.shape[0]
j_shape = image.shape[1]
indexer = np.zeros((i_shape, j_shape), np.int32)
p_indexer = <np.int32_t *>indexer.data
p_image = <np.uint8_t *>image.data
p_indexer = <cnp.int32_t *>indexer.data
p_image = <cnp.uint8_t *>image.data
i_stride = image.strides[0]
assert i_shape >= 3 and j_shape >= 3, \
"Please use the slow method for arrays < 3x3"
+20 -29
View File
@@ -9,39 +9,33 @@ All rights reserved.
Original author: Lee Kamentsky
"""
cdef extern from "numpy/arrayobject.h":
cdef void import_array()
import_array()
import numpy as np
cimport numpy as np
cimport cython
DTYPE_INT32 = np.int32
ctypedef np.int32_t DTYPE_INT32_t
DTYPE_BOOL = np.bool
ctypedef np.int8_t DTYPE_BOOL_t
include "heap_watershed.pxi"
@cython.boundscheck(False)
def watershed(np.ndarray[DTYPE_INT32_t, ndim=1, negative_indices=False,
mode='c'] image,
np.ndarray[DTYPE_INT32_t, ndim=2, negative_indices=False,
mode='c'] pq,
DTYPE_INT32_t age,
np.ndarray[DTYPE_INT32_t, ndim=2, negative_indices=False,
mode='c'] structure,
DTYPE_INT32_t ndim,
np.ndarray[DTYPE_BOOL_t, ndim=1, negative_indices=False,
mode='c'] mask,
np.ndarray[DTYPE_INT32_t, ndim=1, negative_indices=False,
mode='c'] image_shape,
np.ndarray[DTYPE_INT32_t, ndim=1, negative_indices=False,
mode='c'] output):
def watershed(np.ndarray[DTYPE_INT32_t, ndim=1, negative_indices=False,
mode='c'] image,
np.ndarray[DTYPE_INT32_t, ndim=2, negative_indices=False,
mode='c'] pq,
Py_ssize_t age,
np.ndarray[DTYPE_INT32_t, ndim=2, negative_indices=False,
mode='c'] structure,
np.ndarray[DTYPE_BOOL_t, ndim=1, negative_indices=False,
mode='c'] mask,
np.ndarray[DTYPE_INT32_t, ndim=1, negative_indices=False,
mode='c'] output):
"""Do heavy lifting of watershed algorithm
Parameters
----------
@@ -58,20 +52,17 @@ def watershed(np.ndarray[DTYPE_INT32_t, ndim=1, negative_indices=False,
in a flattened array. The remaining elements are the
offsets from the point to its neighbor in the various
dimensions
ndim - # of dimensions in the image
mask - numpy boolean (char) array indicating which pixels to consider
and which to ignore. Also flattened.
image_shape - the dimensions of the image, for boundary checking,
a numpy array of np.int32
output - put the image labels in here
"""
cdef Heapitem elem
cdef Heapitem new_elem
cdef DTYPE_INT32_t nneighbors = structure.shape[0]
cdef DTYPE_INT32_t i = 0
cdef DTYPE_INT32_t index = 0
cdef DTYPE_INT32_t old_index = 0
cdef DTYPE_INT32_t max_index = image.shape[0]
cdef Py_ssize_t nneighbors = structure.shape[0]
cdef Py_ssize_t i = 0
cdef Py_ssize_t index = 0
cdef Py_ssize_t old_index = 0
cdef Py_ssize_t max_index = image.shape[0]
cdef Heap *hp = <Heap *> heap_from_numpy2()
+7 -7
View File
@@ -1,10 +1,10 @@
"""Export fast union find in Cython"""
cimport numpy as np
cimport numpy as cnp
DTYPE = np.int
ctypedef np.int_t DTYPE_t
DTYPE = cnp.intp
ctypedef cnp.intp_t DTYPE_t
cdef DTYPE_t find_root(np.int_t *forest, np.int_t n)
cdef set_root(np.int_t *forest, np.int_t n, np.int_t root)
cdef join_trees(np.int_t *forest, np.int_t n, np.int_t m)
cdef link_bg(np.int_t *forest, np.int_t n, np.int_t *background_node)
cdef DTYPE_t find_root(DTYPE_t *forest, DTYPE_t n)
cdef set_root(DTYPE_t *forest, DTYPE_t n, DTYPE_t root)
cdef join_trees(DTYPE_t *forest, DTYPE_t n, DTYPE_t m)
cdef link_bg(DTYPE_t *forest, DTYPE_t n, DTYPE_t *background_node)
+33 -23
View File
@@ -1,8 +1,11 @@
# -*- python -*-
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
cimport numpy as np
cimport numpy as cnp
"""
See also:
@@ -23,23 +26,25 @@ See also:
# Tree operations implemented by an array as described in Wu et al.
# The term "forest" is used to indicate an array that stores one or more trees
DTYPE = np.int
DTYPE = np.intp
cdef DTYPE_t find_root(np.int_t *forest, np.int_t n):
cdef DTYPE_t find_root(DTYPE_t *forest, DTYPE_t n):
"""Find the root of node n.
"""
cdef np.int_t root = n
cdef DTYPE_t root = n
while (forest[root] < root):
root = forest[root]
return root
cdef set_root(np.int_t *forest, np.int_t n, np.int_t root):
cdef set_root(DTYPE_t *forest, DTYPE_t n, DTYPE_t root):
"""
Set all nodes on a path to point to new_root.
"""
cdef np.int_t j
cdef DTYPE_t j
while (forest[n] < n):
j = forest[n]
forest[n] = root
@@ -48,12 +53,12 @@ cdef set_root(np.int_t *forest, np.int_t n, np.int_t root):
forest[n] = root
cdef join_trees(np.int_t *forest, np.int_t n, np.int_t m):
cdef join_trees(DTYPE_t *forest, DTYPE_t n, DTYPE_t m):
"""Join two trees containing nodes n and m.
"""
cdef np.int_t root = find_root(forest, n)
cdef np.int_t root_m
cdef DTYPE_t root = find_root(forest, n)
cdef DTYPE_t root_m
if (n != m):
root_m = find_root(forest, m)
@@ -64,7 +69,8 @@ cdef join_trees(np.int_t *forest, np.int_t n, np.int_t m):
set_root(forest, n, root)
set_root(forest, m, root)
cdef link_bg(np.int_t *forest, np.int_t n, np.int_t *background_node):
cdef link_bg(DTYPE_t *forest, DTYPE_t n, DTYPE_t *background_node):
"""
Link a node to the background node.
@@ -76,7 +82,7 @@ cdef link_bg(np.int_t *forest, np.int_t n, np.int_t *background_node):
# Connected components search as described in Fiorio et al.
def label(input, np.int_t neighbors=8, np.int_t background=-1):
def label(input, DTYPE_t neighbors=8, DTYPE_t background=-1):
"""Label connected regions of an integer array.
Two pixels are connected when they are neighbors and have the same value.
@@ -134,21 +140,21 @@ def label(input, np.int_t neighbors=8, np.int_t background=-1):
[-1 -1 -1]]
"""
cdef np.int_t rows = input.shape[0]
cdef np.int_t cols = input.shape[1]
cdef DTYPE_t rows = input.shape[0]
cdef DTYPE_t cols = input.shape[1]
cdef np.ndarray[DTYPE_t, ndim=2] data = np.array(input, copy=True,
dtype=DTYPE)
cdef np.ndarray[DTYPE_t, ndim=2] forest
cdef cnp.ndarray[DTYPE_t, ndim=2] data = np.array(input, copy=True,
dtype=DTYPE)
cdef cnp.ndarray[DTYPE_t, ndim=2] forest
forest = np.arange(data.size, dtype=DTYPE).reshape((rows, cols))
cdef np.int_t *forest_p = <np.int_t*>forest.data
cdef np.int_t *data_p = <np.int_t*>data.data
cdef DTYPE_t *forest_p = <DTYPE_t*>forest.data
cdef DTYPE_t *data_p = <DTYPE_t*>data.data
cdef np.int_t i, j
cdef DTYPE_t i, j
cdef np.int_t background_node = -999
cdef DTYPE_t background_node = -999
if neighbors != 4 and neighbors != 8:
raise ValueError('Neighbors must be either 4 or 8.')
@@ -197,7 +203,7 @@ def label(input, np.int_t neighbors=8, np.int_t background=-1):
# Label output
cdef np.int_t ctr = 0
cdef DTYPE_t ctr = 0
for i in range(rows):
for j in range(cols):
if (i*cols + j) == background_node:
@@ -208,4 +214,8 @@ def label(input, np.int_t neighbors=8, np.int_t background=-1):
else:
data[i, j] = data_p[forest[i, j]]
return data
# Work around a bug in ndimage's type checking on 32-bit platforms
if data.dtype == np.int32:
return data.view(np.int32)
else:
return data
+19 -19
View File
@@ -13,13 +13,13 @@ def dilate(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
cdef int rows = image.shape[0]
cdef int cols = image.shape[1]
cdef int srows = selem.shape[0]
cdef int scols = selem.shape[1]
cdef Py_ssize_t rows = image.shape[0]
cdef Py_ssize_t cols = image.shape[1]
cdef Py_ssize_t srows = selem.shape[0]
cdef Py_ssize_t scols = selem.shape[1]
cdef int centre_r = int(selem.shape[0] / 2) - shift_y
cdef int centre_c = int(selem.shape[1] / 2) - shift_x
cdef Py_ssize_t centre_r = int(selem.shape[0] / 2) - shift_y
cdef Py_ssize_t centre_c = int(selem.shape[1] / 2) - shift_x
image = np.ascontiguousarray(image)
if out is None:
@@ -30,11 +30,11 @@ def dilate(np.ndarray[np.uint8_t, ndim=2] image,
cdef np.uint8_t* out_data = <np.uint8_t*>out.data
cdef np.uint8_t* image_data = <np.uint8_t*>image.data
cdef int r, c, rr, cc, s, value, local_max
cdef Py_ssize_t r, c, rr, cc, s, value, local_max
cdef int selem_num = np.sum(selem != 0)
cdef int* sr = <int*>malloc(selem_num * sizeof(int))
cdef int* sc = <int*>malloc(selem_num * sizeof(int))
cdef Py_ssize_t selem_num = np.sum(selem != 0)
cdef Py_ssize_t* sr = <Py_ssize_t*>malloc(selem_num * sizeof(Py_ssize_t))
cdef Py_ssize_t* sc = <Py_ssize_t*>malloc(selem_num * sizeof(Py_ssize_t))
s = 0
for r in range(srows):
@@ -68,13 +68,13 @@ def erode(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
cdef int rows = image.shape[0]
cdef int cols = image.shape[1]
cdef int srows = selem.shape[0]
cdef int scols = selem.shape[1]
cdef Py_ssize_t rows = image.shape[0]
cdef Py_ssize_t cols = image.shape[1]
cdef Py_ssize_t srows = selem.shape[0]
cdef Py_ssize_t scols = selem.shape[1]
cdef int centre_r = int(selem.shape[0] / 2) - shift_y
cdef int centre_c = int(selem.shape[1] / 2) - shift_x
cdef Py_ssize_t centre_r = int(selem.shape[0] / 2) - shift_y
cdef Py_ssize_t centre_c = int(selem.shape[1] / 2) - shift_x
image = np.ascontiguousarray(image)
if out is None:
@@ -87,9 +87,9 @@ def erode(np.ndarray[np.uint8_t, ndim=2] image,
cdef int r, c, rr, cc, s, value, local_min
cdef int selem_num = np.sum(selem != 0)
cdef int* sr = <int*>malloc(selem_num * sizeof(int))
cdef int* sc = <int*>malloc(selem_num * sizeof(int))
cdef Py_ssize_t selem_num = np.sum(selem != 0)
cdef Py_ssize_t* sr = <Py_ssize_t*>malloc(selem_num * sizeof(Py_ssize_t))
cdef Py_ssize_t* sc = <Py_ssize_t*>malloc(selem_num * sizeof(Py_ssize_t))
s = 0
for r in range(srows):
+42 -42
View File
@@ -10,21 +10,18 @@ All rights reserved.
Original author: Lee Kamentsky
"""
cdef extern from "stdlib.h":
ctypedef unsigned long size_t
void free(void *ptr)
void *malloc(size_t size)
void *realloc(void *ptr, size_t size)
from libc.stdlib cimport free, malloc, realloc
cdef struct Heap:
unsigned int items
unsigned int space
Py_ssize_t items
Py_ssize_t space
Heapitem *data
Heapitem **ptrs
cdef inline Heap *heap_from_numpy2():
cdef unsigned int k
cdef Heap *heap
cdef Py_ssize_t k
cdef Heap *heap
heap = <Heap *> malloc(sizeof (Heap))
heap.items = 0
heap.space = 1000
@@ -39,7 +36,7 @@ cdef inline void heap_done(Heap *heap):
free(heap.ptrs)
free(heap)
cdef inline void swap(unsigned int a, unsigned int b, Heap *h):
cdef inline void swap(Py_ssize_t a, Py_ssize_t b, Heap *h):
h.ptrs[a], h.ptrs[b] = h.ptrs[b], h.ptrs[a]
@@ -47,13 +44,13 @@ cdef inline void swap(unsigned int a, unsigned int b, Heap *h):
# heappop - inlined
#
# pop an element off the heap, maintaining heap invariant
#
#
# Note: heap ordering is the same as python heapq, i.e., smallest first.
######################################################
cdef inline void heappop(Heap *heap,
Heapitem *dest):
cdef unsigned int i, smallest, l, r # heap indices
cdef inline void heappop(Heap *heap, Heapitem *dest):
cdef Py_ssize_t i, smallest, l, r # heap indices
#
# Start by copying the first element to the destination
#
@@ -76,10 +73,10 @@ cdef inline void heappop(Heap *heap,
smallest = i
while True:
# loop invariant here: smallest == i
# find smallest of (i, l, r), and swap it to i's position if necessary
l = i*2+1 #__left(i)
r = i*2+2 #__right(i)
l = i * 2 + 1 #__left(i)
r = i * 2 + 2 #__right(i)
if l < heap.items:
if smaller(heap.ptrs[l], heap.ptrs[i]):
smallest = l
@@ -88,13 +85,14 @@ cdef inline void heappop(Heap *heap,
else:
# this is unnecessary, but trims 0.04 out of 0.85 seconds...
break
# the element at i is smaller than either of its children, heap invariant restored.
# the element at i is smaller than either of its children, heap
# invariant restored.
if smallest == i:
break
# swap
swap(i, smallest, heap)
i = smallest
##################################################
# heappush - inlined
#
@@ -102,34 +100,36 @@ cdef inline void heappop(Heap *heap,
#
# Note: heap ordering is the same as python heapq, i.e., smallest first.
##################################################
cdef inline void heappush(Heap *heap,
Heapitem *new_elem):
cdef unsigned int child = heap.items
cdef unsigned int parent
cdef unsigned int k
cdef Heapitem *new_data
cdef inline void heappush(Heap *heap, Heapitem *new_elem):
# grow if necessary
if heap.items == heap.space:
cdef Py_ssize_t child = heap.items
cdef Py_ssize_t parent
cdef Py_ssize_t k
cdef Heapitem *new_data
# grow if necessary
if heap.items == heap.space:
heap.space = heap.space * 2
new_data = <Heapitem *> realloc(<void *> heap.data, <size_t> (heap.space * sizeof(Heapitem)))
heap.ptrs = <Heapitem **> realloc(<void *> heap.ptrs, <size_t> (heap.space * sizeof(Heapitem *)))
new_data = <Heapitem*>realloc(<void*>heap.data,
<Py_ssize_t>(heap.space * sizeof(Heapitem)))
heap.ptrs = <Heapitem**>realloc(<void*>heap.ptrs,
<Py_ssize_t>(heap.space * sizeof(Heapitem *)))
for k in range(heap.items):
heap.ptrs[k] = new_data + (heap.ptrs[k] - heap.data)
for k in range(heap.items, heap.space):
heap.ptrs[k] = new_data + k
heap.data = new_data
# insert new data at child
heap.ptrs[child][0] = new_elem[0]
heap.items += 1
# insert new data at child
heap.ptrs[child][0] = new_elem[0]
heap.items += 1
# restore heap invariant, all parents <= children
while child>0:
parent = (child + 1) / 2 - 1 # __parent(i)
if smaller(heap.ptrs[child], heap.ptrs[parent]):
swap(parent, child, heap)
child = parent
else:
break
# restore heap invariant, all parents <= children
while child > 0:
parent = (child + 1) / 2 - 1 # __parent(i)
if smaller(heap.ptrs[child], heap.ptrs[parent]):
swap(parent, child, heap)
child = parent
else:
break
+8 -7
View File
@@ -9,18 +9,19 @@ All rights reserved.
Original author: Lee Kamentsky
"""
import numpy as np
cimport numpy as np
cimport cython
cimport numpy as cnp
cdef struct Heapitem:
np.int32_t value
np.int32_t age
np.int32_t index
cnp.int32_t value
cnp.int32_t age
Py_ssize_t index
cdef inline int smaller(Heapitem *a, Heapitem *b):
if a.value <> b.value:
return a.value < b.value
return a.value < b.value
return a.age < b.age
include "heap_general.pxi"
+85
View File
@@ -0,0 +1,85 @@
import numpy as np
import scipy.ndimage as nd
def remove_small_objects(ar, min_size=64, connectivity=1, in_place=False):
"""Remove connected components smaller than the specified size.
Parameters
----------
ar : ndarray (arbitrary shape, int or bool type)
The array containing the connected components of interest. If the array
type is int, it is assumed that it contains already-labeled objects.
The ints must be non-negative.
min_size : int, optional (default: 64)
The smallest allowable connected component size.
connectivity : int, {1, 2, ..., ar.ndim}, optional (default: 1)
The connectivity defining the neighborhood of a pixel.
in_place : bool, optional (default: False)
If `True`, remove the connected components in the input array itself.
Otherwise, make a copy.
Raises
------
TypeError
If the input array is of an invalid type, such as float or string.
ValueError
If the input array contains negative values.
Returns
-------
out : ndarray, same shape and type as input `ar`
The input array with small connected components removed.
Examples
--------
>>> from skimage import morphology
>>> from scipy import ndimage as nd
>>> a = np.array([[0, 0, 0, 1, 0],
... [1, 1, 1, 0, 0],
... [1, 1, 1, 0, 1]], bool)
>>> b = morphology.remove_small_connected_components(a, 6)
>>> b
array([[False, False, False, False, False],
[ True, True, True, False, False],
[ True, True, True, False, False]], dtype=bool)
>>> c = morphology.remove_small_connected_components(a, 7, connectivity=2)
>>> c
array([[False, False, False, True, False],
[ True, True, True, False, False],
[ True, True, True, False, False]], dtype=bool)
>>> d = morphology.remove_small_connected_components(a, 6, in_place=True)
>>> d is a
True
"""
# Should use `issubdtype` for bool below, but there's a bug in numpy 1.7
if not (ar.dtype == bool or np.issubdtype(ar.dtype, int)):
raise TypeError("Only bool or integer image types are supported. "
"Got %s." % ar.dtype)
if in_place:
out = ar
else:
out = ar.copy()
if min_size == 0: # shortcut for efficiency
return out
if out.dtype == bool:
selem = nd.generate_binary_structure(ar.ndim, connectivity)
ccs = nd.label(ar, selem)[0]
else:
ccs = out
try:
component_sizes = np.bincount(ccs.ravel())
except ValueError:
raise ValueError("Negative value labels are not supported. Try "
"relabeling the input with `scipy.ndimage.label` or "
"`skimage.morphology.label`.")
too_small = component_sizes < min_size
too_small_mask = too_small[ccs]
out[too_small_mask] = 0
return out
+56
View File
@@ -0,0 +1,56 @@
import numpy as np
from numpy.testing import assert_array_equal, assert_equal, assert_raises
from skimage.morphology import remove_small_objects
test_image = np.array([[0, 0, 0, 1, 0],
[1, 1, 1, 0, 0],
[1, 1, 1, 0, 1]], bool)
def test_one_connectivity():
expected = np.array([[0, 0, 0, 0, 0],
[1, 1, 1, 0, 0],
[1, 1, 1, 0, 0]], bool)
observed = remove_small_objects(test_image, min_size=6)
assert_array_equal(observed, expected)
def test_two_connectivity():
expected = np.array([[0, 0, 0, 1, 0],
[1, 1, 1, 0, 0],
[1, 1, 1, 0, 0]], bool)
observed = remove_small_objects(test_image, min_size=7, connectivity=2)
assert_array_equal(observed, expected)
def test_in_place():
observed = remove_small_objects(test_image, min_size=6, in_place=True)
assert_equal(observed is test_image, True,
"remove_small_objects in_place argument failed.")
def test_labeled_image():
labeled_image = np.array([[2, 2, 2, 0, 1],
[2, 2, 2, 0, 1],
[2, 0, 0, 0, 0],
[0, 0, 3, 3, 3]], dtype=int)
expected = np.array([[2, 2, 2, 0, 0],
[2, 2, 2, 0, 0],
[2, 0, 0, 0, 0],
[0, 0, 3, 3, 3]], dtype=int)
observed = remove_small_objects(labeled_image, min_size=3)
assert_array_equal(observed, expected)
def test_float_input():
float_test = np.random.rand(5, 5)
assert_raises(TypeError, remove_small_objects, float_test)
def test_negative_input():
negative_int = np.random.randint(-4, -1, size=(5, 5))
assert_raises(ValueError, remove_small_objects, negative_int)
if __name__ == "__main__":
np.testing.run_module_suite()
-2
View File
@@ -214,9 +214,7 @@ def watershed(image, markers, connectivity=None, offset=None, mask=None):
c_mask = c_mask.astype(np.int8).flatten()
_watershed.watershed(c_image.flatten(),
pq, age, c,
c_image.ndim,
c_mask,
np.array(c_image.shape, np.int32),
c_output)
c_output = c_output.reshape(c_image.shape)[[slice(1, -1, None)] *
image.ndim]
+19 -17
View File
@@ -1,16 +1,18 @@
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
cimport numpy as np
import scipy
cimport cython
cimport cython
cimport numpy as cnp
from skimage.morphology.ccomp cimport find_root, join_trees
from ..util import img_as_float
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)
def _felzenszwalb_grey(image, double scale=1, sigma=0.8, int min_size=20):
def _felzenszwalb_grey(image, double scale=1, sigma=0.8, Py_ssize_t min_size=20):
"""Felzenszwalb's efficient graph based segmentation for a single channel.
Produces an oversegmentation of a 2d image using a fast, minimum spanning
@@ -49,31 +51,31 @@ def _felzenszwalb_grey(image, double scale=1, sigma=0.8, int min_size=20):
down_cost = np.abs((image[:, 1:] - image[:, :-1]))
dright_cost = np.abs((image[1:, 1:] - image[:-1, :-1]))
uright_cost = np.abs((image[1:, :-1] - image[:-1, 1:]))
cdef np.ndarray[np.float_t, ndim=1] costs = np.hstack([right_cost.ravel(),
cdef cnp.ndarray[cnp.float_t, ndim=1] costs = np.hstack([right_cost.ravel(),
down_cost.ravel(), dright_cost.ravel(),
uright_cost.ravel()]).astype(np.float)
# compute edges between pixels:
height, width = image.shape[:2]
cdef np.ndarray[np.int_t, ndim=2] segments \
= np.arange(width * height, dtype=np.int).reshape(height, width)
cdef cnp.ndarray[cnp.intp_t, ndim=2] segments \
= np.arange(width * height, dtype=np.intp).reshape(height, width)
right_edges = np.c_[segments[1:, :].ravel(), segments[:-1, :].ravel()]
down_edges = np.c_[segments[:, 1:].ravel(), segments[:, :-1].ravel()]
dright_edges = np.c_[segments[1:, 1:].ravel(), segments[:-1, :-1].ravel()]
uright_edges = np.c_[segments[:-1, 1:].ravel(), segments[1:, :-1].ravel()]
cdef np.ndarray[np.int_t, ndim=2] edges \
cdef cnp.ndarray[cnp.intp_t, ndim=2] edges \
= np.vstack([right_edges, down_edges, dright_edges, uright_edges])
# initialize data structures for segment size
# and inner cost, then start greedy iteration over edges.
edge_queue = np.argsort(costs)
edges = np.ascontiguousarray(edges[edge_queue])
costs = np.ascontiguousarray(costs[edge_queue])
cdef np.int_t *segments_p = <np.int_t*>segments.data
cdef np.int_t *edges_p = <np.int_t*>edges.data
cdef np.float_t *costs_p = <np.float_t*>costs.data
cdef np.ndarray[np.int_t, ndim=1] segment_size \
= np.ones(width * height, dtype=np.int)
cdef cnp.intp_t *segments_p = <cnp.intp_t*>segments.data
cdef cnp.intp_t *edges_p = <cnp.intp_t*>edges.data
cdef cnp.float_t *costs_p = <cnp.float_t*>costs.data
cdef cnp.ndarray[cnp.intp_t, ndim=1] segment_size \
= np.ones(width * height, dtype=np.intp)
# inner cost of segments
cdef np.ndarray[np.float_t, ndim=1] cint = np.zeros(width * height)
cdef cnp.ndarray[cnp.float_t, ndim=1] cint = np.zeros(width * height)
cdef int seg0, seg1, seg_new, e
cdef float cost, inner_cost0, inner_cost1
# set costs_p back one. we increase it before we use it
@@ -96,7 +98,7 @@ def _felzenszwalb_grey(image, double scale=1, sigma=0.8, int min_size=20):
cint[seg_new] = costs_p[0]
# postprocessing to remove small segments
edges_p = <np.int_t*>edges.data
edges_p = <cnp.intp_t*>edges.data
for e in range(costs.size):
seg0 = find_root(segments_p, edges_p[0])
seg1 = find_root(segments_p, edges_p[1])
+20 -18
View File
@@ -1,18 +1,18 @@
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
cimport numpy as np
cimport cython
from libc.math cimport exp, sqrt
from itertools import product
from scipy import ndimage
from itertools import product
cimport numpy as cnp
from libc.math cimport exp, sqrt
from ..util import img_as_float
from ..color import rgb2lab
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)
def quickshift(image, ratio=1., float kernel_size=5, max_dist=10,
return_tree=False, sigma=0, convert2lab=True, random_seed=None):
"""Segments image using quickshift clustering in Color-(x,y) space.
@@ -69,7 +69,7 @@ def quickshift(image, ratio=1., float kernel_size=5, max_dist=10,
image = rgb2lab(image)
image = ndimage.gaussian_filter(img_as_float(image), [sigma, sigma, 0])
cdef np.ndarray[dtype=np.float_t, ndim=3, mode="c"] image_c \
cdef cnp.ndarray[dtype=cnp.float_t, ndim=3, mode="c"] image_c \
= np.ascontiguousarray(image) * ratio
random_state = np.random.RandomState(random_seed)
@@ -85,18 +85,19 @@ def quickshift(image, ratio=1., float kernel_size=5, max_dist=10,
raise ValueError("Sigma should be >= 1")
cdef int w = int(3 * kernel_size)
cdef int height = image_c.shape[0]
cdef int width = image_c.shape[1]
cdef int channels = image_c.shape[2]
cdef Py_ssize_t height = image_c.shape[0]
cdef Py_ssize_t width = image_c.shape[1]
cdef Py_ssize_t channels = image_c.shape[2]
cdef double current_density, closest, dist
cdef int r, c, r_, c_, channel
cdef Py_ssize_t r, c, r_, c_, channel, r_min, c_min
cdef np.float_t* image_p = <np.float_t*> image_c.data
cdef np.float_t* current_pixel_p = image_p
cdef cnp.float_t* image_p = <cnp.float_t*> image_c.data
cdef cnp.float_t* current_pixel_p = image_p
cdef np.ndarray[dtype=np.float_t, ndim=2] densities \
cdef cnp.ndarray[dtype=cnp.float_t, ndim=2] densities \
= np.zeros((height, width))
# compute densities
for r in range(height):
for c in range(width):
@@ -116,10 +117,11 @@ def quickshift(image, ratio=1., float kernel_size=5, max_dist=10,
densities += random_state.normal(scale=0.00001, size=(height, width))
# default parent to self:
cdef np.ndarray[dtype=np.int_t, ndim=2] parent \
cdef cnp.ndarray[dtype=cnp.int_t, ndim=2] parent \
= np.arange(width * height).reshape(height, width)
cdef np.ndarray[dtype=np.float_t, ndim=2] dist_parent \
cdef cnp.ndarray[dtype=cnp.float_t, ndim=2] dist_parent \
= np.zeros((height, width))
# find nearest node with higher density
current_pixel_p = image_p
for r in range(height):
+23 -17
View File
@@ -1,13 +1,19 @@
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
cimport numpy as np
from time import time
from scipy import ndimage
cimport numpy as cnp
from ..util import img_as_float
from ..color import rgb2lab, gray2rgb
def slic(image, n_segments=100, ratio=10., max_iter=10, sigma=1,
convert2lab=True):
convert2lab=True):
"""Segments image using k-means clustering in Color-(x,y) space.
Parameters
@@ -62,41 +68,41 @@ def slic(image, n_segments=100, ratio=10., max_iter=10, sigma=1,
image = rgb2lab(image)
# initialize on grid:
cdef int height, width
cdef Py_ssize_t height, width
height, width = image.shape[:2]
# approximate grid size for desired n_segments
cdef int step = np.ceil(np.sqrt(height * width / n_segments))
cdef Py_ssize_t step = int(np.ceil(np.sqrt(height * width / n_segments)))
grid_y, grid_x = np.mgrid[:height, :width]
means_y = grid_y[::step, ::step]
means_x = grid_x[::step, ::step]
means_color = np.zeros((means_y.shape[0], means_y.shape[1], 3))
cdef np.ndarray[dtype=np.float_t, ndim=2] means \
cdef cnp.ndarray[dtype=cnp.float_t, ndim=2] means \
= np.dstack([means_y, means_x, means_color]).reshape(-1, 5)
cdef np.float_t* current_mean
cdef np.float_t* mean_entry
cdef cnp.float_t* current_mean
cdef cnp.float_t* mean_entry
n_means = means.shape[0]
# we do the scaling of ratio in the same way as in the SLIC paper
# so the values have the same meaning
ratio = (ratio / float(step)) ** 2
cdef np.ndarray[dtype=np.float_t, ndim=3] image_yx \
cdef cnp.ndarray[dtype=cnp.float_t, ndim=3] image_yx \
= np.dstack([grid_y, grid_x, image / ratio]).copy("C")
cdef int i, k, x, y, x_min, x_max, y_min, y_max, changes
cdef Py_ssize_t i, k, x, y, x_min, x_max, y_min, y_max, changes
cdef double dist_mean
cdef np.ndarray[dtype=np.int_t, ndim=2] nearest_mean \
= np.zeros((height, width), dtype=np.int)
cdef np.ndarray[dtype=np.float_t, ndim=2] distance \
cdef cnp.ndarray[dtype=cnp.intp_t, ndim=2] nearest_mean \
= np.zeros((height, width), dtype=np.intp)
cdef cnp.ndarray[dtype=cnp.float_t, ndim=2] distance \
= np.empty((height, width))
cdef np.float_t* image_p = <np.float_t*> image_yx.data
cdef np.float_t* distance_p = <np.float_t*> distance.data
cdef np.float_t* current_distance
cdef np.float_t* current_pixel
cdef cnp.float_t* image_p = <cnp.float_t*> image_yx.data
cdef cnp.float_t* distance_p = <cnp.float_t*> distance.data
cdef cnp.float_t* current_distance
cdef cnp.float_t* current_pixel
cdef double tmp
for i in range(max_iter):
distance.fill(np.inf)
changes = 0
current_mean = <np.float_t*> means.data
current_mean = <cnp.float_t*> means.data
# assign pixels to means
for k in range(n_means):
# compute windows:
@@ -30,8 +30,7 @@ from ..filter import rank_order
def _make_graph_edges_3d(n_x, n_y, n_z):
"""
Returns a list of edges for a 3D image.
"""Returns a list of edges for a 3D image.
Parameters
----------
@@ -45,9 +44,12 @@ def _make_graph_edges_3d(n_x, n_y, n_z):
Returns
-------
edges : (2, N) ndarray
with the total number of edges N = n_x * n_y * (nz - 1) +
n_x * (n_y - 1) * nz +
(n_x - 1) * n_y * nz
with the total number of edges::
N = n_x * n_y * (nz - 1) +
n_x * (n_y - 1) * nz +
(n_x - 1) * n_y * nz
Graph edges with each column describing a node-id pair.
"""
vertices = np.arange(n_x * n_y * n_z).reshape((n_x, n_y, n_z))
@@ -200,6 +202,7 @@ def random_walker(data, labels, beta=130, mode='bf', tol=1.e-3, copy=True,
mode : {'bf', 'cg_mg', 'cg'} (default: 'bf')
Mode for solving the linear system in the random walker
algorithm.
- 'bf' (brute force, default): an LU factorization of the Laplacian is
computed. This is fast for small images (<1024x1024), but very slow
(due to the memory cost) and memory-consuming for big images (in 3-D
@@ -214,6 +217,7 @@ def random_walker(data, labels, beta=130, mode='bf', tol=1.e-3, copy=True,
requires that the pyamg module (http://code.google.com/p/pyamg/) is
installed. For images of size > 512x512, this is the recommended
(fastest) mode.
tol : float
tolerance to achieve when solving the linear system, in
cg' and 'cg_mg' modes.
@@ -237,12 +241,12 @@ def random_walker(data, labels, beta=130, mode='bf', tol=1.e-3, copy=True,
Returns
-------
output : ndarray
If `return_full_prob` is False, array of ints of same shape as `data`,
in which each pixel has been labeled according to the marker that
reached the pixel first by anisotropic diffusion.
If `return_full_prob` is True, array of floats of shape
`(nlabels, data.shape)`. `output[label_nb, i, j]` is the probability
that label `label_nb` reaches the pixel `(i, j)` first.
* If `return_full_prob` is False, array of ints of same shape as
`data`, in which each pixel has been labeled according to the marker
that reached the pixel first by anisotropic diffusion.
* If `return_full_prob` is True, array of floats of shape
`(nlabels, data.shape)`. `output[label_nb, i, j]` is the probability
that label `label_nb` reaches the pixel `(i, j)` first.
See also
--------
+3 -3
View File
@@ -13,8 +13,8 @@ def test_color():
img[img > 1] = 1
img[img < 0] = 0
seg = slic(img, sigma=0, n_segments=4)
# we expect 4 segments:
print(seg)
# we expect 4 segments
assert_equal(len(np.unique(seg)), 4)
assert_array_equal(seg[:10, :10], 0)
assert_array_equal(seg[10:, :10], 2)
@@ -31,7 +31,7 @@ def test_gray():
img[img > 1] = 1
img[img < 0] = 0
seg = slic(img, sigma=0, n_segments=4, ratio=50.0)
print(seg)
assert_equal(len(np.unique(seg)), 4)
assert_array_equal(seg[:10, :10], 0)
assert_array_equal(seg[10:, :10], 2)
+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, rescale
from ._warps import swirl, resize, rotate, rescale
from .pyramids import (pyramid_reduce, pyramid_expand,
pyramid_gaussian, pyramid_laplacian)
+144 -63
View File
@@ -1,31 +1,101 @@
cimport cython
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
cimport numpy as np
from random import randint
from libc.math cimport abs, fabs, sqrt, ceil, floor
cimport numpy as cnp
cimport cython
from libc.math cimport abs, fabs, sqrt, ceil
from libc.stdlib cimport rand
np.import_array()
from skimage.draw import circle_perimeter
cdef double PI_2 = 1.5707963267948966
cdef double NEG_PI_2 = -PI_2
cdef inline int round(double r):
return <int>((r + 0.5) if (r > 0.0) else (r - 0.5))
cdef inline Py_ssize_t round(double r):
return <Py_ssize_t>((r + 0.5) if (r > 0.0) else (r - 0.5))
@cython.boundscheck(False)
def _hough(np.ndarray img, np.ndarray[ndim=1, dtype=np.double_t] theta=None):
def _hough_circle(cnp.ndarray img,
cnp.ndarray[ndim=1, dtype=cnp.intp_t] radius,
char normalize=True):
"""Perform a circular Hough transform.
Parameters
----------
img : (M, N) ndarray
Input image with nonzero values representing edges.
radius : ndarray
Radii at which to compute the Hough transform.
normalize : boolean, optional
Normalize the accumulator with the number
of pixels used to draw the radius
Returns
-------
H : 3D ndarray (radius index, (M, N) ndarray)
Hough transform accumulator for each radius
"""
if img.ndim != 2:
raise ValueError('The input image must be 2D.')
# compute the nonzero indexes
cdef cnp.ndarray[ndim=1, dtype=cnp.intp_t] x, y
x, y = np.nonzero(img)
cdef Py_ssize_t num_pixels = x.size
# Offset the image
cdef Py_ssize_t max_radius = radius.max()
x = x + max_radius
y = y + max_radius
cdef Py_ssize_t i, p, c, num_circle_pixels, tx, ty
cdef double incr
cdef cnp.ndarray[ndim=1, dtype=cnp.intp_t] circle_x, circle_y
cdef cnp.ndarray[ndim=3, dtype=cnp.double_t] acc = \
np.zeros((radius.size,
img.shape[0] + 2 * max_radius,
img.shape[1] + 2 * max_radius), dtype=np.double)
for i, rad in enumerate(radius):
# Store in memory the circle of given radius
# centered at (0,0)
circle_x, circle_y = circle_perimeter(0, 0, rad)
num_circle_pixels = circle_x.size
if normalize:
incr = 1.0 / num_circle_pixels
else:
incr = 1
# For each non zero pixel
for p in range(num_pixels):
# Plug the circle at (px, py),
# its coordinates are (tx, ty)
for c in range(num_circle_pixels):
tx = circle_x[c] + x[p]
ty = circle_y[c] + y[p]
acc[i, tx, ty] += incr
return acc
def _hough(cnp.ndarray img, cnp.ndarray[ndim=1, dtype=cnp.double_t] theta=None):
if img.ndim != 2:
raise ValueError('The input image must be 2D.')
# Compute the array of angles and their sine and cosine
cdef np.ndarray[ndim=1, dtype=np.double_t] ctheta
cdef np.ndarray[ndim=1, dtype=np.double_t] stheta
cdef cnp.ndarray[ndim=1, dtype=cnp.double_t] ctheta
cdef cnp.ndarray[ndim=1, dtype=cnp.double_t] stheta
if theta is None:
theta = np.linspace(PI_2, NEG_PI_2, 180)
@@ -34,23 +104,22 @@ def _hough(np.ndarray img, np.ndarray[ndim=1, dtype=np.double_t] theta=None):
stheta = np.sin(theta)
# compute the bins and allocate the accumulator array
cdef np.ndarray[ndim=2, dtype=np.uint64_t] accum
cdef np.ndarray[ndim=1, dtype=np.double_t] bins
cdef int max_distance, offset
cdef cnp.ndarray[ndim=2, dtype=cnp.uint64_t] accum
cdef cnp.ndarray[ndim=1, dtype=cnp.double_t] bins
cdef Py_ssize_t max_distance, offset
max_distance = 2 * <int>ceil((sqrt(img.shape[0] * img.shape[0] +
img.shape[1] * img.shape[1])))
max_distance = 2 * <Py_ssize_t>ceil(sqrt(img.shape[0] * img.shape[0] +
img.shape[1] * img.shape[1]))
accum = np.zeros((max_distance, theta.shape[0]), dtype=np.uint64)
bins = np.linspace(-max_distance / 2.0, max_distance / 2.0, max_distance)
offset = max_distance / 2
# compute the nonzero indexes
cdef np.ndarray[ndim=1, dtype=np.npy_intp] x_idxs, y_idxs
y_idxs, x_idxs = np.PyArray_Nonzero(img)
cdef cnp.ndarray[ndim=1, dtype=cnp.npy_intp] x_idxs, y_idxs
y_idxs, x_idxs = np.nonzero(img)
# finally, run the transform
cdef int nidxs, nthetas, i, j, x, y, accum_idx
cdef Py_ssize_t nidxs, nthetas, i, j, x, y, accum_idx
nidxs = y_idxs.shape[0] # x and y are the same shape
nthetas = theta.shape[0]
for i in range(nidxs):
@@ -61,67 +130,75 @@ def _hough(np.ndarray img, np.ndarray[ndim=1, dtype=np.double_t] theta=None):
accum[accum_idx, j] += 1
return accum, theta, bins
import math
@cython.cdivision(True)
@cython.boundscheck(False)
def _probabilistic_hough(np.ndarray img, int value_threshold, int line_length, \
int line_gap, np.ndarray[ndim=1, dtype=np.double_t] theta=None):
def _probabilistic_hough(cnp.ndarray img, int value_threshold,
int line_length, int line_gap,
cnp.ndarray[ndim=1, dtype=cnp.double_t] theta=None):
if img.ndim != 2:
raise ValueError('The input image must be 2D.')
# compute the array of angles and their sine and cosine
cdef np.ndarray[ndim=1, dtype=np.double_t] ctheta
cdef np.ndarray[ndim=1, dtype=np.double_t] stheta
# calculate thetas if none specified
if theta is None:
theta = np.linspace(math.pi/2, -math.pi/2, 180)
theta = math.pi/2-np.arange(180)/180.0* math.pi
ctheta = np.cos(theta)
stheta = np.sin(theta)
cdef int height = img.shape[0]
cdef int width = img.shape[1]
theta = PI_2 - np.arange(180) / 180.0 * 2 * PI_2
cdef Py_ssize_t height = img.shape[0]
cdef Py_ssize_t width = img.shape[1]
# compute the bins and allocate the accumulator array
cdef np.ndarray[ndim=2, dtype=np.int64_t] accum
cdef np.ndarray[ndim=2, dtype=np.uint8_t] mask = np.zeros((height, width), dtype=np.uint8)
cdef np.ndarray[ndim=2, dtype=np.int32_t] line_end = np.zeros((2, 2), dtype=np.int32)
cdef int max_distance, offset, num_indexes, index
cdef cnp.ndarray[ndim=2, dtype=cnp.int64_t] accum
cdef cnp.ndarray[ndim=1, dtype=cnp.double_t] ctheta, stheta
cdef cnp.ndarray[ndim=2, dtype=cnp.uint8_t] mask = \
np.zeros((height, width), dtype=np.uint8)
cdef cnp.ndarray[ndim=2, dtype=cnp.int32_t] line_end = \
np.zeros((2, 2), dtype=np.int32)
cdef Py_ssize_t max_distance, offset, num_indexes, index
cdef double a, b
cdef int nidxs, nthetas, i, j, x, y, px, py, accum_idx, value, max_value, max_theta
cdef Py_ssize_t nidxs, i, j, x, y, px, py, accum_idx
cdef int value, max_value, max_theta
cdef int shift = 16
# maximum line number cutoff
cdef int lines_max = 2 ** 15
cdef int xflag, x0, y0, dx0, dy0, dx, dy, gap, x1, y1, good_line, count
cdef Py_ssize_t lines_max = 2 ** 15
cdef Py_ssize_t xflag, x0, y0, dx0, dy0, dx, dy, gap, x1, y1, \
good_line, count
cdef list lines = list()
max_distance = 2 * <int>ceil((sqrt(img.shape[0] * img.shape[0] +
img.shape[1] * img.shape[1])))
accum = np.zeros((max_distance, theta.shape[0]), dtype=np.int64)
offset = max_distance / 2
# find the nonzero indexes
cdef np.ndarray[ndim=1, dtype=np.npy_intp] x_idxs, y_idxs
y_idxs, x_idxs = np.nonzero(img)
num_indexes = y_idxs.shape[0] # x and y are the same shape
nthetas = theta.shape[0]
points = []
for i in range(num_indexes):
points.append((x_idxs[i], y_idxs[i]))
lines = []
# create mask of all non-zero indexes
for i in range(num_indexes):
mask[y_idxs[i], x_idxs[i]] = 1
# compute sine and cosine of angles
ctheta = np.cos(theta)
stheta = np.sin(theta)
# find the nonzero indexes
y_idxs, x_idxs = np.nonzero(img)
points = list(zip(x_idxs, y_idxs))
# mask all non-zero indexes
mask[y_idxs, x_idxs] = 1
while 1:
# select random non-zero point
# quit if no remaining points
count = len(points)
if count == 0:
break
index = rand() % (count)
# select random non-zero point
index = rand() % count
x = points[index][0]
y = points[index][1]
del points[index]
# if previously eliminated, skip
if not mask[y, x]:
continue
value = 0
max_value = value_threshold-1
max_value = value_threshold - 1
max_theta = -1
# apply hough transform on point
for j in range(nthetas):
accum_idx = <int>round((ctheta[j] * x + stheta[j] * y)) + offset
@@ -132,7 +209,9 @@ def _probabilistic_hough(np.ndarray img, int value_threshold, int line_length, \
max_theta = j
if max_value < value_threshold:
continue
# from the random point walk in opposite directions and find line beginning and end
# from the random point walk in opposite directions and find line
# beginning and end
a = -stheta[max_theta]
b = ctheta[max_theta]
x0 = x
@@ -188,6 +267,7 @@ def _probabilistic_hough(np.ndarray img, int value_threshold, int line_length, \
# confirm line length is sufficient
good_line = abs(line_end[1, 1] - line_end[0, 1]) >= line_length or \
abs(line_end[1, 0] - line_end[0, 0]) >= line_length
# pass 2: walk the line again and reset accumulator and mask
for k in range(2):
px = x0
@@ -207,7 +287,8 @@ def _probabilistic_hough(np.ndarray img, int value_threshold, int line_length, \
# if non-zero point found, continue the line
if mask[y1, x1]:
if good_line:
accum_idx = <int>round((ctheta[j] * x1 + stheta[j] * y1)) + offset
accum_idx = <int>round((ctheta[j] * x1 \
+ stheta[j] * y1)) + offset
accum[accum_idx, max_theta] -= 1
mask[y1, x1] = 0
# exit when the point is the line end
@@ -218,9 +299,9 @@ def _probabilistic_hough(np.ndarray img, int value_threshold, int line_length, \
# add line to the result
if good_line:
lines.append(((line_end[0, 0], line_end[0, 1]), (line_end[1, 0], line_end[1, 1])))
lines.append(((line_end[0, 0], line_end[0, 1]),
(line_end[1, 0], line_end[1, 1])))
if len(lines) > lines_max:
return lines
return lines
+1 -99
View File
@@ -129,7 +129,7 @@ def rotate(image, angle, resize=False, order=1, mode='constant', cval=0.):
Input image.
angle : float
Rotation angle in degrees in counter-clockwise direction.
resize: bool, optional
resize : bool, optional
Determine whether the shape of the output image will be automatically
calculated, so the complete rotated image exactly fits. Default is
False.
@@ -253,101 +253,3 @@ def swirl(image, center=None, strength=1, radius=100, rotation=0,
return warp(image, _swirl_mapping, map_args=warp_args,
output_shape=output_shape,
order=order, mode=mode, cval=cval)
def homography(image, H, output_shape=None, order=1,
mode='constant', cval=0.):
"""
.. note:: Deprecated in skimage 0.7
`homography` will be removed in skimage 0.8, it is replaced by
`warp` because the latter provides the same functionality::
warp(image, ProjectiveTransform(H))
Perform a projective transformation (homography) on an image.
For each pixel, given its homogeneous coordinate :math:`\mathbf{x}
= [x, y, 1]^T`, its target position is calculated by multiplying
with the given matrix, :math:`H`, to give :math:`H \mathbf{x}`.
E.g., to rotate by theta degrees clockwise, the matrix should be
::
[[cos(theta) -sin(theta) 0]
[sin(theta) cos(theta) 0]
[0 0 1]]
or, to translate x by 10 and y by 20,
::
[[1 0 10]
[0 1 20]
[0 0 1 ]].
Parameters
----------
image : 2-D array
Input image.
H : array of shape ``(3, 3)``
Transformation matrix H that defines the homography.
output_shape : tuple (rows, cols)
Shape of the output image generated.
order : int
Order of splines used in interpolation.
mode : string
How to handle values outside the image borders. Passed as-is
to ndimage.
cval : string
Used in conjunction with mode 'constant', the value outside
the image boundaries.
Examples
--------
>>> # rotate by 90 degrees around origin and shift down by 2
>>> x = np.arange(9, dtype=np.uint8).reshape((3, 3)) + 1
>>> x
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]], dtype=uint8)
>>> theta = -np.pi/2
>>> M = np.array([[np.cos(theta),-np.sin(theta),0],
... [np.sin(theta), np.cos(theta),2],
... [0, 0, 1]])
>>> x90 = homography(x, M, order=1)
>>> x90
array([[3, 6, 9],
[2, 5, 8],
[1, 4, 7]], dtype=uint8)
>>> # translate right by 2 and down by 1
>>> y = np.zeros((5,5), dtype=np.uint8)
>>> y[1, 1] = 255
>>> y
array([[ 0, 0, 0, 0, 0],
[ 0, 255, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0]], dtype=uint8)
>>> M = np.array([[ 1., 0., 2.],
... [ 0., 1., 1.],
... [ 0., 0., 1.]])
>>> y21 = homography(y, M, order=1)
>>> y21
array([[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 255, 0],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0]], dtype=uint8)
"""
import warnings
warnings.warn('the homography function is deprecated; '
'use the `warp` and `ProjectiveTransform` class instead',
category=DeprecationWarning)
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)
+11 -11
View File
@@ -2,9 +2,9 @@
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
cimport numpy as np
import numpy as np
cimport numpy as cnp
from skimage._shared.interpolation cimport (nearest_neighbour_interpolation,
bilinear_interpolation,
biquadratic_interpolation,
@@ -35,7 +35,7 @@ cdef inline void _matrix_transform(double x, double y, double* H, double *x_,
y_[0] = yy / zz
def _warp_fast(np.ndarray image, np.ndarray H, output_shape=None, int order=1,
def _warp_fast(cnp.ndarray image, cnp.ndarray H, output_shape=None, int order=1,
mode='constant', double cval=0):
"""Projective transformation (homography).
@@ -83,9 +83,9 @@ def _warp_fast(np.ndarray image, np.ndarray H, output_shape=None, int order=1,
"""
cdef np.ndarray[dtype=np.double_t, ndim=2, mode="c"] img = \
cdef cnp.ndarray[dtype=cnp.double_t, ndim=2, mode="c"] img = \
np.ascontiguousarray(image, dtype=np.double)
cdef np.ndarray[dtype=np.double_t, ndim=2, mode="c"] M = \
cdef cnp.ndarray[dtype=cnp.double_t, ndim=2, mode="c"] M = \
np.ascontiguousarray(H)
if mode not in ('constant', 'wrap', 'reflect', 'nearest'):
@@ -93,7 +93,7 @@ def _warp_fast(np.ndarray image, np.ndarray H, output_shape=None, int order=1,
"`constant`, `nearest`, `wrap` or `reflect`.")
cdef char mode_c = ord(mode[0].upper())
cdef int out_r, out_c
cdef Py_ssize_t out_r, out_c
if output_shape is None:
out_r = img.shape[0]
out_c = img.shape[1]
@@ -101,15 +101,15 @@ def _warp_fast(np.ndarray image, np.ndarray H, output_shape=None, int order=1,
out_r = output_shape[0]
out_c = output_shape[1]
cdef np.ndarray[dtype=np.double_t, ndim=2] out = \
cdef cnp.ndarray[dtype=cnp.double_t, ndim=2] out = \
np.zeros((out_r, out_c), dtype=np.double)
cdef int tfr, tfc
cdef Py_ssize_t tfr, tfc
cdef double r, c
cdef int rows = img.shape[0]
cdef int cols = img.shape[1]
cdef Py_ssize_t rows = img.shape[0]
cdef Py_ssize_t cols = img.shape[1]
cdef double (*interp_func)(double*, int, int, double, double,
cdef double (*interp_func)(double*, Py_ssize_t, Py_ssize_t, double, double,
char, double)
if order == 0:
interp_func = nearest_neighbour_interpolation
+28 -1
View File
@@ -1,4 +1,4 @@
__all__ = ['hough', 'hough_peaks', 'probabilistic_hough']
__all__ = ['hough', 'hough_line', 'hough_circle', 'hough_peaks', 'probabilistic_hough']
from itertools import izip as zip
@@ -96,8 +96,15 @@ def probabilistic_hough(img, threshold=10, line_length=50, line_gap=10,
"""
return _probabilistic_hough(img, threshold, line_length, line_gap, theta)
from skimage._shared.utils import deprecated
@deprecated('hough_line')
def hough(img, theta=None):
return hough_line(img, theta)
from ._hough_transform import _hough_circle
def hough_line(img, theta=None):
"""Perform a straight line Hough transform.
Parameters
@@ -138,6 +145,26 @@ def hough(img, theta=None):
"""
return _hough(img, theta)
def hough_circle(img, radius, normalize=True):
"""Perform a circular Hough transform.
Parameters
----------
img : (M, N) ndarray
Input image with nonzero values representing edges.
radius : ndarray
Radii at which to compute the Hough transform.
normalize : boolean, optional
Normalize the accumulator with the number
of pixels used to draw the radius
Returns
-------
H : 3D ndarray (radius index, (M, N) ndarray)
Hough transform accumulator for each radius
"""
return _hough_circle(img, radius.astype(np.intp), normalize)
def hough_peaks(hspace, angles, dists, min_distance=10, min_angle=10,
threshold=None, num_peaks=np.inf):
@@ -4,6 +4,7 @@ from numpy.testing import *
import skimage.transform as tf
import skimage.transform.hough_transform as ht
from skimage.transform import probabilistic_hough
from skimage.draw import circle_perimeter
def append_desc(func, description):
@@ -14,8 +15,6 @@ def append_desc(func, description):
return func
from skimage.transform import *
def test_hough():
# Generate a test image
@@ -23,7 +22,7 @@ def test_hough():
for i in range(25, 75):
img[100 - i, i] = 1
out, angles, d = tf.hough(img)
out, angles, d = tf.hough_line(img)
y, x = np.where(out == out.max())
dist = d[y[0]]
@@ -37,7 +36,7 @@ def test_hough_angles():
img = np.zeros((10, 10))
img[0, 0] = 1
out, angles, d = tf.hough(img, np.linspace(0, 360, 10))
out, angles, d = tf.hough_line(img, np.linspace(0, 360, 10))
assert_equal(len(angles), 10)
@@ -76,7 +75,7 @@ def test_hough_peaks_dist():
img = np.zeros((100, 100), dtype=np.bool_)
img[:, 30] = True
img[:, 40] = True
hspace, angles, dists = tf.hough(img)
hspace, angles, dists = tf.hough_line(img)
assert len(tf.hough_peaks(hspace, angles, dists, min_distance=5)[0]) == 2
assert len(tf.hough_peaks(hspace, angles, dists, min_distance=15)[0]) == 1
@@ -86,17 +85,17 @@ def test_hough_peaks_angle():
img[:, 0] = True
img[0, :] = True
hspace, angles, dists = tf.hough(img)
hspace, angles, dists = tf.hough_line(img)
assert len(tf.hough_peaks(hspace, angles, dists, min_angle=45)[0]) == 2
assert len(tf.hough_peaks(hspace, angles, dists, min_angle=90)[0]) == 1
theta = np.linspace(0, np.pi, 100)
hspace, angles, dists = tf.hough(img, theta)
hspace, angles, dists = tf.hough_line(img, theta)
assert len(tf.hough_peaks(hspace, angles, dists, min_angle=45)[0]) == 2
assert len(tf.hough_peaks(hspace, angles, dists, min_angle=90)[0]) == 1
theta = np.linspace(np.pi / 3, 4. / 3 * np.pi, 100)
hspace, angles, dists = tf.hough(img, theta)
hspace, angles, dists = tf.hough_line(img, theta)
assert len(tf.hough_peaks(hspace, angles, dists, min_angle=45)[0]) == 2
assert len(tf.hough_peaks(hspace, angles, dists, min_angle=90)[0]) == 1
@@ -105,10 +104,25 @@ def test_hough_peaks_num():
img = np.zeros((100, 100), dtype=np.bool_)
img[:, 30] = True
img[:, 40] = True
hspace, angles, dists = tf.hough(img)
hspace, angles, dists = tf.hough_line(img)
assert len(tf.hough_peaks(hspace, angles, dists, min_distance=0,
min_angle=0, num_peaks=1)[0]) == 1
def test_houghcircle():
# Prepare picture
img = np.zeros((120, 100), dtype=int)
radius = 20
x_0, y_0 = (99, 50)
x, y = circle_perimeter(y_0, x_0, radius)
img[y, x] = 1
out = tf.hough_circle(img, np.array([radius]))
x, y = np.where(out[0] == out[0].max())
# Offset for x_0, y_0
assert_equal(x[0], x_0 + radius)
assert_equal(y[0], y_0 + radius)
if __name__ == "__main__":
run_module_suite()
+3 -7
View File
@@ -5,7 +5,7 @@ from scipy.ndimage import map_coordinates
from skimage.transform import (warp, warp_coords, rotate, resize, rescale,
AffineTransform,
ProjectiveTransform,
SimilarityTransform, homography)
SimilarityTransform)
from skimage import transform as tf, data, img_as_float
from skimage.color import rgb2gray
@@ -39,10 +39,6 @@ def test_homography():
assert_array_almost_equal(x90, np.rot90(x))
def test_homography_basic():
homography(np.random.random((25, 25)), np.eye(3))
def test_fast_homography():
img = rgb2gray(data.lena()).astype(np.uint8)
img = img[:, :100]
@@ -87,10 +83,10 @@ def test_rotate():
def test_rotate_resize():
x = np.zeros((10, 10), dtype=np.double)
x45 = rotate(x, 45, resize=False)
assert x45.shape == (10, 10)
x45 = rotate(x, 45, resize=True)
# new dimension should be d = sqrt(2 * (10/2)^2)
assert x45.shape == (14, 14)

Some files were not shown because too many files have changed in this diff Show More