使用Python/Numpy将一个数组“绘制”到另一个数组上

8 投票
5 回答
2924 浏览
提问于 2025-04-15 17:17

我正在用Python写一个库来处理视线追踪的功能,但我对numpy和scipy这些东西还不太熟悉。简单来说,我想把一组时间序列的(x,y)坐标上的点“涂”成某种形状,比如一个模糊的圆。

我想做的操作其实和在Photoshop里用画笔工具差不多。

我有一个互动算法,可以把我的“画笔”限制在图像的边界内,并把每个点加到一个累积图像上,但这个过程很慢!我觉得应该有更简单的方法来实现这个功能。

有没有什么建议可以让我知道从哪里开始找呢?

5 个回答

2

在傅里叶空间里做一点数学可能会有帮助:一个平移(用狄拉克函数进行卷积)实际上等于在傅里叶空间里简单地乘以一个相位... 这就让你的画笔移动到准确的位置(这和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))
3

你真的应该看看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_rowfirst_br_collast_br_col来指定你想添加画笔的子图像区域,同时设置first_rowlast_rowfirst_collast_col来裁剪画笔(通常把它们设为0和行/列的最大值-1,但当你靠近图像边界时,可以调整这些值,只画出画笔的一部分)。

希望这些对你有帮助。

7

在你的问题中,你提到了高斯滤波器,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)

撰写回答