«нарисовать» один массив на другой, используя python / numpy - PullRequest
7 голосов
/ 23 декабря 2009

Я пишу библиотеку для обработки слежения за взглядом в Python, и я довольно новичок во всем мире ошеломленных / скупых. По сути, я хочу взять массив значений (x, y) во времени и «нарисовать» некоторую форму на холсте в этих координатах. Например, форма может быть размытым кругом.

Операция, которую я имею в виду, более или менее идентична использованию кисти в Photoshop.

У меня есть интерактивный алгоритм, который подгоняет мою «кисть» к границам моего изображения и добавляет каждую точку к изображению аккумулятора, но это медленно (!), И кажется, что, возможно, есть принципиально более простой способ сделать это.

Какие-нибудь указатели относительно того, где начать искать?

Ответы [ 5 ]

7 голосов
/ 23 декабря 2009

В своем вопросе вы описываете фильтр Гаусса, для которого scipy поддерживает через пакет . Например:

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)

Конечно, вы можете применить это ко всему изображению или просто к патчу, используя нарезку:

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)

Для базовых операций с изображениями, вероятно, вам нужна библиотека изображений Python ( PIL ).

Примечание: для «рисования» с помощью «кисти», я думаю, вы можете просто создать массив булевых масок с помощью кисти. Например:

# 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)
2 голосов
/ 12 марта 2010

Может помочь небольшая математика в пространстве Фурье: перевод (свертывание по дираку) равен простому умножению на фазу в Фурье ... это заставляет вашу кисть перемещаться в точное место (аналогичное решение, чем catchmeifyoutry & dwf, но это позволяет перевод лучше, чем пиксель, как 2.5, увы, с некоторым звонком). Тогда сумма таких штрихов является суммой этих операций.

В коде:

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 голосов
/ 03 января 2010

Вам действительно стоит взглянуть на motmot и libcamiface Эндрю Строу . Он использует его для экспериментов с поведением мух, но это гибкая библиотека для того, чтобы делать только то, что вы делаете и обрабатываете изображения. Есть видео его презентации на SciPy2009.

Что касается упомянутого вами сценария с кистью, я бы сделал копию изображения с помощью метода .copy (), сохранил изображение кисти в массиве и просто добавил его с помощью

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

где вы установите first_br_row, last_br_row first_br_col, last_br_col для адресации подизображения, в которое вы хотите добавить кисть, и first_row, last_row, first_col, last_col для обрезки кисть (обычно установите их в 0 и # row / cols - 1, но настройте, когда вы достаточно близко к границе изображения, чтобы захотеть рисовать только часть кисти).

Надеюсь, все это поможет.

1 голос
/ 11 июля 2013

OpenCV использует массивы numpy и имеет базовые функции рисования: круги, эллипсы, полилинии ...

Чтобы нарисовать линию, вы можете позвонить

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

каждый раз, когда вы получаете событие мыши.

0 голосов
/ 23 декабря 2009

Вы смотрели на Ткинтер ?

Библиотека изображений Python тоже может помочь.

...