开发者

Copying triangular image region with PIL

开发者 https://www.devze.com 2023-03-26 03:52 出处:网络
I have two PIL images and two sets of corresponding 2D points that make a triangle. For example: image1:

I have two PIL images and two sets of corresponding 2D points that make a triangle.

For example:

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

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

I want to copy the triangular re开发者_高级运维gion from image1 and transform it to fit into the corresponding triangular region of image2. Is there any way to do this with PIL without having to copy pixel by pixel and calculate the transformation myself?


I was able to do this with an affine transformation (thanks to this question). After the affine transformation, the destination triangle is drawn to a mask and then pasted on to the destination image. Here's what I came up with:

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)

The source 100x100 image looks like this (triangle overlaid in white):

Copying triangular image region with PIL

The destination 250x250 image looks like this (triangular region filled in with white):

Copying triangular image region with PIL

And then after the transformation and pasting, the destination image looks like this:

Copying triangular image region with PIL


EDITED

This strategy still involves some pixel manipulation, but can leverage the APIs somewhat.

  1. Convert source image into RGBA.
  2. Find the smallest enclosing rectangle of your triangle.
  3. Manually set all pixels within the rectangle, but NOT part of the triangle, to fully transparent. (You might be able to do this without too much trouble using sets for the x/y values, map and partial.)
  4. Find the smallest enclosing rectangle of the triangle in the target image.
  5. Copy the rectangle into the target image by scaling the source enclosing rectangle to the target size.
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号