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

У меня есть два изображения 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 без необходимости копировать пиксель за пикселем и самостоятельно вычислять преобразование?


person jterrace    schedule 04.08.2011    source источник


Ответы (2)


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

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

Целевое изображение размером 250 x 250 выглядит следующим образом (треугольная область, заполненная белым цветом):

dst_before

А затем, после преобразования и вставки, целевое изображение выглядит так:

dst_after

person jterrace    schedule 05.08.2011
comment
Да, но не похоже, чтобы это можно было сделать с помощью PIL. Это не составило особых проблем, так как я получил формулу из упомянутого поста, и numpy решает для меня систему уравнений. Чего я действительно хотел избежать, так это копирования попиксельно. - person jterrace; 05.08.2011

ОТРЕДАКТИРОВАНО

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

  1. Преобразование исходного изображения в RGBA.
  2. Найдите наименьший прямоугольник, охватывающий ваш треугольник.
  3. Вручную установите для всех пикселей внутри прямоугольника, но НЕ части треугольника, значение полной прозрачности. (Вы могли бы сделать это без особых проблем, используя наборы для значений x/y, map и partial.)
  4. Найдите наименьший прямоугольник, охватывающий треугольник в целевом изображении.
  5. Скопируйте прямоугольник в целевое изображение, масштабируя прямоугольник, охватывающий источник, до целевого размера.
person wberry    schedule 04.08.2011
comment
Это не выровняет координаты треугольника на изображении1 с координатами на изображении2 - person jterrace; 05.08.2011
comment
Я все еще не думаю, что это работает. Он позаботится только о переводе и масштабировании, а не о сдвиге и вращении. - person jterrace; 05.08.2011
comment
Вы не упомянули об этом в своем вопросе. Если под сдвигом вы подразумеваете смещение, то вам просто нужно добавить дельту x/y при размещении над целью. Для вращения вы можете вычислить центр треугольника, а затем применить эту формулу вращения: -an-arbitrary-grade/6207584#6207584" title="как повернуть двумерный массив на произвольную степень"> stackoverflow.com/questions/6207480/ - person wberry; 05.08.2011
comment
Я думал, что это ясно, поскольку треугольники имеют разный размер и форму. В итоге я использовал матрицу аффинного преобразования. Подробности смотрите в моем ответе. - person jterrace; 05.08.2011