mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-29 11:26:57 +08:00
Merge branch 'master' of git://github.com/scikit-image/scikit-image
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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()
|
||||
@@ -11,7 +11,6 @@ position of corners.
|
||||
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
from skimage import data
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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()
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,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
@@ -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',
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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))
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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]
|
||||
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
-----
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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
@@ -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,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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[simpleitk]
|
||||
description = Image reading and writing via SimpleITK
|
||||
provides = imread, imsave
|
||||
@@ -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)
|
||||
@@ -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."""
|
||||
|
||||
@@ -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()
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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]
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
--------
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user