[SciPy-User] Bresenham algorithm?

David Warde-Farley dwf at cs.toronto.edu
Sun Sep 20 21:30:27 EDT 2009


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



More information about the SciPy-User mailing list