Beauty and short videos

Beauty-related apps can be said to be essential software on mobile phones, such as Douyin and Kuaishou. No one will dare to upload the “photo fraud” and videos without beauty-related effects. Many people have been curious about how the beauty APP was developed. This article is about how to change lip color in real time on Android. Other functions such as whitening and blush are based on similar principles

The following lip color modification effect is to achieve the function

Beauty principle

The fundamentals of beauty are deep learning plus computer graphics. Deep learning is used for face detection and key point detection. Computer graphics are used to polish skin, thin faces and apply makeup. Generally, OpenGLES is used on Android and Metal is used on IOS. Due to the many and complex concepts of computer graphics, Canvas of Android is used instead in this paper.

Face detection & face key points

  1. Face detection refers to the detection of the face in the picture or video stream, and locate the face in the picture.
  2. Face key point detection is the key point positioning of the facial features and the contour of the face, in general, it is immediately after the face detection.

We will use TengineKit to achieve real-time big red lip effect.

TengineKit

Free mobile terminal real-time face 212 keypoints SDK. Is an easy to integrate face detection and face keypoint SDK. It can run on a variety of phones with very low latency.

Github.com/OAID/Tengin…

Achieve lipstick effect

Configuration Gradle

Build. Gradle in Project

repositories { ... mavenCentral() ... } allprojects { repositories { ... mavenCentral() ... }}Copy the code

Build. gradle added to main Module

    dependencies {
        ...
        implementation 'com. Tengine. Android: tenginekit: 1.0.5'. }Copy the code

Configuration 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"/>
Copy the code

Compared with the previous part using the camera for effect, this paper uses GIF images to replace the video stream input by the camera. If you want to use the camera for implementation, please refer to:

With open source 212 face key code zhuanlan.zhihu.com/p/161038093 Android human face in real-time

Process the image stream from Gif

First we initialize TengineKit:

  1. The normal processing mode is selected
  2. Open face detection and face key point functions
  3. Set the image stream format to RGBA
  4. Set the width and height of the input image stream. Here is the preview width and height of the GIF image
  5. Set the width and height of the output picture stream. Here is the width and height of GifImageView, which is the same as GIF, so the width and height of GIF is used instead
    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())
    );
Copy the code

Get the shape of the lips from the key points

    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;
    }
Copy the code

Color your lips

    public static void drawLipPerfect(Canvas canvas, Path lipPath, int color, int alpha) {
        //most 70% alpha
        if (alpha > 80) {
            alpha = (int) (alpha * 0.9 f + 0.5 f);
        }

        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);
    }
Copy the code

This code comes from github.com/DingProg/Ma…

Apply colours to a drawing

The bitmap sent is RGB_565 and needs to be converted to the standard RGBA format

    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); }}}returnout_bitmap; }});Copy the code

Effect of contrast

advice

If you are interested, you can build on the current project. A lot of the code in this article also comes from this

Github.com/DingProg/Ma…

Further want to try commercial grade beauty effect can refer to

Github.com/CainKernel/…

reference

Github.com/OAID/Tengin…

Github.com/DingProg/Ma…

Github.com/felipecsl/G…

The source code

Github.com/jiangzhongb…