
美颜相关 APP 可以说是现在手机上的必备的软件,例如抖音,快手,拍出的“照骗”和视频不加美颜效果,估计没有人敢传到网上。很多人一直好奇美颜类 APP 是如何开发出来的。本文就大致讲一下在 Android 上如何实现实时修改唇色效果。
下图的红唇效果就是想实现的功能

美颜是的基本原理就是深度学习加计算机图形学。深度学习用来人脸检测和人脸关键点检测。计算机图形学用来磨皮,瘦脸和画妆容。一般在 Android 上使用 OpenGLES,IOS 为 Metal 。由于计算机图形学概念较多和复杂,本文中用 Android 的 Canvas 替代。

我们将使用 TengineKit 来实现实时大红唇效果。
免费移动端实时人脸 212 关键点 SDK 。是一个易于集成的人脸检测和人脸关键点 SDK 。它可以在各种手机上以非常低的延迟运行。
https://github.com/OAID/TengineKit

Project 中的 build.gradle 添加
repositories { ... mavenCentral() ... } allprojects { repositories { ... mavenCentral() ... } } 主 Module 中的 build.gradle 添加
dependencies { ... implementation 'com.tengine.android:tenginekit:1.0.5' ... } <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> 相对于上篇用摄像头来做效果,本文用 gif 图来代替摄像头的输入的视频流,如果想用摄像头实现,可以参考:
用开源 212 点人脸关键点实现 Android 人脸实时打码 https://zhuanlan.zhihu.com/p/161038093
首先我们先初始化 TengineKit:
com.tenginekit.Face.init(getBaseContext(), AndroidConfig.create() .setNormalMode() .openFunc(AndroidConfig.Func.Detect) .openFunc(AndroidConfig.Func.Landmark) .setInputImageFormat(AndroidConfig.ImageFormat.RGBA) .setInputImageSize(facingGif.getGifWidth(), facingGif.getGifHeight()) .setOutputImageSize(facingGif.getGifWidth(), facingGif.getGifHeight()) ); Path getMouthLandmarks(FaceLandmarkInfo fi){ Path outPath = new Path(); outPath.moveTo(fi.landmarks.get(180).X,fi.landmarks.get(180).Y); for(int i = 180; i < 189; i++){ outPath.lineTo( fi.landmarks.get(i).X, fi.landmarks.get(i).Y ); } for(int i = 204; i >= 196; i--){ outPath.lineTo( fi.landmarks.get(i).X, fi.landmarks.get(i).Y ); } outPath.close(); Path inPath = new Path(); inPath.moveTo(fi.landmarks.get(180).X,fi.landmarks.get(180).Y); for(int i = 195; i >= 188; i--){ inPath.lineTo( fi.landmarks.get(i).X, fi.landmarks.get(i).Y ); } for(int i = 204; i <= 211; i++){ inPath.lineTo( fi.landmarks.get(i).X, fi.landmarks.get(i).Y ); } outPath.op(inPath, Path.Op.DIFFERENCE); return outPath; } public static void drawLipPerfect(Canvas canvas, Path lipPath, int color, int alpha) { //most 70% alpha if (alpha > 80) { alpha = (int) (alpha * 0.9f + 0.5f); } alpha = (int) (Color.alpha(color) * ((float) alpha / 255)) << 24; color = alphaColor(color, alpha); final PointF position = new PointF(); float blur_radius = 5; Bitmap mask = createMask(lipPath, color, blur_radius, position); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER)); canvas.drawBitmap(mask, position.x, position.y, paint); } 此代码来源于 https://github.com/DingProg/Makeup
传过来的 bitmap 为 RGB_565,需要转为标准的 RGBA 格式
facingGif.setOnFrameAvailable(new GifImageView.OnFrameAvailable() { @Override public Bitmap onFrameAvailable(Bitmap bitmap) { // bitmap RGB_565 Bitmap out_bitmap = Bitmap.createBitmap( facingGif.getGifWidth(), facingGif.getGifHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(out_bitmap); canvas.drawBitmap(bitmap, 0, 0, null); bitmap.recycle(); byte[] bytes = bitmap2Bytes(out_bitmap); Face.FaceDetect faceDetect = com.tenginekit.Face.detect(bytes); if(faceDetect.getFaceCount() > 0){ faceLandmarks = faceDetect.landmark2d(); if(faceLandmarks != nul){ for (int i = 0; i < faceLandmarks.size(); i++) { Path m_p = getMouthLandmarks(faceLandmarks.get(i)); LipDraw.drawLipPerfect(canvas, m_p, Color.WHITE, 100); } } } return out_bitmap; } });

有兴趣的同学可以在当前项目的基础上面深化,具体可以参考
https://github.com/DingProg/Makeup
更进一步想尝试商业级的美颜效果可以参考
https://github.com/CainKernel/CainCamera
https://github.com/jiangzhongbo/TengineKit_Demo_Face_Beauty
https://zhuanlan.zhihu.com/p/163604590
1 KalaSearch 2020 年 7 月 27 日 做得挺棒的,感谢 lz 分享 这个 gif 选得也好 :D |
2 96412hj 2020 年 7 月 27 日 美颜和人脸识别技术是不是有点类似? |
3 exmorning OP @KalaSearch ;-) |
5 dying4death 2020 年 7 月 27 日 男人看的颜值和女人看的颜值什么意思 |
6 exmorning OP @dying4death 男性审美和女性审美不一样,所以打分也不一致,不过这个算法做的有问题,作为附带功能带上去 |
7 glumess 2020 年 7 月 27 日 大佬优秀,感谢分享,请问文章可以在公众号 《音视频开发进阶》中进行转载吗? |
9 Veneris 2020 年 7 月 27 日 感谢分享,蛮清晰的文章。 |
11 rayhy 2020 年 7 月 28 日 via Android 请问楼主,这些算法在桌面端或者 Web 端实现有什么辅助用的基础库吗?就是不太想从底层写起,比 opencv 再高一个层次的。 |
13 dream4ever 2020 年 7 月 28 日 这个妹子不错,哈哈 |
14 exmorning OP @dream4ever 欢迎骚扰~ |
15 dream4ever 2020 年 7 月 29 日 @exmorning 咦,莫非你就是动图里的妹子? |
16 AmberJiang 2020 年 7 月 31 日 via iPad 卧槽 一开始看这妹子 我还以为是王鸥 |
17 duanxiaoyu 2020 年 8 月 10 日 学会了,去哪找妹子来测试 |
18 firefox12 2020 年 8 月 11 日 大佬牛逼, 但是如果我现在想从零开始 实现这些 该如何入门,目前 你描述的 只不过是 用个库 调调 api,没有核心技术。 |
19 firefox12 2020 年 8 月 11 日 还有你的简书都挂了, 能不能把文章放到 github 上? |