I was able to do this with an affinity transformation (thanks to this question ). After the affine transformation, the destination triangle is drawn to the mask and then inserted into the target image. Here is 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 100x100 source image looks like this (the triangle is superimposed in white):

The 250x250 destination image looks like this (the triangular area is filled with white):

Then, after conversion and paste, the target image is as follows:
