人脸美颜——飞桨PaddleHub实战
基于PaddleHub的人脸美颜
随着各种美颜相机的出现,我们可以拍出各种胜似明星的照片,我们可以瘦脸、大眼、红唇以及增白,但这背后是如何实现的,你又了解多少呢?
AI美颜核心技术之一就是人脸关键点检测。PaddleHub已经开源了人脸关键点检测模型face_landmark_localization。人脸关键点检测是人脸识别和分析领域中的关键一步,它是诸如自动人脸识别、表情分析、三维人脸重建及三维动画等其它人脸相关问题的前提和突破口。该模型转换自 Github,支持同一张图中的多个人脸检测。它可以识别人脸中的68个关键点。
1、准备工作
(1)线上环境:百度AI Studio提供了线上一站式开发实训平台,直接可在该平台完成。
(2)本地实现:在本编译器中,需要提前安装PaddleHub库,pip安装即可,最好加上国内源。
pip install paddlehub==1.6.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
2、实现步骤
(1)人脸关键点检测
import cv2
import paddlehub as hub
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import mathsrc_img = cv2.imread('./test_sample.jpg')module = hub.Module(name="face_landmark_localization")
result = module.keypoint_detection(images=[src_img])tmp_img = src_img.copy()
for index, point in enumerate(result[0]['data'][0]):# cv2.putText(img, str(index), (int(point[0]), int(point[1])), cv2.FONT_HERSHEY_COMPLEX, 3, (0,0,255), -1)cv2.circle(tmp_img, (int(point[0]), int(point[1])), 2, (0, 0, 255), -1)res_img_path = 'face_landmark.jpg'
cv2.imwrite(res_img_path, tmp_img)img = mpimg.imread(res_img_path)
# 展示预测68个关键点结果
plt.figure(figsize=(10,10))
plt.imshow(img)
plt.axis('off')
plt.show()
可得出人脸的68个关键点图:
(2)瘦脸
利用识别到的68个关键点完成瘦脸功能。左右脸各瘦多少,可以根据图片和自己的满意度,改变参数 face_landmark[ ]。同时利用局部平移算法局部平移算法完成瘦脸.
import numpy as np
import math
'''1、瘦脸'''
def thin_face(image, face_landmark):"""实现自动人像瘦脸image: 人像图片face_landmark: 人脸关键点"""end_point = face_landmark[30]# 瘦左脸,3号点到5号点的距离作为瘦脸距离dist_left = np.linalg.norm(face_landmark[3] - face_landmark[5])image = local_traslation_warp(image, face_landmark[3], end_point, dist_left)# 瘦右脸,13号点到15号点的距离作为瘦脸距离dist_right = np.linalg.norm(face_landmark[13] - face_landmark[15])image = local_traslation_warp(image, face_landmark[13], end_point, dist_right)return imagedef local_traslation_warp(image, start_point, end_point, radius):"""局部平移算法"""radius_square = math.pow(radius, 2)image_cp = image.copy()dist_se = math.pow(np.linalg.norm(end_point - start_point), 2)height, width, channel = image.shapefor i in range(width):for j in range(height):# 计算该点是否在形变圆的范围之内# 优化,第一步,直接判断是会在(start_point[0], start_point[1])的矩阵框中if math.fabs(i - start_point[0]) > radius and math.fabs(j - start_point[1]) > radius:continuedistance = (i - start_point[0]) * (i - start_point[0]) + (j - start_point[1]) * (j - start_point[1])if (distance < radius_square):# 计算出(i,j)坐标的原坐标# 计算公式中右边平方号里的部分ratio = (radius_square - distance) / (radius_square - distance + dist_se)ratio = ratio * ratio# 映射原位置new_x = i - ratio * (end_point[0] - start_point[0])new_y = j - ratio * (end_point[1] - start_point[1])new_x = new_x if new_x >= 0 else 0new_x = new_x if new_x < height - 1 else height - 2new_y = new_y if new_y >= 0 else 0new_y = new_y if new_y < width - 1 else width - 2# 根据双线性插值法得到new_x, new_y的值image_cp[j, i] = bilinear_insert(image, new_x, new_y)return image_cpdef bilinear_insert(image, new_x, new_y):"""双线性插值法"""w, h, c = image.shapeif c == 3:x1 = int(new_x)x2 = x1 + 1y1 = int(new_y)y2 = y1 + 1part1 = image[y1, x1].astype(np.float) * (float(x2) - new_x) * (float(y2) - new_y)part2 = image[y1, x2].astype(np.float) * (new_x - float(x1)) * (float(y2) - new_y)part3 = image[y2, x1].astype(np.float) * (float(x2) - new_x) * (new_y - float(y1))part4 = image[y2, x2].astype(np.float) * (new_x - float(x1)) * (new_y - float(y1))insertValue = part1 + part2 + part3 + part4return insertValue.astype(np.int8)face_landmark = np.array(result[0]['data'][0], dtype='int')src_img = thin_face(src_img, face_landmark)res_img_path = 'res.jpg'
cv2.imwrite(res_img_path, src_img)img = mpimg.imread(res_img_path)
# 展示瘦脸图片
plt.figure(figsize=(10,10))
plt.imshow(img)
plt.axis('off')
plt.show()
瘦脸图片展示:
(3)大眼
完成瘦脸之后,我们还可以对人像中的眼睛进行放大。在识别到的左右眼中的一个位置,对其进行缩放(图像局部缩放算法),实现大眼。
'''2、大眼
完成瘦脸之后,我们还可以对人像中的眼睛进行放大。
在识别到的左右眼中的一个位置,对其进行缩放(图像局部缩放),实现大眼。'''
import math
import numpy as npdef enlarge_eyes(image, face_landmark, radius=15, strength=10):"""放大眼睛image: 人像图片face_landmark: 人脸关键点radius: 眼睛放大范围半径strength:眼睛放大程度"""# 以左眼最低点和最高点之间的中点为圆心left_eye_top = face_landmark[37]left_eye_bottom = face_landmark[41]left_eye_center = (left_eye_top + left_eye_bottom)/2# 以右眼最低点和最高点之间的中点为圆心right_eye_top = face_landmark[43]right_eye_bottom = face_landmark[47]right_eye_center = (right_eye_top + right_eye_bottom)/2# 放大双眼local_zoom_warp(image, left_eye_center, radius=radius, strength=strength)local_zoom_warp(image, right_eye_center, radius=radius, strength=strength)def local_zoom_warp(image, point, radius, strength):"""图像局部缩放算法"""height = image.shape[0]width = image.shape[1]left =int(point[0] - radius) if point[0] - radius >= 0 else 0top = int(point[1] - radius) if point[1] - radius >= 0 else 0right = int(point[0] + radius) if point[0] + radius < width else width-1bottom = int(point[1] + radius) if point[1] + radius < height else height-1radius_square = math.pow(radius, 2)for y in range(top, bottom):offset_y = y - point[1]for x in range(left, right):offset_x = x - point[0]dist_xy = offset_x * offset_x + offset_y * offset_yif dist_xy <= radius_square:scale = 1 - dist_xy / radius_squarescale = 1 - strength / 100 * scalenew_x = offset_x * scale + point[0]new_y = offset_y * scale + point[1]new_x = new_x if new_x >=0 else 0new_x = new_x if new_x < height-1 else height-2new_y = new_y if new_y >= 0 else 0new_y = new_y if new_y < width-1 else width-2image[y, x] = BilinearInsert(image, new_x, new_y)# 双线性插值法
def BilinearInsert(src, ux, uy):w, h, c = src.shapeif c == 3:x1 = int(ux)x2 = x1 + 1y1 = int(uy)y2 = y1 + 1part1 = src[y1, x1].astype(np.float) * (float(x2) - ux) * (float(y2) - uy)part2 = src[y1, x2].astype(np.float) * (ux - float(x1)) * (float(y2) - uy)part3 = src[y2, x1].astype(np.float) * (float(x2) - ux) * (uy - float(y1))part4 = src[y2, x2].astype(np.float) * (ux - float(x1)) * (uy - float(y1))insertValue = part1 + part2 + part3 + part4return insertValue.astype(np.int8)
'''在瘦脸的基础上,继续放大双眼'''
enlarge_eyes(src_img, face_landmark, radius=13, strength=13)
cv2.imwrite(res_img_path, src_img)
img = mpimg.imread(res_img_path)
plt.figure(figsize=(10, 10))
plt.imshow(img)
plt.axis('off')
plt.show()
大眼结果展示:
(4)红唇
目前已经叠加了瘦脸、大眼的美颜功能,我们还可以给人像增添气色,给人像画上红唇。我们只需将识别到的唇部位置给涂上红色即可达到相应的目的。
import cv2def rouge(image, face_landmark, ruby=True):"""自动涂口红image: 人像图片face_landmark: 人脸关键点ruby:是否需要深色口红"""image_cp = image.copy()if ruby:rouge_color = (0, 0, 255)else:rouge_color = (0, 0, 200)points = face_landmark[48:68]hull = cv2.convexHull(points)cv2.drawContours(image, [hull], -1, rouge_color, -1)cv2.addWeighted(image, 0.2, image_cp, 0.9, 0, image_cp)return image_cp
'''继续叠加红唇'''
src_img = rouge(src_img, face_landmark)
cv2.imwrite(res_img_path, src_img)
img = mpimg.imread(res_img_path)
plt.figure(figsize=(10, 10))
plt.imshow(img)
plt.axis('off')
plt.show()
红唇结果展示:
(5)美白
我们还可以加上美肤功能。由于标记出来的68个关键点没有涵盖额头的位置,我们需要预估额头位置。为了简单估计二头所在区域,本教程以0号、16号点所在线段为直径的半圆为额头位置。
import cv2
import numpy as npdef whitening(img, face_landmark):"""美白"""# 简单估计额头所在区域# 根据0号、16号点画出额头(以0号、16号点所在线段为直径的半圆)radius=(np.linalg.norm(face_landmark[0] - face_landmark[16]) / 2).astype('int32')center_abs=tuple(((face_landmark[0] + face_landmark[16]) / 2).astype('int32'))angle=np.degrees(np.arctan((lambda l:l[1]/l[0])(face_landmark[16]-face_landmark[0]))).astype('int32')face = np.zeros_like(img)cv2.ellipse(face,center_abs,(radius,radius),angle,180,360,(255,255,255),2)points=face_landmark[0:17]hull = cv2.convexHull(points)cv2.polylines(face, [hull], True, (255,255,255), 2)index = face >0face[index] = img[index]dst = np.zeros_like(face)# v1:磨皮程度v1 = 3# v2: 细节程度v2 = 2tmp1 = cv2.bilateralFilter(face, v1 * 5, v1 * 12.5, v1 * 12.5)tmp1 = cv2.subtract(tmp1,face)tmp1 = cv2.add(tmp1,(10,10,10,128))tmp1 = cv2.GaussianBlur(tmp1,(2*v2-1, 2*v2-1),0)tmp1 = cv2.add(img,tmp1)dst = cv2.addWeighted(img, 0.1, tmp1, 0.9, 0.0)dst = cv2.add(dst,(10, 10, 10,255))index = dst>0img[index] = dst[index]return img
'''美白'''src_img = whitening(src_img, face_landmark)cv2.imwrite(res_img_path, src_img)img = mpimg.imread(res_img_path)plt.figure(figsize=(10, 10))plt.imshow(img)plt.axis('off')plt.savefig('result_pic_test2.png')plt.show()
美白后的图片:
3、后续
经过前面几步,大体的美颜工作已经完成,同时我们可以在美白后的基础上继续一些处理,比如描眉、去痘等等。
同时,需要注意的是瘦脸时的,点一定要选好,不然图片中人脸会变形。
人脸美颜——飞桨PaddleHub实战相关推荐
- 一键人物抠图、人物图片背景替换——飞桨PaddleHub实战
PaddleHub一键抠图并替换背景 抠图模型千千万,而我就用DeepLabv3+.DeepLabv3+ 是Google DeepLab语义分割系列网络的最新作,其前作有 DeepLabv1,Deep ...
- 当飞桨PaddleHub遇到微信小程序,AI也能指物作诗
点击左上方蓝字关注我们 [飞桨开发者说]刘建建,飞桨开发者,现工作于西部某厂,从事管理工作. 项目构想 最近飞桨PaddleHub大火,吸引无数开发者眼球,作为俗人的我也不例外,被看图写诗和艺术风格迁 ...
- 飞桨PaddleHub实现皮影戏
飞桨(PaddlePaddle)是集深度学习核心框架.工具组件和服务平台为一体的技术先进.功能完备的开源深度学习平台,已被中国企业广泛使用,深度契合企业应用需求,拥有活跃的开发者社区生态.提供丰富的官 ...
- 使用飞桨PaddleHub实现将视频动作转化为皮影戏
前言 飞桨(PaddlePaddle)是集深度学习核心框架.工具组件和服务平台为一体的技术先进.功能完备的开源深度学习平台,已被中国企业广泛使用,深度契合企业应用需求,拥有活跃的开发者社区生态.提供丰 ...
- Linux系统 安装飞桨PaddleHub+LAC实现词法分析 实现加载自定义词典分词 (解决Lac服务启动报错问题、解决自定义词典空格无法分词问题)
1.先上链接:飞桨PaddlePaddle-源于产业实践的开源深度学习平台 2.LAC模型简介:Lexical Analysis of Chinese,简称 LAC,是一个联合的词法分析模型,能整体性 ...
- 超有范,使用飞桨paddleHub抠图制作任意形状的词云(学习心得)
文章目录 1 抠图代码 2 抠图效果 3 绘制词云图 4 词云效果图 5 项目链接 链接 1 抠图代码 # 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Als ...
- 双服务器架构实战飞桨部署-自动上色和老相片修复
双服务器架构实战飞桨部署-自动上色和老相片修复 宋 朱熹 <即事有怀寄彦辅仲宗二兄>诗之二:"闻说双飞桨,翩然下广津. 飞桨功能强大,部署非常简单方便(对我这个不熟练的人,并不是 ...
- 截屏就可以转文字?飞桨带您体验OCR超轻量中英文识别模型
[飞桨开发者说]陈千鹤,华中科技大学计算机科学与技术学院大一在读 任务背景 目前很多实用小工具都趋向收费模式,即使免费,不是功能不完整,就是有很多约束条件,在应用时效果无法达到我们的预期.于是我萌生一 ...
- “OpenI/O 2020启智开发者大会”共话开源,百度飞桨引领行业发展
点击左上方蓝字关注我们 2020年12月2日,"OpenI/O 2020启智开发者大会"在北京国家会议中心召开.大会以"启智筑梦 开源先行"为主题,立足于国际国 ...
最新文章
- cordova 学习笔记
- boost::graph::dimacs_basic_reader用法的测试程序
- P4294-[WC2008]游览计划【斯坦纳树】
- tms tck_在雅加达EE TCK中使用Arquillian的可能方法
- Jmeter 生成HTML性能测试报告
- java 对象流 乱码,JAVA 中的 IO 流
- 配置hive元数据到mysql后启动不了 java.sql.SQLException: Access denied for user ‘root‘@‘hd101‘ (using password:
- yapi接口管理工具
- java实现日期转中文大写形式
- 2db多少功率_功率换算(dB与W).doc
- python中正则表达式与jieba分词的使用
- xinxin--小爱同学
- 视频教程-Excel玩转财务管理-Office/WPS
- 软件开发中的需求分析
- mysql 安装启动服务器一直失败_mysql安装后服务器启动失败的几种解决办法
- 软件测试是要学习什么技能?
- 上海无印良品地理空间分布特征与选址策略可视化研究
- matlab中nnt,基于MATLAB的边坡稳定性评价方法
- 注意力不集中是因为你没有紧迫感
- 『C语言』题集 of ⑩