7

Tengo dos imágenes PIL y dos conjuntos de puntos 2D correspondientes que forman un triángulo.Copiando región de imagen triangular con PIL

Por ejemplo:

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

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

quiero copiar la región triangular desde imagen1 y transformarla para encajar en la región triangular correspondiente de imagen2. ¿Hay alguna manera de hacer esto con PIL sin tener que copiar píxel por píxel y calcular la transformación yo mismo?

Respuesta

3

Pude hacer esto con una transformación afín (gracias a this question). Después de la transformación afín, el triángulo de destino se dibuja en una máscara y luego se pega a la imagen de destino. Esto es lo que ocurrió:

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) 

El origen de la imagen de 100x100 se ve así (triángulo sobrepuesto en blanco):

src_before

El destino de imagen de 250x250 se ve así (región triangular rellena con blanco):

dst_before

y luego, después de la transformación y pegar, el des tino imagen se ve así:

dst_after

+0

¿No deseaba calcular la transformación a mano? – carlosdc

+0

Sí, pero no parecía que hubiera una manera de hacer eso con PIL.No fue demasiado problema ya que obtuve la fórmula de la publicación referenciada y numpy resuelve el sistema de ecuaciones para mí. Lo que realmente quería evitar era copiar píxel por píxel. – jterrace

0

EDITED

Esta estrategia todavía implica una cierta manipulación de píxeles, pero puede aprovechar las API algo.

  1. Convertir la imagen de origen en RGBA.
  2. Encuentra el rectángulo de encierre más pequeño de tu triángulo.
  3. Establezca manualmente todos los píxeles dentro del rectángulo, pero NO parte del triángulo, a completamente transparente. (Es posible que pueda hacer esto sin demasiados problemas usando conjuntos para los valores x/y, map y partial.)
  4. Busque el rectángulo más pequeño que rodea al triángulo en la imagen de destino.
  5. Copie el rectángulo en la imagen de destino escalando el rectángulo de origen de la fuente al tamaño de destino.
+0

que no va a alinear el triángulo de coordenadas en imagen1 con las coordenadas en imagen2 – jterrace

+0

Todavía no creo que esto funciona. Solo se ocupará de la traducción y la escala, no del corte ni de la rotación. – jterrace

+0

No mencionó eso en su pregunta. Si por cizalla te refieres a desplazamiento, entonces solo tienes que agregar el delta x/y cuando lo colocas sobre el objetivo. Para la rotación, puede calcular el centro del triángulo y luego aplicar esta fórmula de rotación: http://stackoverflow.com/questions/6207480/how-to-rotate-a-two-dimensional-array-to-an-arbitrary- grado/6207584 # 6207584 – wberry

Cuestiones relacionadas