Merge pull request #257 from ahojnnes/shared

ENH: Add shared package.
This commit is contained in:
Stefan van der Walt
2012-08-25 10:35:29 -07:00
25 changed files with 389 additions and 341 deletions
View File
+7
View File
@@ -0,0 +1,7 @@
cdef inline unsigned char point_in_polygon(int 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,
unsigned char *result)
+54
View File
@@ -0,0 +1,54 @@
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
cdef inline unsigned char point_in_polygon(int nr_verts, double *xp, double *yp,
double x, double y):
"""Test whether point lies inside a polygon.
Parameters
----------
nr_verts : int
Number of vertices of polygon.
xp, yp : double array
Coordinates of polygon with length nr_verts.
x, y : double
Coordinates of point.
"""
cdef int i
cdef unsigned char c = 0
cdef int j = nr_verts - 1
for i in range(nr_verts):
if (
(((yp[i] <= y) and (y < yp[j])) or
((yp[j] <= y) and (y < yp[i])))
and (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i])
):
c = not c
j = i
return c
cdef void points_in_polygon(int nr_verts, double *xp, double *yp,
int nr_points, double *x, double *y,
unsigned char *result):
"""Test whether points lie inside a polygon.
Parameters
----------
nr_verts : int
Number of vertices of polygon.
xp, yp : double array
Coordinates of polygon with length nr_verts.
nr_points : int
Number of points to test.
x, y : double array
Coordinates of points.
result : unsigned char array
Test results for each point.
"""
cdef int n
for n in range(nr_points):
result[n] = point_in_polygon(nr_verts, xp, yp, x[n], y[n])
+13
View File
@@ -0,0 +1,13 @@
cdef inline double nearest_neighbour(double* image, int rows, int cols,
double r, double c, char mode,
double cval=*)
cdef inline double bilinear_interpolation(double* image, int rows, int cols,
double r, double c, char mode,
double cval=*)
cdef inline double get_pixel(double* image, int rows, int cols, int r, int c,
char mode, double cval=*)
cdef inline int coord_map(int dim, int coord, char mode)
+128
View File
@@ -0,0 +1,128 @@
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
from libc.math cimport ceil, floor, round
cdef inline double nearest_neighbour(double* image, int rows, int cols,
double r, double c, char mode,
double cval=0):
"""Nearest neighbour interpolation at a given position in the image.
Parameters
----------
image : double array
Input image.
rows, cols: int
Shape of image.
r, c : int
Position at which to interpolate.
mode : {'C', 'W', 'M'}
Wrapping mode. Constant, Wrap or Mirror.
cval : double
Constant value to use for constant mode.
"""
return get_pixel(image, rows, cols, <int>round(r), <int>round(c),
mode, cval)
cdef inline double bilinear_interpolation(double* image, int rows, int cols,
double r, double c, char mode,
double cval=0):
"""Bilinear interpolation at a given position in the image.
Parameters
----------
image : double array
Input image.
rows, cols: int
Shape of image.
r, c : int
Position at which to interpolate.
mode : {'C', 'W', 'M'}
Wrapping mode. Constant, Wrap or Mirror.
cval : double
Constant value to use for constant mode.
"""
cdef double dr, dc
cdef int minr, minc, maxr, maxc
minr = <int>floor(r)
minc = <int>floor(c)
maxr = <int>ceil(r)
maxc = <int>ceil(c)
dr = r - minr
dc = c - minc
top = (1 - dc) * get_pixel(image, rows, cols, minr, minc, mode, cval) \
+ dc * get_pixel(image, rows, cols, minr, maxc, mode, cval)
bottom = (1 - dc) * get_pixel(image, rows, cols, maxr, minc, mode, cval) \
+ dc * get_pixel(image, rows, cols, maxr, maxc, mode, cval)
return (1 - dr) * top + dr * bottom
cdef inline double get_pixel(double* image, int rows, int cols, int r, int c,
char mode, double cval=0):
"""Get a pixel from the image, taking wrapping mode into consideration.
Parameters
----------
image : double array
Input image.
rows, cols: int
Shape of image.
r, c : int
Position at which to get the pixel.
mode : {'C', 'W', 'M'}
Wrapping mode. Constant, Wrap or Mirror.
cval : double
Constant value to use for constant mode.
"""
if mode == 'C':
if (r < 0) or (r > rows - 1) or (c < 0) or (c > cols - 1):
return cval
else:
return image[r * cols + c]
else:
return image[coord_map(rows, r, mode) * cols + coord_map(cols, c, mode)]
cdef inline int coord_map(int dim, int coord, char mode):
"""
Wrap a coordinate, according to a given mode.
Parameters
----------
dim : int
Maximum coordinate.
coord : int
Coord provided by user. May be < 0 or > dim.
mode : {'W', 'M'}
Whether to wrap or mirror the coordinate if it
falls outside [0, dim).
"""
dim = dim - 1
if mode == 'M': # mirror
if (coord < 0):
# How many times times does the coordinate wrap?
if (<int>(-coord / dim) % 2 != 0):
return dim - <int>(-coord % dim)
else:
return <int>(-coord % dim)
elif (coord > dim):
if (<int>(coord / dim) % 2 != 0):
return <int>(dim - (coord % dim))
else:
return <int>(coord % dim)
elif mode == 'W': # wrap
if (coord < 0):
return <int>(dim - (-coord % dim))
elif (coord > dim):
return <int>(coord % dim)
return coord
+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/env python
import os
from skimage._build import cython
base_path = os.path.abspath(os.path.dirname(__file__))
def configuration(parent_package='', top_path=None):
from numpy.distutils.misc_util import Configuration, get_numpy_include_dirs
config = Configuration('_shared', parent_package, top_path)
config.add_data_dir('tests')
cython(['geometry.pyx'], working_path=base_path)
cython(['interpolation.pyx'], working_path=base_path)
cython(['transform.pyx'], working_path=base_path)
config.add_extension('geometry', sources=['geometry.c'])
config.add_extension('interpolation', sources=['interpolation.c'],
include_dirs=[get_numpy_include_dirs()])
config.add_extension('transform', sources=['transform.c'],
include_dirs=[get_numpy_include_dirs()])
return config
if __name__ == '__main__':
from numpy.distutils.core import setup
setup(maintainer='Scikits-image Developers',
author='Scikits-image Developers',
maintainer_email='scikits-image@googlegroups.com',
description='Transforms',
url='https://github.com/scikits-image/scikits-image',
license='SciPy License (BSD Style)',
**(configuration(top_path='').todict())
)
+5
View File
@@ -0,0 +1,5 @@
cimport numpy as cnp
cdef float integrate(cnp.ndarray[float, ndim=2, mode="c"] sat,
int r0, int c0, int r1, int c1)
+44
View File
@@ -0,0 +1,44 @@
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
cimport numpy as cnp
cdef float integrate(cnp.ndarray[float, ndim=2, mode="c"] sat,
int r0, int c0, int r1, int c1):
"""
Using a summed area table / integral image, calculate the sum
over a given window.
This function is the same as the `integrate` function in
`skimage.transform.integrate`, but this Cython version significantly
speeds up the code.
Parameters
----------
sat : ndarray of float
Summed area table / integral image.
r0, c0 : int
Top-left corner of block to be summed.
r1, c1 : int
Bottom-right corner of block to be summed.
Returns
-------
S : int
Sum over the given window.
"""
cdef float S = 0
S += sat[r1, c1]
if (r0 - 1 >= 0) and (c0 - 1 >= 0):
S += sat[r0 - 1, c0 - 1]
if (r0 - 1 >= 0):
S -= sat[r0 - 1, c1]
if (c0 - 1 >= 0):
S -= sat[r1, c0 - 1]
return S
+2 -6
View File
@@ -3,11 +3,7 @@ import math
from libc.math cimport sqrt
cimport numpy as np
cimport cython
cdef extern from "../morphology/_pnpoly.h":
int pnpoly(int nr_verts, double *xp, double *yp,
double x, double y)
from skimage._shared.geometry cimport point_in_polygon
@cython.boundscheck(False)
@@ -119,7 +115,7 @@ def polygon(y, x, shape=None):
for r in range(minr, maxr+1):
for c in range(minc, maxc+1):
if pnpoly(nr_verts, cptr, rptr, c, r):
if point_in_polygon(nr_verts, cptr, rptr, c, r):
rr.append(r)
cc.append(c)
+1 -1
View File
@@ -15,7 +15,7 @@ def configuration(parent_package='', top_path=None):
cython(['_draw.pyx'], working_path=base_path)
config.add_extension('_draw', sources=['_draw.c'],
include_dirs=[get_numpy_include_dirs()])
include_dirs=[get_numpy_include_dirs(), '../shared'])
return config
+2 -45
View File
@@ -35,51 +35,8 @@ cimport numpy as np
import numpy as np
from scipy.signal import fftconvolve
from skimage.transform import integral
cdef extern from "math.h":
float sqrt(float x)
float fabs(float x)
@cython.boundscheck(False)
cdef float integrate(np.ndarray[float, ndim=2, mode="c"] sat,
int r0, int c0, int r1, int c1):
"""
Using a summed area table / integral image, calculate the sum
over a given window.
This function is the same as the `integrate` function in
`skimage.transform.integrate`, but this Cython version significantly
speeds up the code.
Parameters
----------
sat : ndarray of float
Summed area table / integral image.
r0, c0 : int
Top-left corner of block to be summed.
r1, c1 : int
Bottom-right corner of block to be summed.
Returns
-------
S : int
Sum over the given window.
"""
cdef float S = 0
S += sat[r1, c1]
if (r0 - 1 >= 0) and (c0 - 1 >= 0):
S += sat[r0 - 1, c0 - 1]
if (r0 - 1 >= 0):
S -= sat[r0 - 1, c1]
if (c0 - 1 >= 0):
S -= sat[r1, c0 - 1]
return S
from libc.math cimport sqrt, fabs
from skimage._shared.transform cimport integrate
@cython.boundscheck(False)
+2 -2
View File
@@ -1,11 +1,11 @@
#cython: cdivison=True
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np
cimport numpy as np
from libc.math cimport sin, cos, abs
from skimage.transform._project cimport bilinear_interpolation
from skimage._shared.interpolation cimport bilinear_interpolation
def _glcm_loop(np.ndarray[dtype=np.uint8_t, ndim=2,
+2 -3
View File
@@ -16,10 +16,9 @@ def configuration(parent_package='', top_path=None):
cython(['_template.pyx'], working_path=base_path)
config.add_extension('_texture', sources=['_texture.c'],
include_dirs=[get_numpy_include_dirs(),
'../transform'])
include_dirs=[get_numpy_include_dirs(), '../_shared'])
config.add_extension('_template', sources=['_template.c'],
include_dirs=[get_numpy_include_dirs()])
include_dirs=[get_numpy_include_dirs(), '../_shared'])
return config
+1 -2
View File
@@ -2,9 +2,8 @@
import _mcp
cimport _mcp
from libc.math cimport fabs
cdef extern from "math.h":
double fabs(double f)
cdef class MCP_Diff(_mcp.MCP):
"""MCP_Diff(costs, offsets=None, fully_connected=True)
+4 -15
View File
@@ -8,15 +8,10 @@ integers, so currently the only way to clip results efficiently
one.
"""
import cython
import numpy as np
cimport numpy as np
import cython
cdef extern from "math.h":
float exp(float) nogil
float pow(float, float) nogil
from libc.math cimport exp, pow
@cython.boundscheck(False)
@@ -189,7 +184,6 @@ 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,
@@ -219,7 +213,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
@@ -283,6 +276,7 @@ cdef void rgb_2_hsv(float* RGB, float* HSV) nogil:
HSV[1] = S
HSV[2] = V
@cython.cdivision(True)
cdef void hsv_2_rgb(float* HSV, float* RGB) nogil:
cdef float H, S, V
@@ -388,6 +382,7 @@ def py_hsv_2_rgb(H, S, V):
return (R, G, B)
def py_rgb_2_hsv(R, G, B):
'''Convert an HSV value to RGB.
@@ -561,9 +556,3 @@ def hsv_multiply(np.ndarray[np.uint8_t, ndim=3] img,
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]
-72
View File
@@ -1,72 +0,0 @@
/* `pnpoly` is from
http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
Copyright (c) 1970-2003, Wm. Randolph Franklin
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimers.
2. Redistributions in binary form must reproduce the above
copyright notice in the documentation and/or other materials
provided with the distribution.
3. The name of W. Randolph Franklin may not be used to endorse or
promote products derived from this Software without specific
prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. */
#ifdef __cplusplus
extern "C" {
#endif
unsigned char pnpoly(int nr_verts, double *xp, double *yp, double x, double y)
{
int i, j;
unsigned char c = 0;
for (i = 0, j = nr_verts-1; i < nr_verts; j = i++) {
if ((((yp[i]<=y) && (y<yp[j])) ||
((yp[j]<=y) && (y<yp[i]))) &&
(x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
c = !c;
}
return c;
}
void npnpoly(int nr_verts, double *xp, double *yp,
int nr_points, double *x, double *y,
unsigned char *result)
/*
* For N provided points, calculate whether they are in
* the polygon defined by vertices *xp, *yp.
*
* nr_verts : number of vertices
* *xp, *yp : x and y coordinates of vertices
* nr_points : number of data points provided
* *x, *y : data points
*/
{
unsigned char n = 0;
for (n = 0; n < nr_points; n++) {
result[n] = pnpoly(nr_verts, xp, yp, x[n], y[n]);
}
}
#ifdef __cplusplus
}
#endif
+30 -37
View File
@@ -2,14 +2,7 @@
cimport numpy as np
import numpy as np
cdef extern from "_pnpoly.h":
int pnpoly(int nr_verts, double *xp, double *yp,
double x, double y)
void npnpoly(int nr_verts, double *xp, double *yp,
int nr_points, double *x, double *y,
unsigned char *result)
from skimage._shared.geometry cimport point_in_polygon, points_in_polygon
def grid_points_inside_poly(shape, verts):
@@ -49,45 +42,45 @@ def grid_points_inside_poly(shape, verts):
for m in range(M):
for n in range(N):
out[m, n] = pnpoly(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)
def points_inside_poly(points, verts):
"""Test whether points lie inside a polygon.
"""Test whether points lie inside a polygon.
Parameters
----------
points : (N, 2) array
Input points, ``(x, y)``.
verts : (M, 2) array
Vertices of the polygon, sorted either clockwise or anti-clockwise.
The first point may (but does not need to be) duplicated.
Parameters
----------
points : (N, 2) array
Input points, ``(x, y)``.
verts : (M, 2) array
Vertices of the polygon, sorted either clockwise or anti-clockwise.
The first point may (but does not need to be) duplicated.
Returns
-------
mask : (N,) array of bool
True if corresponding point is inside the polygon.
Returns
-------
mask : (N,) array of bool
True if corresponding point is inside the polygon.
"""
cdef np.ndarray[np.double_t, ndim=1, mode="c"] x, y, vx, vy
"""
cdef np.ndarray[np.double_t, ndim=1, mode="c"] x, y, vx, vy
points = np.asarray(points)
verts = np.asarray(verts)
points = np.asarray(points)
verts = np.asarray(verts)
x = points[:, 0].astype(np.double)
y = points[:, 1].astype(np.double)
x = points[:, 0].astype(np.double)
y = points[:, 1].astype(np.double)
vx = verts[:, 0].astype(np.double)
vy = verts[:, 1].astype(np.double)
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)
npnpoly(vx.shape[0], <double*>vx.data, <double*>vy.data,
x.shape[0], <double*>x.data, <double*>y.data,
<unsigned char*>out.data)
cdef np.ndarray[np.uint8_t, ndim=1] out = \
np.zeros(x.shape[0], dtype=np.uint8)
return out.astype(bool)
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)
return out.astype(bool)
+1 -1
View File
@@ -29,7 +29,7 @@ def configuration(parent_package='', top_path=None):
config.add_extension('_skeletonize_cy', sources=['_skeletonize_cy.c'],
include_dirs=[get_numpy_include_dirs()])
config.add_extension('_pnpoly', sources=['_pnpoly.c'],
include_dirs=[get_numpy_include_dirs()])
include_dirs=[get_numpy_include_dirs(), '../shared'])
config.add_extension('_convex_hull', sources=['_convex_hull.c'],
include_dirs=[get_numpy_include_dirs()])
config.add_extension('_greyreconstruct', sources=['_greyreconstruct.c'],
+1 -5
View File
@@ -1,6 +1,7 @@
import numpy as np
cimport numpy as np
cimport cython
from libc.math cimport exp, sqrt
from itertools import product
from scipy import ndimage
@@ -9,11 +10,6 @@ from ..util import img_as_float
from ..color import rgb2lab
cdef extern from "math.h":
double exp(double)
double sqrt(double)
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)
+1
View File
@@ -6,6 +6,7 @@ def configuration(parent_package='', top_path=None):
config = Configuration('skimage', parent_package, top_path)
config.add_subpackage('_shared')
config.add_subpackage('color')
config.add_subpackage('data')
config.add_subpackage('draw')
+19 -26
View File
@@ -2,27 +2,20 @@ cimport cython
import numpy as np
cimport numpy as np
from random import randint
from libc.math cimport abs, fabs, sqrt, ceil, floor, round
from libc.stdlib cimport rand
np.import_array()
cdef extern from "stdlib.h":
int rand()
cdef extern from "math.h":
int abs(int)
double fabs(double)
double sqrt(double)
double ceil(double)
double floor(double)
cdef double round(double val):
return floor(val + 0.5);
cdef double PI_2 = 1.5707963267948966
cdef double NEG_PI_2 = -PI_2
@cython.boundscheck(False)
def _hough(np.ndarray img, np.ndarray[ndim=1, dtype=np.double_t] theta=None):
if img.ndim != 2:
raise ValueError('The input image must be 2D.')
@@ -31,7 +24,7 @@ def _hough(np.ndarray img, np.ndarray[ndim=1, dtype=np.double_t] theta=None):
cdef np.ndarray[ndim=1, dtype=np.double_t] stheta
if theta is None:
theta = np.linspace(PI_2, NEG_PI_2, 180)
theta = np.linspace(PI_2, NEG_PI_2, 180)
ctheta = np.cos(theta)
stheta = np.sin(theta)
@@ -39,14 +32,14 @@ def _hough(np.ndarray img, np.ndarray[ndim=1, dtype=np.double_t] theta=None):
# 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 int max_distance, offset
max_distance = 2 * <int>ceil((sqrt(img.shape[0] * img.shape[0] +
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.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)
@@ -58,7 +51,7 @@ def _hough(np.ndarray img, np.ndarray[ndim=1, dtype=np.double_t] theta=None):
nthetas = theta.shape[0]
for i in range(nidxs):
x = x_idxs[i]
y = y_idxs[i]
y = y_idxs[i]
for j in range(nthetas):
accum_idx = <int>round((ctheta[j] * x + stheta[j] * y)) + offset
accum[accum_idx, j] += 1
@@ -94,7 +87,7 @@ def _probabilistic_hough(np.ndarray img, int value_threshold, int line_length, \
# 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
max_distance = 2 * <int>ceil((sqrt(img.shape[0] * img.shape[0] +
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
@@ -114,11 +107,11 @@ def _probabilistic_hough(np.ndarray img, int value_threshold, int line_length, \
# select random non-zero point
count = len(points)
if count == 0:
break
break
index = rand() % (count)
x = points[index][0]
y = points[index][1]
del points[index]
del points[index]
# if previously eliminated, skip
if not mask[y, x]:
continue
@@ -147,7 +140,7 @@ def _probabilistic_hough(np.ndarray img, int value_threshold, int line_length, \
dx0 = 1
else:
dx0 = -1
dy0 = <int>round(b * (1 << shift) / fabs(a))
dy0 = <int>round(b * (1 << shift) / fabs(a))
y0 = (y0 << shift) + (1 << (shift - 1))
else:
if b > 0:
@@ -156,7 +149,7 @@ def _probabilistic_hough(np.ndarray img, int value_threshold, int line_length, \
dy0 = -1
dx0 = <int>round(a * (1 << shift) / fabs(b))
x0 = (x0 << shift) + (1 << (shift - 1))
# pass 1: walk the line, merging lines less than specified gap length
for k in range(2):
gap = 0
@@ -208,9 +201,9 @@ def _probabilistic_hough(np.ndarray img, int value_threshold, int line_length, \
x1 = px >> shift
y1 = py
# 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
if mask[y1, x1]:
if good_line:
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
-7
View File
@@ -1,7 +0,0 @@
cimport numpy as np
import numpy as np
cdef inline double bilinear_interpolation(double* image, int rows, int cols,
double r, double c, char mode,
double cval=*)
+18 -106
View File
@@ -1,111 +1,12 @@
#cython: cdivison=True
#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
cimport numpy as np
import numpy as np
from cython.operator import dereference
from libc.math cimport ceil, floor
cdef inline double bilinear_interpolation(double* image, int rows, int cols,
double r, double c, char mode,
double cval=0):
"""Bilinear interpolation at a given position in the image.
Parameters
----------
image : double array
Input image.
rows, cols: int
Shape of image.
r, c : int
Position at which to interpolate.
mode : {'C', 'W', 'M'}
Wrapping mode. Constant, Wrap or Mirror.
cval : double
Constant value to use for constant mode.
"""
cdef double dr, dc
cdef int minr, minc, maxr, maxc
minr = <int>floor(r)
minc = <int>floor(c)
maxr = <int>ceil(r)
maxc = <int>ceil(c)
dr = r - minr
dc = c - minc
top = (1 - dc) * get_pixel(image, rows, cols, minr, minc, mode, cval) \
+ dc * get_pixel(image, rows, cols, minr, maxc, mode, cval)
bottom = (1 - dc) * get_pixel(image, rows, cols, maxr, minc, mode, cval) \
+ dc * get_pixel(image, rows, cols, maxr, maxc, mode, cval)
return (1 - dr) * top + dr * bottom
cdef inline double get_pixel(double* image, int rows, int cols, int r, int c,
char mode, double cval=0):
"""Get a pixel from the image, taking wrapping mode into consideration.
Parameters
----------
image : double array
Input image.
rows, cols: int
Shape of image.
r, c : int
Position at which to get the pixel.
mode : {'C', 'W', 'M'}
Wrapping mode. Constant, Wrap or Mirror.
cval : double
Constant value to use for constant mode.
"""
if mode == 'C':
if (r < 0) or (r > rows - 1) or (c < 0) or (c > cols - 1):
return cval
else:
return image[r * cols + c]
else:
return image[coord_map(rows, r, mode) * cols + coord_map(cols, c, mode)]
cdef inline int coord_map(int dim, int coord, char mode):
"""
Wrap a coordinate, according to a given mode.
Parameters
----------
dim : int
Maximum coordinate.
coord : int
Coord provided by user. May be < 0 or > dim.
mode : {'W', 'M'}
Whether to wrap or mirror the coordinate if it
falls outside [0, dim).
"""
dim = dim - 1
if mode == 'M': # mirror
if (coord < 0):
# How many times times does the coordinate wrap?
if (<int>(-coord / dim) % 2 != 0):
return dim - <int>(-coord % dim)
else:
return <int>(-coord % dim)
elif (coord > dim):
if (<int>(coord / dim) % 2 != 0):
return <int>(dim - (coord % dim))
else:
return <int>(coord % dim)
elif mode == 'W': # wrap
if (coord < 0):
return <int>(dim - (-coord % dim))
elif (coord > dim):
return <int>(coord % dim)
return coord
from skimage._shared.interpolation cimport (nearest_neighbour,
bilinear_interpolation)
cdef inline _matrix_transform(double x, double y, double* H, double *x_,
@@ -132,7 +33,7 @@ cdef inline _matrix_transform(double x, double y, double* H, double *x_,
y_[0] = yy / zz
def homography(np.ndarray image, np.ndarray H, output_shape=None,
def homography(np.ndarray image, np.ndarray H, output_shape=None, int order=1,
mode='constant', double cval=0):
"""
Projective transformation (homography).
@@ -167,6 +68,10 @@ def homography(np.ndarray image, np.ndarray H, output_shape=None,
Transformation matrix H that defines the homography.
output_shape : tuple (rows, cols)
Shape of the output image generated.
order : {0, 1}
Order of interpolation::
* 0: Nearest-neighbour interpolation.
* 1: Bilinear interpolation (default).
mode : {'constant', 'mirror', 'wrap'}
How to handle values outside the image borders.
cval : string
@@ -175,13 +80,15 @@ def homography(np.ndarray image, np.ndarray H, output_shape=None,
"""
cdef np.ndarray[dtype=np.double_t, ndim=2] img = image.astype(np.double)
cdef np.ndarray[dtype=np.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 = \
np.ascontiguousarray(np.linalg.inv(H))
if mode not in ('constant', 'wrap', 'mirror'):
raise ValueError("Invalid mode specified. Please use "
"`constant`, `wrap` or `mirror`.")
cdef char mode_c
if mode == 'constant':
mode_c = ord('C')
elif mode == 'wrap':
@@ -189,6 +96,7 @@ def homography(np.ndarray image, np.ndarray H, output_shape=None,
elif mode == 'mirror':
mode_c = ord('M')
cdef int out_r, out_c
if output_shape is None:
out_r = img.shape[0]
out_c = img.shape[1]
@@ -207,7 +115,11 @@ def homography(np.ndarray image, np.ndarray H, output_shape=None,
for tfr in range(out_r):
for tfc in range(out_c):
_matrix_transform(tfc, tfr, <double*>M.data, &c, &r)
out[tfr, tfc] = bilinear_interpolation(<double*>img.data, rows,
cols, r, c, mode_c)
if order == 0:
out[tfr, tfc] = nearest_neighbour(<double*>img.data, rows,
cols, r, c, mode_c)
elif order == 1:
out[tfr, tfc] = bilinear_interpolation(<double*>img.data, rows,
cols, r, c, mode_c)
return out
+1 -1
View File
@@ -20,7 +20,7 @@ def configuration(parent_package='', top_path=None):
include_dirs=[get_numpy_include_dirs()])
config.add_extension('_project', sources=['_project.c'],
include_dirs=[get_numpy_include_dirs()])
include_dirs=[get_numpy_include_dirs(), '../_shared'])
return config
+15 -12
View File
@@ -54,20 +54,23 @@ def test_fast_homography():
H[:2, :2] = [[C, -S], [S, C]]
H[:2, 2] = [tx, ty]
for mode in ('constant', 'mirror', 'wrap'):
p0 = warp(img, ProjectiveTransform(H).inverse, mode=mode, order=1)
p1 = fast_homography(img, H, mode=mode)
tform = ProjectiveTransform(H)
# import matplotlib.pyplot as plt
# f, (ax0, ax1, ax2, ax3) = plt.subplots(1, 4)
# ax0.imshow(img)
# ax1.imshow(p0, cmap=plt.cm.gray)
# ax2.imshow(p1, cmap=plt.cm.gray)
# ax3.imshow(np.abs(p0 - p1), cmap=plt.cm.gray)
# plt.show()
for order in range(2):
for mode in ('constant', 'mirror', 'wrap'):
p0 = warp(img, tform.inverse, mode=mode, order=order)
p1 = fast_homography(img, H, mode=mode, order=order)
d = np.mean(np.abs(p0 - p1))
assert d < 0.001
# import matplotlib.pyplot as plt
# f, (ax0, ax1, ax2, ax3) = plt.subplots(1, 4)
# ax0.imshow(img)
# ax1.imshow(p0, cmap=plt.cm.gray)
# ax2.imshow(p1, cmap=plt.cm.gray)
# ax3.imshow(np.abs(p0 - p1), cmap=plt.cm.gray)
# plt.show()
d = np.mean(np.abs(p0 - p1))
assert d < 0.001
def test_swirl():