偶像刘德华,我爱你30年,我要和你用python换个脸
1 说明:
=====
1.1 首先:刘德华是我的偶像,一直很喜欢他,向他致敬,无意冒犯,仅供学习。
1.2 技术要点:python+OpenCV(cv2)+dlib+numpy,代码详细,简单通俗,小白秒懂。
1.3 图片来源:今日头条免费正版图库。
偶像刘德华:ldh.jpeg
来自网络,假设是我:me.jpeg
换脸后的效果,小bug,可能与光线有关
2 准备:
=====
2.1 参看文章来源:#https://github.com/Mister5ive/changeFaceImg #下载,提取shape_predictor_68_face_landmarks.dat #上面github下载的代码多,弃用。 #https://blog.csdn.net/ugly_scarecrow/article/details/77449576 #代码来源,并对代码进行修改,注释和删减
2.2 环境:
python3.8+OpenCV4.2.0+dlib19.19+微软编辑器vscode+深度操作系统deepin-linux。
3 代码分析:
=========
3.1 第1步:导入模块import cv2 import dlib import sys import numpy as np
3.2 第2步:参数设定SCALE_FACTOR = 1 FEATHER_AMOUNT = 11 # 代表各个区域的关键点标号 FACE_POINTS = list(range(17, 68)) MOUTH_POINTS = list(range(48, 61)) RIGHT_BROW_POINTS = list(range(17, 22)) LEFT_BROW_POINTS = list(range(22, 27)) RIGHT_EYE_POINTS = list(range(36, 42)) LEFT_EYE_POINTS = list(range(42, 48)) NOSE_POINTS = list(range(27, 35)) JAW_POINTS = list(range(0, 17)) # pupillary distance. 瞳孔距离 COLOUR_CORRECT_BLUR_FRAC = 0.6
3.3 第3步:加载模型,注意路径。模型需要在dlib包或者上面提到的github中获取。PREDICTOR_PATH = "/home/xgj/Desktop/change-face/model/shape_predictor_68_face_landmarks.dat" detector = dlib.get_frontal_face_detector() predictor = dlib.shape_predictor(PREDICTOR_PATH)
3.4 第4步:函数定义# 获取关键点坐标位置,只获取一张人脸 # input:代表一张图片的numpy array # output:68*2的关键点坐标位置matrix def get_landmarks(im): rects = detector(im, 1) return np.matrix([[p.x, p.y] for p in predictor(im, rects[0]).parts()]) def read_im_and_landmarks(fname): im = cv2.imread(fname, cv2.IMREAD_COLOR) im = cv2.resize(im, (im.shape[1] * SCALE_FACTOR, im.shape[0] * SCALE_FACTOR)) s = get_landmarks(im) return im, s def draw_convex_hull(im, points, color): points = cv2.convexHull(points) # 检测凸包函数 cv2.fillConvexPoly(im, points, color=color) # 绘制好多边形后并填充 点的顺序不同绘制出来的凸包也不同 def get_face_mask(im, landmarks): im = np.zeros(im.shape[:2], dtype=np.float64) draw_convex_hull(im,landmarks,color=1) im = np.array([im, im, im]).transpose((1, 2, 0)) # 得到一个类似于3通道的图片 return im # 用普氏分析(Procrustes analysis)调整脸部 def transformation_from_points(points1, points2): points1 = points1.astype(np.float64) points2 = points2.astype(np.float64) c1 = np.mean(points1, axis=0) c2 = np.mean(points2, axis=0) points1 -= c1 points2 -= c2 # 计算标准差 s1 = np.std(points1) s2 = np.std(points2) points1 /= s1 points2 /= s2 # 通过奇异值分解求得旋转矩阵R U, S, Vt = np.linalg.svd(points1.T * points2) R = (U * Vt).T # 维度:2*2 # 仿射变换矩阵3*3 # numpy.hstack用来在第1个维度上拼接tup numpy.vstack在第0个维度上拼接tup return np.vstack([np.hstack(((s2 / s1) * R, c2.T - (s2 / s1) * R * c1.T)), np.matrix([0., 0., 1.])]) def warp_im(im, M, dshape): output_im = np.zeros(dshape, dtype=im.dtype) cv2.warpAffine(im,M[:2],(dshape[1], dshape[0]),dst=output_im,borderMode=cv2.BORDER_TRANSPARENT,flags=cv2.WARP_INVERSE_MAP) return output_im # 颜色校正 def correct_colours(im1, im2, landmarks1): blur_amount = COLOUR_CORRECT_BLUR_FRAC * np.linalg.norm(np.mean(landmarks1[LEFT_EYE_POINTS], axis=0)-np.mean(landmarks1[RIGHT_EYE_POINTS], axis=0)) blur_amount = int(blur_amount) if blur_amount % 2 == 0: blur_amount += 1 im1_blur = cv2.GaussianBlur(im1, (blur_amount, blur_amount), 0) im2_blur = cv2.GaussianBlur(im2, (blur_amount, blur_amount), 0) # Avoid pide-by-zero errors. im2_blur += (128 * (im2_blur <= 1.0)).astype(im2_blur.dtype) return (im2.astype(np.float64) * im1_blur.astype(np.float64)/im2_blur.astype(np.float64))
3.5 第5步:加载图片和开始换脸im1, landmarks1 = read_im_and_landmarks("/home/xgj/Desktop/change-face/me.jpeg") #需要换脸:me的脸 im2, landmarks2 = read_im_and_landmarks("/home/xgj/Desktop/change-face/ldh.jpeg") #偶像的脸:ldh的脸 #换脸点 M = transformation_from_points(landmarks1,landmarks2) # get_face_mask()的定义是为一张图像和一个标记矩阵生成一个掩膜 mask = get_face_mask(im2, landmarks2) warped_mask = warp_im(mask, M, im1.shape) # 33. 用min函数取掩膜区域效果更好 combined_mask = np.min([get_face_mask(im1, landmarks1), warped_mask],axis=0) # 将图像2的掩膜转换到图像1的坐标空间 warped_im2 = warp_im(im2, M, im1.shape) warped_corrected_im2 = correct_colours(im1, warped_im2, landmarks1) output_im = im1 * (1.0 - combined_mask) + warped_corrected_im2 * combined_mask #保存换脸后的图片 #cv2.imwrite("/home/xgj/Desktop/change-face/output.jpg", output_im) output_im = output_im.astype(np.uint8) #展示图片 cv2.imshow("outputface", output_im) cv2.waitKey()
4 操作和效果:
华仔,爱你一万年。
五岁孩子扁桃体肿大,是什么原因引起的?还会引起什么病?扁桃体是人体的免疫器官,相当于两个巨大的淋巴结,经常和外界抗原接触会产生生理性的免疫反应,会产生生理性的免疫反应,之所以会出现扁桃体肿大是因为被病毒或是细菌感染了。宝宝扁桃体肿大的
你在生孩子前多久才停止上班的?我清楚的记得!正月十七的预产期,当天请假去检查了一下,医生说连一指骨缝都没开,回来又继续上班了!一周后,听隔壁嫂子说,她家弟媳也是超了预产期,孩子憋的在肚子里拉胎便了都,家婆沉不住
有人说北方女人坐月子一般喝小米粥,那南方呢?老辈人说,坐月子相当于第二次发育,婚前孕前的痛经宫寒平胸等问题,都有可能通过坐好月子得到改善。反之,月子没坐好,就会落下种种潜在疾病,例如体虚风湿内脏下垂盆底肌松弛等等。所以,女性
女孩第一次来月经大概在13岁,是不是代表她已经有生育能力了?女孩排卵才会产生月经,显示她已有生育能力。如果女孩子13岁出现了青春期发育,尤其是出现规律的月经,是有卵泡排出的,是可以怀孕的,所以如果女孩子这时候发生不正当的性生活,可以造成怀孕
我对孩子自理能力的培养自理能力,就是自我服务自己照顾自己的能力,它是一个人应该具备的最基本的生活技能。好多大人在带小娃过程中,看到孩子自己穿衣服慢腾腾就沉不住气帮孩子穿,看到孩子自己吃饭洒的到处都是,甚
婴幼儿常见便血原因今天我们来继续学习在婴幼儿时期的真性血便的常见原因。1hr肛裂肛裂通俗来讲就是肛门有个裂口,是1岁以下婴儿直肠出血的最常见原因。通常因为大便粗硬,超过了肛门顺应扩张的限度,导致肛门
7岁女孩体重高达100公斤血糖爆表进了ICU命悬一线温州网讯才7岁的小女孩,体重却高达100公斤,血糖超过正常范围的十几倍。孩子因呼吸急促意识不清被送往医院急救。记者昨从温医大附属育英儿童医院获悉,经过医护人员70多个小时的救治,终
生孩子后花了多少钱?不看不知道四脚吞金兽不是浪得虚名如今养育一个孩子的成本无法估量。就算我们没有养育孩子的经验,在日常生活中也是会有所感受的,凡是有关孩子的东西价格都非常高,虽然也有参差不齐的质量,但妈妈们都会选择最好的。这或许就是
养育男孩一定要注意的四件事情1。妈妈一定要树立爸爸在家里面的权威。爸爸是儿子学习的最好榜样,爸爸有权威,儿子才愿意跟他学习。2。爸爸要足够的尊重妈妈。儿子会通过观察父亲的行为,来学习如何爱别人,如何与异性相处
丢掉绘本吧,在孩子最好的学习年纪如果你接触过,你应该很清楚,练钢琴的时候,开始路子不正,后面很难改。练轮滑的时候,如果动作错误,没有发力和节奏意识,后面很难进展。练字的时候,方式方法不对,连审美都会出现问题越来越
老话说夏天一碗汤,不用郎中帮,这3道汤给孩子喝,助力成长夏天到了,天气一天比一天热。燥热的天气里,人们很容易变得没胃口,心情烦闷。老辈子常说夏天一碗汤,不用郎中帮,道出了夏天多喝汤好处多,既能及时给身体补充水分,多种食材搭配制作,营养也