這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

美顏和短視頻
美顏相關APP可以說是現在手機上的必備的軟體,例如抖音,快手,拍出的“照騙”和視頻不加美顏效果,估計沒有人敢傳到網上,很多人一直好奇美顏類APP是如何開發出來的,本文就大致講一下在Android上如何實作實時修改唇色效果,其它功能例如美白,腮紅都是類似的原理
下圖的唇色修改效果就是想實作的功能
美顏原理
美顏是的基本原理就是深度學習加計算機圖形學,深度學習用來人臉檢測和人臉關鍵點檢測,計算機圖形學用來磨皮,瘦臉和畫妝容,一般在Android上使用OpenGLES,IOS為Metal,由于計算機圖形學概念較多和復雜,本文中用Android的Canvas替代,
人臉檢測 & 人臉關鍵點
- 人臉檢測指的是對圖片或者視頻流中的人臉進行檢測,并定位到圖片中的人臉,
- 人臉關鍵點檢測是對人臉中五官和臉的輪廓進行關鍵點定位,一般情況下它緊接在人臉檢測后,
我們將使用TengineKit來實作實時大紅唇效果,
TengineKit
免費移動端實時人臉212關鍵點SDK,是一個易于集成的人臉檢測和人臉關鍵點SDK,它可以在各種手機上以非常低的延遲運行,
github.com/OAID/Tengin…
實作口紅效果
配置 Gradle
Project中的build.gradle添加
repositories {
...
mavenCentral()
...
}
allprojects {
repositories {
...
mavenCentral()
...
}
}
主Module中的build.gradle添加
dependencies {
...
implementation 'com.tengine.android:tenginekit:1.0.5'
...
}
配置 manifests
<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人臉實時打碼 zhuanlan.zhihu.com/p/161038093
處理Gif傳過來的圖片流
首先我們先初始化TengineKit:
- 選用normal處理模式
- 打開人臉檢測和人臉關鍵點功能
- 設定圖片流格式為RGBA
- 設定輸入圖片流的寬高,此處為gif圖的預覽寬高
- 設定輸出圖片流的寬高,此處為GifImageView的寬高,此處和gif一致,所以用gif圖的寬高代替
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);
}
此代碼來源于 github.com/DingProg/Ma…
渲染
傳過來的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 != null){
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://juejin.cn/post/6855129006367309832
如果對您有所幫助,歡迎您點個關注,我會定時更新技術檔案,大家一起討論學習,一起進步,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/539027.html
標籤:其他
