"painting" one array on another using python / numpy

I am writing a library for handling eye tracking in Python, and I'm pretty new to numpy / scipy all over the world. In fact, I want to take an array of values ​​(x, y) in time and "draw" some figure on the canvas in these coordinates. For example, the shape may be a blurry circle.

The operation that I mean is more or less identical to using the brush tool in Photoshop.

I have a reciprocal algorithm that cuts off my β€œbrush” to fit within my image and adds every point to the battery image, but it is slow (!), And it seems like a fundamentally simpler way to do this.

Any directions on where to start looking?

+7
python numpy scipy image-processing
source share
5 answers

In your question, you describe a Gaussian filter for which scipy has support through package . For example:

from scipy import * # rand from pylab import * # figure, imshow from scipy.ndimage import gaussian_filter # random "image" I = rand(100, 100) figure(1) imshow(I) # gaussian filter J = gaussian_filter(I, sigma=10) figure(2) imshow(J) 

Of course, you can apply this on the whole image or just on the patch using slicing:

 J = array(I) # copy image J[30:70, 30:70] = gaussian_filter(I[30:70, 30:70], sigma=1) # apply filter to subregion figure(2) imshow(2) 

For basic image processing, the Python Image Library ( PIL ) is probably what you want.

Note: for β€œpainting” with the β€œbrush”, I think you could just create an array of boolean masks with your brush. For example:

 # 7x7 boolean mask with the "brush" (example: a _crude_ circle) mask = array([[0, 0, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 1, 0], [1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1], [0, 1, 1, 1, 1, 1, 0], [0, 0, 1, 1, 1, 0, 0]], dtype=bool) # random image I = rand(100, 100) # apply filter only on mask # compute the gauss. filter only on the 7x7 subregion, not the whole image I[40:47, 40:47][mask] = gaussian_filter(I[40:47, 40:47][mask], sigma=1) 
+7
source share

You really should look at Andrew Straw motmot and libcamiface . He uses it for flight experiments, but it is a flexible library in order to do exactly what I get and process. There is a video of his presentation at SciPy2009.

As for the brush script that you mentioned, I would make a copy of the image with the .copy () method, save the brush image in an array and just add it with

 arr[first_br_row:last_br_row, first_br_col:last_br_col] += brush[first_row:last_row, first_col:last_col] 

where you set first_br_row , last_br_row first_br_col , last_br_col for addressing, where you want to add a brush and first_row , last_row , first_col , last_col to copy the brush (usually set them to 0 and # rows / cols - 1, but set when you're close enough to the border of the image to draw part of the brush).

Hope all of this helps.

+2
source share

Doing a bit of math in Fourier space can help: translation (convolution by Dirac) is equal to a simple multiplication by a phase in Fourier ... it makes your brush move to the exact place (similar solution, catchmeifyoutry and dwf, but it allows you to make the translation more subtle, than a pixel, for example 2.5, alas, with some ringing). Then the sum of such strokes is the sum of these operations.

In code:

 import numpy import pylab from scipy import mgrid def FTfilter(image, FTfilter): from scipy.fftpack import fftn, fftshift, ifftn, ifftshift from scipy import real FTimage = fftshift(fftn(image)) * FTfilter return real(ifftn(ifftshift(FTimage))) def translate(image, vec): """ Translate image by vec (in pixels) """ u = ((vec[0]+image.shape[0]/2) % image.shape[0]) - image.shape[0]/2 v = ((vec[1]+image.shape[1]/2) % image.shape[1]) - image.shape[1]/2 f_x, f_y = mgrid[-1:1:1j*image.shape[0], -1:1:1j*image.shape[1]] trans = numpy.exp(-1j*numpy.pi*(u*f_x + v*f_y)) return FTfilter(image, trans) def occlude(image, mask): # combine in oclusive mode return numpy.max(numpy.dstack((image, mask)), axis=2) if __name__ == '__main__': Image = numpy.random.rand(100, 100) X, Y = mgrid[-1:1:1j*Image.shape[0], -1:1:1j*Image.shape[1]] brush = X**2 + Y**2 < .05 # relative size of the brush # shows the brush pylab.imshow(brush) # move it to some other position / use a threshold to avoid ringing brushed = translate(brush, [20, -10.51]) > .6 pylab.imshow(brushed) pylab.imshow(occlude(Image, brushed)) more_strokes = [[40, -15.1], [-40, -15.1], [-25, 15.1], [20, 10], [0, -10], [25, -10.51]] for stroke in more_strokes: brushed = brushed + translate(brush, stroke) > .6 pylab.imshow(occlude(Image, brushed)) 
+2
source share

OpenCV uses numpy arrays and has basic drawing functions: circles, ellipses, polylines ...

To draw a line, you can call

 cv.line(array,previous_point,new_point,colour,thickness=x) 

every time you get a mouse event.

+1
source share

Have you viewed Tkinter ?

A Python image library can also help.

0
source share

All Articles