text: import numpy as np
  import cv2
  
  
  def read_points(pts):
      points = []
  
      for key in pts:
          for point in pts[key]:
              points.append(point)
  
      return points
  
  
  def apply_affine_transform(src, src_tri, dst_tri, size):
      warp_mat = cv2.getAffineTransform(np.float32(src_tri), np.float32(dst_tri))
  
      dst = cv2.warpAffine(src, warp_mat, (size[0], size[1]), None, flags=cv2.INTER_LINEAR,
                           borderMode=cv2.BORDER_REFLECT_101)
  
      return dst
  
  
  def rect_contains(rect, point):
      x_inside = rect[0] <= point[0] <= rect[0] + rect[2]
      y_inside = rect[1] <= point[1] <= rect[1] + rect[3]
      return x_inside and y_inside
  
  
  def calculate_delaunay_triangles(rect, points):
      subdiv = cv2.Subdiv2D(rect)
  
      for p in points:
          subdiv.insert(p)
  
      triangle_list = subdiv.getTriangleList()
  
      delaunay_tri = []
  
      pt = []
  
      for t in triangle_list:
          pt1, pt2, pt3 = [(t[i], t[i + 1]) for i in [0, 2, 4]]
          pt += [pt1, pt2, pt3]
  
          if rect_contains(rect, pt1) and rect_contains(rect, pt2) and rect_contains(rect, pt3):
              ind = []
              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)
              if len(ind) == 3:
                  delaunay_tri.append((ind[0], ind[1], ind[2]))
  
          pt = []
  
      return delaunay_tri
  
  
  def warp_triangle(img1, img2, t1, t2):
      r1 = cv2.boundingRect(np.float32([t1]))
      r2 = cv2.boundingRect(np.float32([t2]))
  
      t1_rect = []
      t2_rect = []
      t2_rect_int = []
  
      for i in range(0, 3):
          t1_rect.append(((t1[i][0] - r1[0]), (t1[i][1] - r1[1])))
          t2_rect.append(((t2[i][0] - r2[0]), (t2[i][1] - r2[1])))
          t2_rect_int.append(((t2[i][0] - r2[0]), (t2[i][1] - r2[1])))
  
      mask = np.zeros((r2[3], r2[2], 3), dtype=np.float32)
      cv2.fillConvexPoly(mask, np.int32(t2_rect_int), (1.0, 1.0, 1.0), 16, 0)
  
      img1_rect = img1[r1[1]:r1[1] + r1[3], r1[0]:r1[0] + r1[2]]
      # img2_rect = np.zeros((r2[3], r2[2]), dtype = img1_rect.dtype)
  
      size = (r2[2], r2[3])
  
      img2_rect = apply_affine_transform(img1_rect, t1_rect, t2_rect, size)
  
      img2_rect = img2_rect * 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]] * (
                  (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]] + img2_rect
  