[SciPy-User] Bresenham algorithm?

Sebastian Haase seb.haase at gmail.com
Mon Sep 21 02:42:44 EDT 2009


On Sun, Sep 20, 2009 at 5:30 PM, David Warde-Farley <dwf at cs.toronto.edu> wrote:
> On 20-Sep-09, at 12:27 PM, Xavier Gnata wrote:
>
>> Does scipy provide the Bresenham algorithm ?
>> For sure it is simple to implement this algo in python but it is
>> slow :(
>
> It doesn't, that I know of, but it would be easy enough to use Cython
> to speed it up. This is precisely the sort of thing Cython is good
> for: iterative algorithms that cannot easily be vectorized. It'll be
> particularly fast since Bresenham's algorithm is all in integer
> arithmetic (note that you're still dealing with ints in Python).
>
> Here's an implementation I found here: http://mail.python.org/pipermail/python-list/1999-July/007163.html
>
> def bresenham(x,y,x2,y2):
>     """Brensenham line algorithm"""
>     steep = 0
>     coords = []
>     dx = abs(x2 - x)
>     if (x2 - x) > 0: sx = 1
>     else: sx = -1
>     dy = abs(y2 - y)
>     if (y2 - y) > 0: sy = 1
>     else: sy = -1
>     if dy > dx:
>         steep = 1
>         x,y = y,x
>         dx,dy = dy,dx
>         sx,sy = sy,sx
>     d = (2 * dy) - dx
>     for i in range(0,dx):
>         if steep: coords.append((y,x))
>         else: coords.append((x,y))
>         while d >= 0:
>             y = y + sy
>             d = d - (2 * dx)
>         x = x + sx
>         d = d + (2 * dy)
>     return coords #added by me
>
> Now here's the version I've marked up with Cython:
>
> cdef extern from "math.h":
>     int abs(int i)
>
> def bresenham(int x, int y, int x2, int y2):
>     cdef int steep = 0
>     cdef int dx = abs(x2 - x)
>     cdef int dy = abs(y2 - y)
>     cdef int sx, sy, d, i
>     coords = []
>     if (x2 - x) > 0: sx = 1
>     else: sx = -1
>     if (y2 - y) > 0: sy = 1
>     else: sy = -1
>     if dy > dx:
>         steep = 1
>         x,y = y,x
>         dx,dy = dy,dx
>         sx,sy = sy,sx
>     d = (2 * dy) - dx
>     for i in range(0,dx):
>         if steep:
>             coords.append((y,x))
>         else:
>             coords.append((x,y))
>         while d >= 0:
>             y = y + sy
>             d = d - (2 * dx)
>         x = x + sx
>         d = d + (2 * dy)
>     return coords
>
>
> And here is the speed comparison:
>
> In [1]: from bresenham import bresenham as bresenham_py
>
> In [2]: from bresenham_cython import bresenham as bresenham_cy
>
> In [3]: a = bresenham_py(0, 0, 12900, 10500)
>
> In [4]: b = bresenham_cy(0, 0, 12900, 10500)
>
> In [5]: a == b # Check that they produce the same results
> Out[5]: True
>
> In [6]: timeit bresenham_py(0, 0, 12900, 10500)
> 100 loops, best of 3: 12.6 ms per loop
>
> In [7]: timeit bresenham_cy(0, 0, 12900, 10500) # python was already
> pretty fast
> 100 loops, best of 3: 2.27 ms per loop
>
> So, with that minimal effort and the compilation step we've already
> got a 5x speedup. Note that my Cython'ed version still uses a Python
> list. It could be easily modified so that you could pass in your array
> and do the summing inside this function, bypassing the need for any
> Python API calls at all, and gaining further speed ups.
>
> If I comment out the lines involving 'coords' (the list/tuples
> manipulation)
>
> In [7]: timeit bresenham_cy(0, 0, 12900, 10050)
> 10000 loops, best of 3: 28.7 us per loop
>
> which is almost an additional hundred-fold speedup.
>
> For information on how to pass in ndarray arguments into a Cython
> function, see:
>
>        http://wiki.cython.org/tutorials/numpy
>
> David

If you comment out the list/tuples handling - assuming you want to
plug in numpy arrays here, you have to know the number of points up
front.
(To be able to pre-allocate the array correctly)
Is this easy ?  (rounding errors ?)

Cheers,

- Sebastian Haase



More information about the SciPy-User mailing list