## Copyright (C) 2006 Stefan van der Walt ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted provided that the following conditions are ## met: ## ## 1. Redistributions of source code must retain the above copyright ## notice, this list of conditions and the following disclaimer. ## 2. Redistributions in binary form must reproduce the above copyright ## notice, this list of conditions and the following disclaimer in ## the documentation and/or other materials provided with the ## distribution. ## ## THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ## IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ## WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ## DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ## INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ## (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ## SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ## STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING ## IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ## POSSIBILITY OF SUCH DAMAGE. __all__ = ['hough'] import numpy as np itype = np.uint16 # See ticket 225 def hough(img, angles=None): """Perform a straight line Hough transform. Parameters ---------- img : (M, N) bool ndarray Thresholded input image. angles : ndarray or list Angles at which to compute the transform. Returns ------- H : 2-D ndarray Hough transform coefficients. distances : ndarray Distance values. angles : ndarray Angle values. Examples -------- Generate a test image: >>> img = np.zeros((100, 150), dtype=bool) >>> img[30, :] = 1 >>> img[:, 65] = 1 >>> img[35:45, 35:50] = 1 >>> for i in range(90): >>> img[i, i] = 1 >>> img += np.random.random(img.shape) > 0.95 Apply the Hough transform: >>> out, angles, d = houghtf(img) Plot the results: >>> import matplotlib.pyplot as plt >>> plt.imshow(out, cmap=plt.cm.bone) >>> plt.xlabel('Angle (degree)') >>> plt.ylabel('Distance %d (pixel)' % d[0]) >>> plt.show() """ if img.ndim != 2: raise ValueError("Input must be a two-dimensional array") img = img.astype(bool) if not angles: angles = np.linspace(-90,90,180) theta = angles / 180. * np.pi d = np.ceil(np.hypot(*img.shape)) nr_bins = 2*d - 1 bins = np.linspace(-d, d, nr_bins) out = np.zeros((nr_bins, len(theta)), dtype=itype) rows, cols = img.shape x,y = np.mgrid[:rows, :cols] for i, (cT, sT) in enumerate(zip(np.cos(theta), np.sin(theta))): rho = np.round_(cT * x[img] + sT * y[img]) - bins[0] + 1 rho = rho.astype(itype) rho[(rho < 0) | (rho > nr_bins)] = 0 bc = np.bincount(rho.flat)[1:] out[:len(bc), i] = bc return out, angles, bins