7

我有兩個PIL圖像和兩組相應的創建三角形的2D點。使用PIL複製三角形圖像區域

例如:

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

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

欲三角形區域從圖像1複製並變換其配合到圖像2的對應的三角形區域。有沒有辦法與PIL做到這一點,而不必逐個像素地複製並自己計算轉換?

回答

3

我能夠通過仿射變換完成此操作(感謝this question)。仿射變換之後,將目標三角形繪製到蒙版上,然後粘貼到目標圖像上。以下是我想出了:

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

,然後將變換和粘貼後的DES tination圖像看起來是這樣的:

dst_after

+0

難道你不想用手來計算轉換嗎? – carlosdc

+0

是的,但似乎沒有辦法用PIL做到這一點。從參考文章中得到公式後,並沒有太多的麻煩,numpy爲我解決了方程組。我真正想避免的是逐個像素地複製。 – jterrace

0

EDITED

這種策略仍涉及一些像素操作,但可以在一定程度利用這些API。

  1. 將源圖像轉換爲RGBA。
  2. 找到三角形中最小的包圍矩形。
  3. 手動設置矩形內的所有像素,但不是三角形的一部分,以完全透明。 (您可以使用x/y值設置,mappartial,而無需太多麻煩。)
  4. 在目標圖像中查找三角形的最小包圍矩形。
  5. 通過將源封閉矩形縮放到目標大小,將矩形複製到目標圖像中。
+0

這不會排隊三角座標圖像1與圖像2 – jterrace

+0

我仍然不認爲這個工程的座標。它只會照顧平移和縮放,而不是剪切和旋轉。 – jterrace

+0

你沒有提到你的問題。如果通過剪切來表示偏移量,那麼當放置在目標上時,您只需添加δx/y。對於旋轉,你可以計算三角形的中心,然後應用這個旋轉公式:http://stackoverflow.com/questions/6207480/how-to-rotate-a-two-dimensional-array-to-an-arbitrary-度/ 6207584#6207584 – wberry