[日常] 基于人脸关键点的人脸对齐实现 水深无声 2024-04-17 05:46 23阅读 0赞 > 本篇文档仅讨论通过人脸关键点在二维平面上进行人脸对齐,不讨论三维相关的算法。 > 代码中所使用 landmark 依据下图所示: > > ![20190823182203437.jpg][] ### 1. 通过双眼坐标进行旋正 ### import cv2 import math import numpy as np def Alignment_1(img,landmark): if landmark.shape[0]==68: # use left_eye and right_eye location x = landmark[36,0] - landmark[45,0] y = landmark[36,1] - landmark[45,1] elif landmark.shape[0]==5: x = landmark[0,0] - landmark[1,0] y = landmark[0,1] - landmark[1,1] if x==0: angle = 0 else: angle = math.atan(y/x)*180/math.pi center = (img.shape[1]//2, img.shape[0]//2) RotationMatrix = cv2.getRotationMatrix2D(center, angle, 1) new_img = cv2.warpAffine(img,RotationMatrix,(img.shape[1],img.shape[0])) RotationMatrix = np.array(RotationMatrix) new_landmark = [] for i in range(landmark.shape[0]): pts = [] pts.append(RotationMatrix[0,0]*landmark[i,0]+RotationMatrix[0,1]*landmark[i,1]+RotationMatrix[0,2]) pts.append(RotationMatrix[1,0]*landmark[i,0]+RotationMatrix[1,1]*landmark[i,1]+RotationMatrix[1,2]) new_landmark.append(pts) new_landmark = np.array(new_landmark) return new_img, new_landmark ### 2. 通过矩阵运算求解仿射矩阵进行旋正 ### import cv2 import math import numpy as np def Alignment_2(std_img,std_landmark,img,landmark): # https://matthewearl.github.io/2015/07/28/switching-eds-with-python/ def Transformation(std_landmark,landmark): std_landmark = np.matrix(std_landmark).astype(np.float64) landmark = np.matrix(landmark).astype(np.float64) c1 = np.mean(std_landmark, axis=0) c2 = np.mean(landmark, axis=0) std_landmark -= c1 landmark -= c2 s1 = np.std(std_landmark) s2 = np.std(landmark) std_landmark /= s1 landmark /= s2 U, S, Vt = np.linalg.svd(std_landmark.T * landmark) R = (U * Vt).T return np.vstack([np.hstack(((s2 / s1) * R, c2.T - (s2 / s1) * R * c1.T)),np.matrix([0., 0., 1.])]) Trans_Matrix = Transformation(std_landmark,landmark) # Shape: 3 * 3 Trans_Matrix = Trans_Matrix[:2] Trans_Matrix = cv2.invertAffineTransform(Trans_Matrix) new_img = cv2.warpAffine(img,Trans_Matrix,(img.shape[1],img.shape[0])) Trans_Matrix = np.array(Trans_Matrix) new_landmark = [] for i in range(landmark.shape[0]): pts = [] pts.append(Trans_Matrix[0,0]*landmark[i,0]+Trans_Matrix[0,1]*landmark[i,1]+Trans_Matrix[0,2]) pts.append(Trans_Matrix[1,0]*landmark[i,0]+Trans_Matrix[1,1]*landmark[i,1]+Trans_Matrix[1,2]) new_landmark.append(pts) new_landmark = np.array(new_landmark) return new_img, new_landmark ### 3. 通过最小二乘法求解仿射矩阵进行旋正 ### import cv2 import math import numpy as np def Alignment_3(std_img,std_landmark,img,landmark): def Transformation(std_landmark,landmark): Trans_Matrix = np.float32([[1, 0, 0], [0, 1, 0]]) n_pts = landmark.shape[0] ones = np.ones((n_pts, 1), landmark.dtype) landmark_ = np.hstack([landmark, ones]) std_landmark_ = np.hstack([std_landmark, ones]) A, res, rank, s = np.linalg.lstsq(landmark_, std_landmark_,rcond=-1) if rank == 3: Trans_Matrix = np.float32([ [A[0, 0], A[1, 0], A[2, 0]], [A[0, 1], A[1, 1], A[2, 1]] ]) elif rank == 2: Trans_Matrix = np.float32([ [A[0, 0], A[1, 0], 0], [A[0, 1], A[1, 1], 0] ]) return Trans_Matrix # def Transformation(std_landmark,landmark): # from matlab_cp2tform import get_similarity_transform_for_cv2 # return get_similarity_transform_for_cv2(landmark, std_landmark, False) Trans_Matrix = Transformation(std_landmark,landmark) # Shape: 2 * 3 new_img = cv2.warpAffine(img,Trans_Matrix,(img.shape[1],img.shape[0])) Trans_Matrix = np.array(Trans_Matrix) new_landmark = [] for i in range(landmark.shape[0]): pts = [] pts.append(Trans_Matrix[0,0]*landmark[i,0]+Trans_Matrix[0,1]*landmark[i,1]+Trans_Matrix[0,2]) pts.append(Trans_Matrix[1,0]*landmark[i,0]+Trans_Matrix[1,1]*landmark[i,1]+Trans_Matrix[1,2]) new_landmark.append(pts) new_landmark = np.array(new_landmark) return new_img, new_landmark ### 4. 总结 ### **对比三种方式,其运行结果如下所示:** ![20190823181623371.jpg][]![20190823181614663.jpg][]![20190823181606147.jpg][] **参考资料:** * [Switching Eds: Face swapping with Python, dlib, and OpenCV][Switching Eds_ Face swapping with Python_ dlib_ and OpenCV] * [numpy.linalg.lstsq这个是什么意思啊?][numpy.linalg.lstsq] * [新视界-OpenCV教程(12)- 图像的几何变换][-OpenCV_12_-] * [【人脸】人脸检测与对齐python实现][python] * [opencv仿射变换GetAffineTransform的总结][opencv_GetAffineTransform] * [Opencv-Python学习笔记五——图像翻转,平移,仿射及透视 warpAffine][Opencv-Python_ warpAffine] [20190823182203437.jpg]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/11/8570b77a9abc4f25a7ede4c8eadc95d9.jpg [20190823181623371.jpg]: https://img-blog.csdnimg.cn/20190823181623371.jpg [20190823181614663.jpg]: https://img-blog.csdnimg.cn/20190823181614663.jpg [20190823181606147.jpg]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/11/5a722b1ceb2943f2aac5f2be5cd32734.jpg [Switching Eds_ Face swapping with Python_ dlib_ and OpenCV]: https://matthewearl.github.io/2015/07/28/switching-eds-with-python/ [numpy.linalg.lstsq]: https://www.zhihu.com/question/40540185 [-OpenCV_12_-]: https://zhuanlan.zhihu.com/p/47273624 [python]: https://zhuanlan.zhihu.com/p/55479744 [opencv_GetAffineTransform]: https://blog.csdn.net/gdut2015go/article/details/46359165 [Opencv-Python_ warpAffine]: https://www.jianshu.com/p/ef67cacf442c
还没有评论,来说两句吧...