I am trying to perform image warping, but I can't seem to apply the transformation matrix given a set of points. Am trying to accomplish is a face morphing given the feature points which in total is 68 feature points I already calculated the triangulation between the points but I can't seem to warp the image.
import numpy as np
import cv2 as cv
import dlib
from warp import triangulate, warp
def crop_faces(image1_path, image2_path):
cropped_faces_list = []
for img in [image1_path, image2_path]:
image = cv.imread(img)
# convert to grayscale of each frames
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
# read the haarcascade to detect the faces in an image
face_cascade = cv.CascadeClassifier(cv.data.haarcascades + 'haarcascade_frontalface_default.xml')
# detects faces in the input image
faces = face_cascade.detectMultiScale(gray, 1.3, 4)
print('Number of detected faces:', len(faces))
# Crop and save each detected face
cropped_faces = []
if len(faces) > 0:
for (x, y, w, h) in faces:
cropped_faces.append(image[y: y + h, x:x + w])
cropped_faces_list.append(cropped_faces)
return cropped_faces_list
def generate_face_correspondeces(theImage1, theImage2):
# Detect the points of face.
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
imgList = crop_faces(theImage1, theImage2)
list1 = []
list2 = []
feature_points = []
cropped_images = []
j = 1
for m, img_list in enumerate(imgList):
for img in img_list:
if (j == 1):
currList = list1
else:
currList = list2
# Ask the detector to find the bounding boxes of each face. The 1 in the
# second argument indicates that we should upsample the image 1 time. This
# will make everything bigger and allow us to detect more faces.
dets = detector(img, 1)
try:
if len(dets) == 0:
raise NoFaceFound # type: ignore
except NoFaceFound: # type: ignore
print("Sorry, but I couldn't find a face in the image.")
j = j + 1
for k, rect in enumerate(dets):
# Get landmarks/part for the face in rect
shape = predictor(img, rect)
for i in range(0, 68):
x = shape.part(i).x
y = shape.part(i).y
currList.append((x, y))
cv.circle(img, (x, y), 1, (0, 255, 0), 2)
feature_points.append(currList)
cropped_images.append(img)
cv.imwrite(f"test_{m}.png", img)
return feature_points, cropped_images
img1 = './Images/mulher1.jpg'
img2 = './Images/homem.jpg'
feature_points, cropped_images = generate_face_correspondeces(img1, img2)
for i, image in enumerate(cropped_images):
triangulate(image, feature_points[i])
warp(img2, feature_points[0], feature_points[1])
import numpy as np
import cv2 as cv
def triangulate(image, points):
# Create Subdiv2D object
rect = (0, 0, image.shape[0], image.shape[1]) # Rectangle covering the entire image
triangulation = cv.Subdiv2D(rect)
# Insert points into triangulation object
valid_points = [] # List to store valid points within the image bounds
for point in points:
x, y = point
if 0 <= x < image.shape[1] and 0 <= y < image.shape[0]: # Check if point is within image bounds
triangulation.insert((x, y))
valid_points.append((x, y))
# Get triangles
triangleList1 = triangulation.getTriangleList()
# Draw triangles on the image (optional)
for t in triangleList1:
pt1 = (int(t[0]), int(t[1]))
pt2 = (int(t[2]), int(t[3]))
pt3 = (int(t[4]), int(t[5]))
cv.line(image, pt1, pt2, (0, 255, 0), 1, cv.LINE_AA)
cv.line(image, pt2, pt3, (0, 255, 0), 1, cv.LINE_AA)
cv.line(image, pt3, pt1, (0, 255, 0), 1, cv.LINE_AA)
# Show or return the triangulated image (optional)
cv.imshow('Triangulated Image', image)
cv.waitKey(0)
cv.destroyAllWindows()
return valid_points
def warp(image, points1, points2):
# Compute affine transformation matrix
M = cv.getAffineTransform(np.float32(points1), np.float32(points2))
# Warp image1 onto image2
rows, cols, _ = image.shape
warped_image = cv.warpAffine(image, M, (cols, rows))
# Display or save the warped image
cv.imshow('Warped Image', warped_image)
cv.waitKey(0)
cv.destroyAllWindows()
Am getting this error
M = cv.getAffineTransform(np.float32(points1), np.float32(points2))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cv2.error: OpenCV(4.9.0) D:\a\opencv-python\opencv-python\opencv\modules\imgproc\src\imgwarp.cpp:3554: error: (-215:Assertion failed) src.checkVector(2, CV_32F) == 3 && dst.checkVector(2, CV_32F) == 3 in function 'cv::getAffineTransform'
In my initial attempt, i used cv.getAffineTransform()
to compute the affine transformation matrix (M) based on the feature points (points1 and points2). However, this function expects exactly three points in each list to compute the transformation matrix for an affine transformation.
The face landmarks likely consist of more than three points (68 points to be exact), which means cv.getAffineTransform()
wouldn't work as intended because it expects only three corresponding points for an affine transformation.
Instead, i used cv.estimateAffine2D()
. This function estimates an affine transformation between two sets of points even when there are more than three points. It computes the best-fit affine transformation matrix based on the provided sets of corresponding points (src_pts and dst_pts). This function is more suitable for the case since i have a larger number of feature points (68 points) to determine the transformation.
img1 = './Images/mulher1.jpg'
img2 = './Images/homem.jpg'
feature_points, cropped_images = generate_face_correspondeces(img1, img2)
img_shape = []
for i, image in enumerate(cropped_images):
triangulate(image, feature_points[i])
img_shape.append((image.shape[1], image.shape[0]))
src_pts = np.asarray(feature_points[1], dtype=np.float32)
dst_pts = np.asarray(feature_points[0], dtype=np.float32)
transformMatrix = cv.estimateAffine2D(src_pts, dst_pts)
warped_img = cv.warpAffine(cropped_images[1], transformMatrix[0], img_shape[0])
cv.imshow("img", warped_img)
cv.waitKey(0)