在计算机图形学中,人们一直都在处理变形的三角形,因为任何3D表面都可以由三角形近似。图像可以分解为三角形并变形。但是,在OpenCV中,没有封装好的方法可以将三角形内的像素变换到另一个三角形内的像素。
仿射变换是一组3个点(即三角形)来转换到另一组的任意3个点的最简单的方法。
下图说明了仿射变换如何用于更改正方形的形状。请注意,使用仿射变换可以将正方形的形状更改为任何方向和比例的平行四边形。但是,仿射变换的灵活性不足以将正方形变换为任意四边形。
换句话说,在进行仿射变换之后,平行线继续平行。
opencv封装了仿射变换用的函数:https://www.cnblogs.com/nipan/p/4174271.html
import cv2
import numpy as np
# Warps and alpha blends triangular regions from img1 and img2 to img
def warpTriangle(img1, img2, tri1, tri2) :
# Find bounding rectangle for each triangle计算边界框
r1 = cv2.boundingRect(tri1)
r2 = cv2.boundingRect(tri2)
# Offset points by left top corner of the respective rectangles裁剪图像并更改坐标
tri1Cropped = []
tri2Cropped = []
for i in range(0, 3):
tri1Cropped.append(((tri1[0][i][0] - r1[0]),(tri1[0][i][1] - r1[1])))
tri2Cropped.append(((tri2[0][i][0] - r2[0]),(tri2[0][i][1] - r2[1])))
# Crop input image
img1Cropped = img1[r1[1]:r1[1] + r1[3], r1[0]:r1[0] + r1[2]]
# Given a pair of triangles, find the affine transform.
#刚刚获得了裁剪后的输入和输出图像中输入和输出三角形的坐标。使用这两个三角形,我们可以找到仿射变换,可以使用以下代码在裁剪后的图像中将输入三角形转换为输出三角形。
warpMat = cv2.getAffineTransform( np.float32(tri1Cropped), np.float32(tri2Cropped) )
# Apply the Affine Transform just found to the src image
#上一步中找到的仿射变换将应用于裁剪后的输入图像,以获得裁剪后的输出图像。
img2Cropped = cv2.warpAffine( img1Cropped, warpMat, (r2[2], r2[3]), None, flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101 )
# Get mask by filling triangle
#我们对矩形区域内的三角形感兴趣。因此,我们使用fillConvexPoly创建了一个蒙版,该蒙版用于涂黑三角形之外的所有像素。最后,可以使用输出边界矩形的左上角将此新裁剪的图像放置在输出图像中的正确位置。
mask = np.zeros((r2[3], r2[2], 3), dtype = np.float32)
cv2.fillConvexPoly(mask, np.int32(tri2Cropped), (1.0, 1.0, 1.0), 16, 0);
img2Cropped = img2Cropped * mask
# Copy triangular region of the rectangular patch to the output image
img2[r2[1]:r2[1]+r2[3], r2[0]:r2[0]+r2[2]] = img2[r2[1]:r2[1]+r2[3], r2[0]:r2[0]+r2[2]] * ( (1.0, 1.0, 1.0) - mask )
img2[r2[1]:r2[1]+r2[3], r2[0]:r2[0]+r2[2]] = img2[r2[1]:r2[1]+r2[3], r2[0]:r2[0]+r2[2]] + img2Cropped
if __name__ == '__main__' :
# Read input image
imgIn = cv2.imread("robot.jpg")
# Output image is set to white
imgOut = 255 * np.ones(imgIn.shape, dtype = imgIn.dtype)
# Input triangle
triIn = np.float32([[[360,200], [60,250], [450,400]]])
# Output triangle
triOut = np.float32([[[400,200], [160,270], [400,400]]])
# Warp all pixels inside input triangle to output triangle
warpTriangle(imgIn, imgOut, triIn, triOut)
# Draw triangle using this color
color = (255, 150, 0)
# Draw triangles in input and output images.
cv2.polylines(imgIn, triIn.astype(int), True, color, 2, 16)
cv2.polylines(imgOut, triOut.astype(int), True, color, 2, 16)
cv2.imshow("Input", imgIn)
cv2.imshow("Output", imgOut)
cv2.waitKey(0)