123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- import cv2
- import numpy as np
- import math
- # Constrains points to be inside boundary
- def constrainPoint(p, w, h):
- p = (min(max(p[0], 0), w - 1), min(max(p[1], 0), h - 1))
- return p
- # Compute similarity transform given two sets of two points.
- # OpenCV requires 3 pairs of corresponding points.
- # We are faking the third one.
- def similarityTransform(inPoints, outPoints):
- s60 = math.sin(60*math.pi/180)
- c60 = math.cos(60*math.pi/180)
- inPts = np.copy(inPoints).tolist()
- outPts = np.copy(outPoints).tolist()
- # The third point is calculated so that the three points make an equilateral triangle
- xin = c60*(inPts[0][0] - inPts[1][0]) - s60*(inPts[0][1] - inPts[1][1]) + inPts[1][0]
- yin = s60*(inPts[0][0] - inPts[1][0]) + c60*(inPts[0][1] - inPts[1][1]) + inPts[1][1]
- inPts.append([np.int(xin), np.int(yin)])
- xout = c60*(outPts[0][0] - outPts[1][0]) - s60*(outPts[0][1] - outPts[1][1]) + outPts[1][0]
- yout = s60*(outPts[0][0] - outPts[1][0]) + c60*(outPts[0][1] - outPts[1][1]) + outPts[1][1]
- outPts.append([np.int(xout), np.int(yout)])
- # Now we can use estimateRigidTransform for calculating the similarity transform.
- tform = cv2.estimateAffinePartial2D(np.array([inPts]), np.array([outPts]))
- return tform[0]
- # Check if a point is inside a rectangle
- def rectContains(rect, point):
- if point[0] < rect[0]:
- return False
- elif point[1] < rect[1]:
- return False
- elif point[0] > rect[2]:
- return False
- elif point[1] > rect[3]:
- return False
- return True
- # Calculate Delaunay triangles for set of points
- # Returns the vector of indices of 3 points for each triangle
- def calculateDelaunayTriangles(rect, points):
- # Create an instance of Subdiv2D
- subdiv = cv2.Subdiv2D(rect)
- # Insert points into subdiv
- for p in points:
- subdiv.insert((int(p[0]), int(p[1])))
- # Get Delaunay triangulation
- triangleList = subdiv.getTriangleList()
- # Find the indices of triangles in the points array
- delaunayTri = []
- for t in triangleList:
- # The triangle returned by getTriangleList is
- # a list of 6 coordinates of the 3 points in
- # x1, y1, x2, y2, x3, y3 format.
- # Store triangle as a list of three points
- pt = []
- pt.append((t[0], t[1]))
- pt.append((t[2], t[3]))
- pt.append((t[4], t[5]))
- pt1 = (t[0], t[1])
- pt2 = (t[2], t[3])
- pt3 = (t[4], t[5])
- if rectContains(rect, pt1) and rectContains(rect, pt2) and rectContains(rect, pt3):
- # Variable to store a triangle as indices from list of points
- ind = []
- # Find the index of each vertex in the points list
- for j in range(0, 3):
- for k in range(0, len(points)):
- if(abs(pt[j][0] - points[k][0]) < 1.0 and abs(pt[j][1] - points[k][1]) < 1.0):
- ind.append(k)
- # Store triangulation as a list of indices
- if len(ind) == 3:
- delaunayTri.append((ind[0], ind[1], ind[2]))
- return delaunayTri
- # Apply affine transform calculated using srcTri and dstTri to src and
- # output an image of size.
- def applyAffineTransform(src, srcTri, dstTri, size):
- # Given a pair of triangles, find the affine transform.
- warpMat = cv2.getAffineTransform(np.float32(srcTri), np.float32(dstTri))
- # Apply the Affine Transform just found to the src image
- dst = cv2.warpAffine(src, warpMat, (size[0], size[1]), None,
- flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101)
- return dst
- # Warps and alpha blends triangular regions from img1 and img2 to img
- def warpTriangle(img1, img2, t1, t2):
- # Find bounding rectangle for each triangle
- r1 = cv2.boundingRect(np.float32([t1]))
- r2 = cv2.boundingRect(np.float32([t2]))
- # Offset points by left top corner of the respective rectangles
- t1Rect = []
- t2Rect = []
- t2RectInt = []
- for i in range(0, 3):
- t1Rect.append(((t1[i][0] - r1[0]), (t1[i][1] - r1[1])))
- t2Rect.append(((t2[i][0] - r2[0]), (t2[i][1] - r2[1])))
- t2RectInt.append(((t2[i][0] - r2[0]), (t2[i][1] - r2[1])))
- # Get mask by filling triangle
- mask = np.zeros((r2[3], r2[2], 3), dtype=np.float32)
- cv2.fillConvexPoly(mask, np.int32(t2RectInt), (1.0, 1.0, 1.0), 16, 0)
- # Apply warpImage to small rectangular patches
- img1Rect = img1[r1[1]:r1[1] + r1[3], r1[0]:r1[0] + r1[2]]
- size = (r2[2], r2[3])
- img2Rect = applyAffineTransform(img1Rect, t1Rect, t2Rect, size)
- img2Rect = img2Rect * 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]] + img2Rect
|