07-人脸识别-人脸矫正
人脸矫正有几个问题。
1.歪头:
2.侧脸:
3.半边脸:缺失另外半边脸,要寻找其他的解决方案。
大多数情况下,截取到的人脸是包含歪头和侧脸的现象的。这两个问题,可以同时通过仿射变换来矫正。
但是要注意,侧脸,是缺少一部分脸部信息的。
人脸矫正,对歪头的正确度提高有帮助,对侧脸就一般了。
思路:
1.之前步骤已经在每张人脸上找到5个特征;
2.测量 正面脸 的五点对应坐标 pts_dst(这是测量出来的,重要的是5点的位置相对关系);
3.每张脸的5个点坐标 pts_src,其中的鼻子坐标要设置成和2中鼻子坐标相同,其他坐标点按比例换算;
4.这两组左边,估计矫正的单应性矩阵(就是仿射变换矩阵,歪脸 to 正脸的变换矩阵);
5.然后对人脸做仿射变换,得到矫正后的图。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | import tensorflow as tf import numpy as np import cv2 import detect_face import matplotlib.pyplot as plt import math from scipy import misc img = misc.imread( '001.jpg' ) sess = tf.Session() pnet, rnet, onet = detect_face.create_mtcnn(sess, None ) # pnet, rnet, onet are 3 funtions minsize = 20 threshold = [ 0.6 , 0.7 , 0.7 ] factor = 0.709 df_result, df_points_result = detect_face.detect_face(img, minsize, pnet, rnet, onet, threshold, factor) # df_points_result is faceNumber X 10 # need transpose to 10 X faceNumber df_points_result = np.transpose(df_points_result) vec_vec_points = [] for subPoints in df_points_result: # subPoints: [x1,x2,x3,x4,x5,y1,y2,y3,y4,y5] # image axis, so convert nose to (48,48) # Points of small faces are too close to compute correct Homography Matrix. # So, scale points. deltaX = 48 - subPoints[ 2 ] deltaY = 48 - subPoints[ 7 ] vec_vec_points.append([[subPoints[ 0 ] + deltaX, subPoints[ 5 ] + deltaY], [subPoints[ 1 ] + deltaX, subPoints[ 6 ] + deltaY], [subPoints[ 2 ] + deltaX, subPoints[ 7 ] + deltaY], [subPoints[ 3 ] + deltaX, subPoints[ 8 ] + deltaY], [subPoints[ 4 ] + deltaX, subPoints[ 9 ] + deltaY]]) n_face = df_result.shape[ 0 ] print ( 'detected face number: {}' . format (n_face)) print (df_result) plt.figure( 'faces' ) i = 0 plt_nrow = n_face / 5 plt_nrow = plt_nrow + int (n_face ! = plt_nrow * 5 ) plt_ncol = 5 crop_face = [] crop_face_adjust = [] size_img = ( 96 , 96 ) pts_dst = np.array([[ 29.0 , 24.0 ],[ 67.0 , 24.0 ],[ 48.0 , 48.0 ],[ 28.0 , 62.0 ],[ 68.0 , 62.0 ]]) # measure for subfaceRec in df_result: i = i + 1 subfaceRec = subfaceRec.astype( int ) img_a_face = img[subfaceRec[ 1 ]:subfaceRec[ 3 ], subfaceRec[ 0 ]:subfaceRec[ 2 ]] crop_face.append(img_a_face) # adjust image pts_src = np.array(vec_vec_points[i - 1 ]) H, _ = cv2.findHomography(pts_src, pts_dst) img_a_face_adjust = cv2.warpPerspective(img_a_face, H, (img_a_face.shape[ 1 ] + 30 , img_a_face.shape[ 0 ] + 30 )) crop_face_adjust.append(img_a_face_adjust) # resize image img_a_face = cv2.resize(img_a_face, size_img, interpolation = cv2.INTER_CUBIC) # display and show print ( 'plt_nrow:{}, plt_ncol:{}, i:{}' . format (plt_nrow, plt_ncol, i)) plt.subplot(plt_nrow, plt_ncol, i) plt.imshow(img_a_face) cv2.rectangle(img, (subfaceRec[ 0 ], subfaceRec[ 1 ]), (subfaceRec[ 2 ], subfaceRec[ 3 ]), ( 0 , 255 , 0 ), 2 ) # show face adjust i = 0 plt.figure( 'faces_adjust' ) for sub_img_ad in crop_face_adjust: timg = cv2.resize(sub_img_ad, size_img, interpolation = cv2.INTER_CUBIC) i = i + 1 plt.subplot(plt_nrow, plt_ncol, i) plt.imshow(timg) # draw points plt.figure( 'img' ) for subPoints in df_points_result: # subPoints: [x1,x2,x3,x4,x5,y1,y2,y3,y4,y5] cv2.circle(img, (subPoints[ 0 ], subPoints[ 5 ]), 2 , ( 255 , 0 , 0 ), - 1 ) # Red left eye cv2.circle(img, (subPoints[ 1 ], subPoints[ 6 ]), 2 , ( 0 , 0 , 255 ), - 1 ) # Blue right eye cv2.circle(img, (subPoints[ 2 ], subPoints[ 7 ]), 2 , ( 0 , 255 , 0 ), - 1 ) # Green nose cv2.circle(img, (subPoints[ 3 ], subPoints[ 8 ]), 2 , ( 255 , 255 , 0 ), - 1 ) # yellow left mouse cv2.circle(img, (subPoints[ 4 ], subPoints[ 9 ]), 2 , ( 0 , 255 , 255 ), - 1 ) # cyan right mouse plt.imshow(img) plt.show() sess.close() |
结果:
问题:
效果不是很理想,或许只使用旋转矩阵,效果更好吧。
毕竟侧脸情况,要考虑其他更有效的算法。
值得一提的是,FaceNet对于输入的人脸,没有矫正的要求。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?