“绘画”使用 python / numpy 将一个数组复制到另一个数组

发布于 2024-08-16 05:31:57 字数 267 浏览 3 评论 0原文

我正在编写一个库来用 Python 处理注视跟踪,并且我对整个 numpy / scipy 世界相当陌生。本质上,我希望及时获取一组 (x,y) 值,并在这些坐标的画布上“绘制”一些形状。例如,形状可能是一个模糊的圆圈。

我想到的操作与使用 Photoshop 中的画笔工具大致相同。

我有一个交互式算法,可以将我的“画笔”修剪到图像的范围内,并将每个点添加到累加器图像中,但它很慢(!),而且似乎可能有一种根本上更简单的方法来做到这一点。

关于从哪里开始寻找的任何指示?

I'm writing a library to process gaze tracking in Python, and I'm rather new to the whole numpy / scipy world. Essentially, I'm looking to take an array of (x,y) values in time and "paint" some shape onto a canvas at those coordinates. For example, the shape might be a blurred circle.

The operation I have in mind is more or less identical to using the paintbrush tool in Photoshop.

I've got an interative algorithm that trims my "paintbrush" to be within the bounds of my image and adds each point to an accumulator image, but it's slow(!), and it seems like there's probably a fundamentally easier way to do this.

Any pointers as to where to start looking?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

青春如此纠结 2024-08-23 05:31:57

在您的问题中,您描述了一个高斯滤波器,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)

In your question you describe a Gaussian filter, for which scipy has support via a 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 a 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 manipulation, the Python Image library (PIL) is probably what you want.

NOTE:
for "painting" with a "brush", I think you could just create a boolean mask array with your brush. For instance:

# 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)
青朷 2024-08-23 05:31:57

你真的应该研究一下 Andrew Straw 的 motmotlibcamiface。他将它用于苍蝇行为实验,但它是一个灵活的库,可以完成我认为您正在做的图像采集和处理。有一个关于他在 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_rowlast_br_row first_br_collast_br_col 定位要添加画笔的子图像以及 first_rowlast_rowfirst_collast_col 来剪辑画笔(通常将它们设置为 0 和 # rows/cols - 1,但当您足够接近画笔时进行调整)图像边界只想绘制画笔的一部分)。

希望一切有帮助。

You should really look into Andrew Straw's motmot and libcamiface. He uses it for fly behaviour experiments but it's a flexible library for doing just the kind of image acquisition and processing you're doing I think. There's a video of his presentation at SciPy2009.

As for the paintbrush scenario you mention, I'd make a copy of the image with the .copy() method, keep the paintbrush image in an array, and simply 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 to address the subimage where you want to add the brush and first_row, last_row, first_col, last_col to clip the brush (normally set them to 0 and # rows/cols - 1, but adjust when you're near enough to the image boundary to only want to paint part of the brush).

Hope all that helps.

初见终念 2024-08-23 05:31:57

在傅里叶空间中做一些数学可能会有所帮助:平移(狄拉克卷积)等于傅里叶中的相位的简单乘法......这使您的画笔移动到确切的位置(与 catchmeifyoutry 和 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))

Doing a little of math in Fourier space may help: a translation (convolution by a dirac) is equal to a simple multiplication by a phase in Fourier... this makes your paintbrush move to the exact place (a similar solution than catchmeifyoutry & dwf, but this allows a translation finer than the pixel, like 2.5, alas with some ringing). Then, a 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))
苦妄 2024-08-23 05:31:57

OpenCV 使用 numpy 数组并具有基本的绘图功能:圆、椭圆、折线...

要绘制一条线,您可以

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

在每次收到鼠标事件时调用。

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

To draw a line you can call

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

each time you get a mouse event.

硪扪都還晓 2024-08-23 05:31:57

您是否研究过Tkinter

Python 图像库 也可能有一些帮助。

Have you looked into Tkinter?

Python Image Library may be some help too.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文