使用PIL复制三角形图像区域

8

我有两张PIL图像和两组对应的2D点,这些点构成了一个三角形。

例如:

image1:
100x100 pixels
points = [(10,10), (20,20), (10,20)]

image2:
250x250 pixels
points = [(35,30), (75,19), (50,90)]

我想从图像1中复制三角形区域,并将其变换以适应图像2中相应的三角形区域。是否有一种方法可以使用PIL完成此操作,而不必逐像素复制并自己计算变换?
2个回答

6

我能够通过仿射变换(感谢这个问题)来实现这个。经过仿射变换后,目标三角形被绘制到掩模上,然后粘贴到目标图像上。以下是我的解决方案:

import Image
import ImageDraw
import numpy

def transformblit(src_tri, dst_tri, src_img, dst_img):
    ((x11,x12), (x21,x22), (x31,x32)) = src_tri
    ((y11,y12), (y21,y22), (y31,y32)) = dst_tri

    M = numpy.array([
                     [y11, y12, 1, 0, 0, 0],
                     [y21, y22, 1, 0, 0, 0],
                     [y31, y32, 1, 0, 0, 0],
                     [0, 0, 0, y11, y12, 1],
                     [0, 0, 0, y21, y22, 1],
                     [0, 0, 0, y31, y32, 1]
                ])

    y = numpy.array([x11, x21, x31, x12, x22, x32])

    A = numpy.linalg.solve(M, y)

    src_copy = src_img.copy()
    srcdraw = ImageDraw.Draw(src_copy)
    srcdraw.polygon(src_tri)
    src_copy.show()
    transformed = src_img.transform(dst_img.size, Image.AFFINE, A)

    mask = Image.new('1', dst_img.size)
    maskdraw = ImageDraw.Draw(mask)
    maskdraw.polygon(dst_tri, fill=255)

    dstdraw = ImageDraw.Draw(dst_img)
    dstdraw.polygon(dst_tri, fill=(255,255,255))
    dst_img.show()
    dst_img.paste(transformed, mask=mask)
    dst_img.show()


im100 = Image.open('test100.jpg')
im250 = Image.open('test250.jpg')

tri1 = [(10,10), (20,20), (10,20)]
tri2 = [(35,30), (75,19), (50,90)]

transformblit(tri1, tri2, im100, im250)

源图像为100x100,如下图所示(白色三角形覆盖):

src_before

目标图像为250x250,如下图所示(白色三角区域填充):

dst_before

变换和粘贴后,目标图像如下所示:

dst_after


是的,但似乎用PIL没有办法做到这一点。这并不太麻烦,因为我从参考帖子中得到了公式,并且numpy可以为我解决方程组。我真正想避免的是逐像素复制。 - jterrace

0

编辑

这种策略仍然涉及一些像素操作,但可以利用API。

  1. 将源图像转换为RGBA。
  2. 找到三角形的最小包围矩形。
  3. 手动设置矩形内所有像素,但不包括三角形部分,全部透明。(您可以使用x/y值的集合、mappartial轻松完成此操作。)
  4. 在目标图像中找到三角形的最小包围矩形。
  5. 通过将源包围矩形缩放到目标大小来将矩形复制到目标图像中。

这样做无法将图像1中的三角形坐标与图像2中的坐标对齐。 - jterrace
我仍然认为这不起作用。它只能处理平移和缩放,而不能处理剪切和旋转。 - jterrace
你在问题中没有提到这一点。如果你所说的“shear”是指偏移,那么当放置在目标上时,你只需要添加delta x/y即可。对于旋转,你可以计算三角形的中心,然后应用这个旋转公式:http://stackoverflow.com/questions/6207480/how-to-rotate-a-two-dimensional-array-to-an-arbitrary-degree/6207584#6207584 - wberry
我认为这是很清楚的,因为三角形的大小和形状不同。最终我使用了一个仿射变换矩阵。请查看我的答案以获取详细信息。 - jterrace

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接