Копирование треугольной области изображения с помощью PIL - PullRequest
7 голосов
/ 04 августа 2011

У меня есть два изображения 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 ]

5 голосов
/ 05 августа 2011

Мне удалось сделать это с помощью аффинного преобразования (благодаря этому вопросу ). После аффинного преобразования целевой треугольник рисуется в маске, а затем вставляется в конечное изображение. Вот что я придумал:

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

0 голосов
/ 05 августа 2011

EDITED

Эта стратегия все еще включает в себя некоторые манипуляции с пикселями, но может несколько использовать API.

  1. Преобразование исходного изображения в RGBA.
  2. Найдите наименьший вмещающий прямоугольник вашего треугольника.
  3. Вручную установите все пиксели в прямоугольнике, но НЕ в части треугольника, на полностью прозрачный. (Вы можете сделать это без особых проблем, используя наборы для значений x / y, map и partial.)
  4. Найдите наименьший вмещающий прямоугольник треугольника на целевом изображении.
  5. Скопируйте прямоугольник в целевое изображение путем масштабирования исходного прямоугольника до целевого размера.
...