blog

Jitterbug APPワイド目の特殊効果のオープンソースの実装は、お嬢様の甘い部門は、個人的に効果のデモを行う

ワイドアイ効果\n\nデカ目効果の原理\nアイ・エフェクトの原理は、AIとコンピューター・グラフィックスを組み合わせたビューティー・エフェクトの原理と似ています。\nビューティーの基本原理は、ディープ...

Oct 10, 2020 · 6 min. read
シェア

ワイドアイ効果

ワイドアイ効果の原理

広い目の美しさの特殊効果の原理はほとんど同じですが、AIとCGの組み合わせです。

美の基本原理は、ディープラーニングとCGです。ディープラーニングは顔検出と顔キーポイント検出に使用されます。コンピュータグラフィックスは、皮膚剥離、顔の間引き、化粧塗りなどに使用します。一般的にAndroidではOpenGLES、IOSではMetalが使用されています。

AIから全体のプロセスの美しさを説明するために、学生のソースコードを参照してくださいに直接最後まで引っ張ることができ、それは基本的に同じであることを、ジッタリ声の美しさの効果のオープンソースの実装を見てきました!

顔検出&顔のキーポイント

  1. 顔検出は、写真やビデオストリーム内の顔の検出を指し、イメージ内の顔を検索します。
  2. 通常の処理モードを選択
TengineKitは、大きな目の効果を実装するために使用されます。

TengineKit

Free Mobile Real-Time Face 212 Keypoint SDK.は、簡単に統合できる顔検出と顔キーポイントSDKです。

github.com/Tengin...

TengineKit

口紅効果

Gradleの設定

プロジェクトのBuild.gradleに

 repositories {
 ...
 mavenCentral()
 ...
 }
 allprojects {
 repositories {
 ...
 mavenCentral()
 ...
 }
 }

メインモジュールに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 から渡されるイメージのストリームを処理します。

まずはTengineKitの初期化から始めましょう。

  1. 通常の処理モードを選択します。
  2. 顔検出と顔キーポイント機能をオンにします。
  3. イメージストリームのフォーマットをRGBAに設定します。
  4. 入力イメージストリームの幅と高さを設定します。ここではgifイメージのプレビュー幅と高さを設定しています。
  5. 出力イメージストリームの幅を設定します。ここでは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())
 );

キーポイントから目の中心を取得します。

 Point getLeftEyeCenter(FaceLandmarkInfo fi){
 FaceLandmarkPoint p1 = fi.landmarks.get(105);
 FaceLandmarkPoint p2 = fi.landmarks.get(113);
 return new Point((int)((p1.X + p2.X) / 2), (int)((p1.Y + p2.Y) / 2));
 }
 Point getRightEyeCenter(FaceLandmarkInfo fi){
 FaceLandmarkPoint p1 = fi.landmarks.get(121);
 FaceLandmarkPoint p2 = fi.landmarks.get(129);
 return new Point((int)((p1.X + p2.X) / 2), (int)((p1.Y + p2.Y) / 2));
 }

目の拡大アルゴリズム

public class MagnifyEyeUtils {
 /**
 * 目の拡大アルゴリズム
 * @param bitmap 元のビットマップ
 * @param centerPoint 中心点を拡大する
 * @param radius ズーム半径
 * @param sizeLevel 拡大[0,4]
 * @return 目を拡大した後のイメージ
 */
 public static Bitmap magnifyEye(Bitmap bitmap, Point centerPoint, int radius, float sizeLevel) {
 Bitmap dstBitmap = bitmap.copy(Bitmap.Config.RGB_565, true);
 int left = centerPoint.x - radius < 0 ? 0 : centerPoint.x - radius;
 int top = centerPoint.y - radius < 0 ? 0 : centerPoint.y - radius;
 int right = centerPoint.x + radius > bitmap.getWidth() ? bitmap.getWidth() - 1 : centerPoint.x + radius;
 int bottom = centerPoint.y + radius > bitmap.getHeight() ? bitmap.getHeight() - 1 : centerPoint.y + radius;
 int powRadius = radius * radius;
 int offsetX, offsetY, powDistance, powOffsetX, powOffsetY;
 int disX, disY;
 //数値が負の場合、結果は縮小される。
 float strength = (5 + sizeLevel * 2) / 10;
 for (int i = top; i <= bottom; i++) {
 offsetY = i - centerPoint.y;
 for (int j = left; j <= right; j++) {
 offsetX = j - centerPoint.x;
 powOffsetX = offsetX * offsetX;
 powOffsetY = offsetY * offsetY;
 powDistance = powOffsetX + powOffsetY;
 if (powDistance <= powRadius) {
 double distance = Math.sqrt(powDistance);
 double sinA = offsetX / distance;
 double cosA = offsetY / distance;
 double scaleFactor = distance / radius - 1;
 scaleFactor = (1 - scaleFactor * scaleFactor * (distance / radius) * strength);
 distance = distance * scaleFactor;
 disY = (int) (distance * cosA + centerPoint.y + 0.5);
 disY = checkY(disY, bitmap);
 disX = (int) (distance * sinA + centerPoint.x + 0.5);
 disX = checkX(disX, bitmap);
 //中心点をそのままにする
 if (!(j == centerPoint.x && i == centerPoint.y)) {
 dstBitmap.setPixel(j, i, bitmap.getPixel(disX, disY));
 //dstBitmap.setPixel(j, i, Color.WHITE);
 }
 }
 }
 }
 return dstBitmap;
 }
 private static int checkY(int disY, Bitmap bitmap) {
 if (disY < 0) {
 disY = 0;
 } else if (disY >= bitmap.getHeight()) {
 disY = bitmap.getHeight() - 1;
 }
 return disY;
 }
 private static int checkX(int disX, Bitmap bitmap) {
 if (disX < 0) {
 disX = 0;
 } else if (disX >= bitmap.getWidth()) {
 disX = bitmap.getWidth() - 1;
 }
 return disX;
 }
}

このコードは github.com/Ma...

レンダリング

渡されたビットマップは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++) {
 FaceLandmarkInfo fi = faceLandmarks.get(i);
 out_bitmap = MagnifyEyeUtils.magnifyEye(out_bitmap, getLeftEyeCenter(fi), 40, 4);
 out_bitmap = MagnifyEyeUtils.magnifyEye(out_bitmap, getRightEyeCenter(fi), 40, 4);
 }
 }
 }
 return out_bitmap;
 }
 });

比較

提案

  1. TengineKit - 無料、高速、簡単、モバイルでのリアルタイム顔検出&FaceLandmark SDK。

  2. Makeup - "女神 "を反逆者に、メイクアップをコード化しましょう!

  3. CainCamera - CainCamera は美容カメラ、イメージ、ショートビデオの開発について学ぶための Android プロジェクトです。

ソースコード

github.com/jiangzhongb...

Read next

ACM-ICPC分割法の基本アルゴリズム

分割統治」の文字通りの解釈は、複雑な問題を2つ以上の同一または類似の部分問題に分割し、最終的な部分問題が単純かつ直接的に解けるようになるまで、その部分問題をより小さな部分問題に分割することです!

Oct 10, 2020 · 3 min read