2009-12-22 23 views
7

Escribo una biblioteca para procesar el seguimiento de miradas en Python, y soy bastante nuevo en el mundo numpy/scipy. Esencialmente, estoy buscando tomar una matriz de valores (x, y) en el tiempo y "pintar" alguna forma en un lienzo en esas coordenadas. Por ejemplo, la forma puede ser un círculo borroso."pintar" una matriz en otra usando python/numpy

El funcionamiento que tengo en mente es más o menos idéntico al uso de la herramienta Pincel en Photoshop.

Tengo un algoritmo de intención que recorta mi "pincel" para que esté dentro de los límites de mi imagen y agrega cada punto a una imagen de acumulador, pero es lento (!) Y parece que es fundamentalmente más fácil forma de hacer esto.

¿Alguna sugerencia sobre dónde empezar a buscar?

+0

Parece que quieres algún tipo de blit rápido. Sin embargo, me falta conocimiento de Python para sugerir una buena respuesta. – Sekhat

Respuesta

7

En su pregunta usted describe un filtro gaussiano, para el cual scipy tiene soporte a través de un package. Por ejemplo:

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) 

Por supuesto, se puede aplicar esto en toda la imagen, o simplemente en un parche, utilizando rebanar:

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) 

Para la manipulación básica de imágenes, la biblioteca de imágenes de Python (PIL) es probablemente lo que quieres.

NOTA: para "pintar" con un "pincel", creo que podría crear una matriz de máscara booleana con su pincel. Por ejemplo:

# 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) 
+0

Hm, esto puede ponerme en el camino correcto, creo que un poco de magia me ayudará a hacer lo que necesito. – Nate

+0

Agregué un ejemplo con una máscara booleana, tal vez eso es lo que necesita. – catchmeifyoutry

+0

esto es agradable +1 :) – Nope

0

¿Has mirado en Tkinter?

Python Image Library puede ser de ayuda también.

+0

Tkinter me alarma un poco: soy muy receloso de utilizar una GUI takelit para hacer arreglos matemáticos. Y estoy familiarizado con PIL, pero realmente no veo cómo esto resuelve nada que numpy no hace. ¿Todavía tendría que hacer algunos caprichos extraños para agregar las matrices juntas ...? – Nate

2

realmente debería mirar en Andrés motmot y libcamiface paja. Lo usa para experimentos de comportamiento de moscas pero creo que es una biblioteca flexible para hacer el tipo de adquisición y procesamiento de imágenes que estás haciendo. Hay un video de su presentación en SciPy2009.

En cuanto al escenario pincel lo mencionas, me gustaría hacer una copia de la imagen con el método .copy(), mantener la imagen pincel en una matriz, y simplemente añadir que con

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

donde configura first_br_row, last_br_rowfirst_br_col, last_br_col para hacer frente a la sub-imagen en la que desea añadir el cepillo y first_row, last_row, first_col, last_col al clip de la brocha (normalmente los puso a 0 y # filas/cols - 1, pero ajustar cuando' esté lo suficientemente cerca del límite de la imagen como para querer pintar solo parte del pincel).

Espero que todo lo que ayude.

+0

¡Gracias! Resulta que sí, los trucos de división e indexación ayudarán un montón. ¡Sin embargo! La respuesta correcta es, probablemente, dibujar puntos individuales y aplicar el pincel y desenfocar ambos como núcleos. Gracias por el bache en las bibliotecas; sin embargo, esto es realmente una tarea de procesamiento posterior: los datos ya se han recopilado. – Nate

2

Hacer un poco de matemática en el espacio de Fourier puede ayudar: una traducción (convolución por dirac) es igual a una simple multiplicación por una fase en Fourier ... esto hace que su pincel se mueva al lugar exacto (una solución similar que catchmeifyoutry & dwf, pero esto permite una traducción más fina que el píxel, como 2.5, por desgracia con un poco de timbre). Entonces, una suma de tales golpes es la suma de estas operaciones.

En código:

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)) 
1

OpenCV utiliza matrices numpy y tiene funciones básicas de dibujo: círculos, elipses, polilíneas ...

Para dibujar una línea que puede llamar

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

cada vez que obtienes un evento de mouse.

Cuestiones relacionadas