Как с помощью HUAWEI ML Kit интегрировать в приложения стикеры с изображением лица

от автора

Общая информация

Сейчас мы повсюду видим милые и смешные стикеры с изображением лица. Они используются не только в приложениях для камер, но и в социальных сетях и развлекательных приложениях. В этой статье я покажу вам, как создать 2D-стикеры с помощью инструмента HUAWEI ML Kit. Скоро мы также расскажем о процессе разработки 3D-стикеров, так что следите за обновлениями!

Сценарии

Приложения для съемки и редактирования фотографий, такие как селфи-камеры и социальные сети (TikTok, Weibo, WeChat и др.), часто предлагают набор стикеров для настройки изображений. С помощью этих стикеров пользователи могут создавать привлекательный и яркий контент и делиться им.

Подготовка

Добавьте репозиторий Maven Huawei в файл на уровне проекта build.gradle

Откройте файл build.gradle в корневом каталоге вашего проекта Android Studio.
image
Добавьте адрес репозитория Maven.

buildscript {     {               maven {url 'http://developer.huawei.com/repo/'}   }     } allprojects {   repositories {              maven { url 'http://developer.huawei.com/repo/'}   } } 

Добавьте зависимости SDK в файл на уровне приложения build.gradle

image

// Face detection SDK. implementation 'com.huawei.hms:ml-computer-vision-face:2.0.1.300' // Face detection model. implementation 'com.huawei.hms:ml-computer-vision-face-shape-point-model:2.0.1.300' 

Запросите права доступа к камере, сети и памяти в файле AndroidManifest.xml

<!--Camera permission-->  <uses-feature android:name="android.hardware.camera" /> <uses-permission android:name="android.permission.CAMERA" /> <!--Write permission-->  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!--Read permission-->  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 

Разработка кода

Настройте анализатор лица

MLFaceAnalyzerSetting detectorOptions; detectorOptions = new MLFaceAnalyzerSetting.Factory()       .setFeatureType(MLFaceAnalyzerSetting.TYPE_UNSUPPORT_FEATURES)       .setShapeType(MLFaceAnalyzerSetting.TYPE_SHAPES)       .allowTracing(MLFaceAnalyzerSetting.MODE_TRACING_FAST)       .create(); detector = MLAnalyzerFactory.getInstance().getFaceAnalyzer(detectorOptions); 

Получите точки контура лица и передайте их в FacePointEngine

С помощью обратного вызова камеры получите данные камеры, а затем вызовите анализатор лица, чтобы получить точки контура лица, и передайте эти точки в FacePointEngine. Фильтр стикеров сможет использовать их позже.

@Override public void onPreviewFrame(final byte[] imgData, final Camera camera) {   int width = mPreviewWidth;   int height = mPreviewHeight;    long startTime = System.currentTimeMillis();   // Set the shooting directions of the front and rear cameras to be the same.   if (isFrontCamera()){       mOrientation = 0;   }else {       mOrientation = 2;   }   MLFrame.Property property =           new MLFrame.Property.Creator()                   .setFormatType(ImageFormat.NV21)                   .setWidth(width)                   .setHeight(height)                   .setQuadrant(mOrientation)                   .create();    ByteBuffer data = ByteBuffer.wrap(imgData);   // Call the face analyzer API.   SparseArray<MLFace> faces = detector.analyseFrame(MLFrame.fromByteBuffer(data,property));   // Determine whether face information is obtained.   if(faces.size()>0){       MLFace mLFace = faces.get(0);       EGLFace EGLFace = FacePointEngine.getInstance().getOneFace(0);       EGLFace.pitch = mLFace.getRotationAngleX();       EGLFace.yaw = mLFace.getRotationAngleY();       EGLFace.roll = mLFace.getRotationAngleZ() - 90;       if (isFrontCamera())           EGLFace.roll = -EGLFace.roll;       if (EGLFace.vertexPoints == null) {           EGLFace.vertexPoints = new PointF[131];       }       int index = 0;       // Obtain the coordinates of a user's face contour points and convert them to the floating point numbers in normalized coordinate system of OpenGL.       for (MLFaceShape contour : mLFace.getFaceShapeList()) {           if (contour == null) {               continue;           }           List<MLPosition> points = contour.getPoints();            for (int i = 0; i < points.size(); i++) {               MLPosition point = points.get(i);               float x = ( point.getY() / height) * 2 - 1;               float y = ( point.getX() / width ) * 2 - 1;               if (isFrontCamera())                   x = -x;               PointF Point = new PointF(x,y);               EGLFace.vertexPoints[index] = Point;               index++;           }       }       // Insert a face object.       FacePointEngine.getInstance().putOneFace(0, EGLFace);       // Set the number of faces.       FacePointEngine.getInstance().setFaceSize(faces!= null ? faces.size() : 0);   }else{       FacePointEngine.getInstance().clearAll();   }   long endTime = System.currentTimeMillis();   Log.d("TAG","Face detect time: " + String.valueOf(endTime - startTime)); } 

На изображении ниже показано, как точки контура лица возвращаются с помощью API ML Kit.
image

Определение данных стикера в формате JSON

public class FaceStickerJson {    public int[] centerIndexList;   // Center coordinate index list. If the list contains multiple indexes, these indexes are used to calculate the central point.   public float offsetX;           // X-axis offset relative to the center coordinate of the sticker, in pixels.   public float offsetY;           // Y-axis offset relative to the center coordinate of the sticker, in pixels.   public float baseScale;         // Base scale factor of the sticker.   public int startIndex;         // Face start index, which is used for computing the face width.   public int endIndex;           // Face end index, which is used for computing the face width.   public int width;               // Sticker width.   public int height;             // Sticker height.   public int frames;             // Number of sticker frames.   public int action;             // Action. 0 indicates default display. This is used for processing the sticker action.   public String stickerName;     // Sticker name, which is used for marking the folder or PNG file path.   public int duration;           // Sticker frame displays interval.   public boolean stickerLooping; // Indicates whether to perform rendering in loops for the sticker.   public int maxCount;           // Maximum number of rendering times. ... } 

Сделайте стикер с изображением кота

Создайте файл JSON для стикера с изображением кота и определите центральную точку между бровями (84) и кончиком носа (85) с помощью индекса лица. Вставьте уши и нос кота, а затем поместите файл JSON и изображение в папку assets.

{   "stickerList": [{       "type": "sticker",       "centerIndexList": [84],       "offsetX": 0.0,       "offsetY": 0.0,       "baseScale": 1.3024,       "startIndex": 11,       "endIndex": 28,       "width": 495,       "height": 120,       "frames": 2,       "action": 0,       "stickerName": "nose",       "duration": 100,       "stickerLooping": 1,       "maxcount": 5   }, {       "type": "sticker",       "centerIndexList": [83],       "offsetX": 0.0,       "offsetY": -1.1834,       "baseScale": 1.3453,       "startIndex": 11,       "endIndex": 28,       "width": 454,       "height": 150,       "frames": 2,       "action": 0,       "stickerName": "ear",       "duration": 100,       "stickerLooping": 1,       "maxcount": 5   }] } 

Рендеринг стикера в текстуру

Мы выполняем рендеринг стикера в текстуру с помощью класса GLSurfaceView — он проще, чем TextureView. Создайте экземпляр фильтра стикеров в onSurfaceChanged, передайте путь стикера и запустите камеру.

@Override public void onSurfaceCreated(GL10 gl, EGLConfig config) {    GLES30.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);   mTextures = new int[1];   mTextures[0] = OpenGLUtils.createOESTexture();   mSurfaceTexture = new SurfaceTexture(mTextures[0]);   mSurfaceTexture.setOnFrameAvailableListener(this);    // Pass the samplerExternalOES into the texture.   cameraFilter = new CameraFilter(this.context);    // Set the face sticker path in the assets directory.   String folderPath ="cat";   stickerFilter = new FaceStickerFilter(this.context,folderPath);    // Create a screen filter object.   screenFilter = new BaseFilter(this.context);    facePointsFilter = new FacePointsFilter(this.context);   mEGLCamera.openCamera(); } 

Инициализируйте фильтр стикеров в onSurfaceChanged

@Override public void onSurfaceChanged(GL10 gl, int width, int height) {   Log.d(TAG, "onSurfaceChanged. width: " + width + ", height: " + height);   int previewWidth = mEGLCamera.getPreviewWidth();   int previewHeight = mEGLCamera.getPreviewHeight();   if (width > height) {       setAspectRatio(previewWidth, previewHeight);   } else {       setAspectRatio(previewHeight, previewWidth);   }   // Set the image size, create a FrameBuffer, and set the display size.   cameraFilter.onInputSizeChanged(previewWidth, previewHeight);   cameraFilter.initFrameBuffer(previewWidth, previewHeight);   cameraFilter.onDisplaySizeChanged(width, height);    stickerFilter.onInputSizeChanged(previewHeight, previewWidth);   stickerFilter.initFrameBuffer(previewHeight, previewWidth);   stickerFilter.onDisplaySizeChanged(width, height);    screenFilter.onInputSizeChanged(previewWidth, previewHeight);   screenFilter.initFrameBuffer(previewWidth, previewHeight);   screenFilter.onDisplaySizeChanged(width, height);    facePointsFilter.onInputSizeChanged(previewHeight, previewWidth);   facePointsFilter.onDisplaySizeChanged(width, height);   mEGLCamera.startPreview(mSurfaceTexture); } 

Нарисуйте на экране стикер с помощью onDrawFrame

@Override public void onDrawFrame(GL10 gl) {   int textureId;   // Clear the screen and depth buffer.   GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT);   // Update a texture image.   mSurfaceTexture.updateTexImage();   // Obtain the SurfaceTexture transform matrix.    mSurfaceTexture.getTransformMatrix(mMatrix);   // Set the camera display transform matrix.   cameraFilter.setTextureTransformMatrix(mMatrix);    // Draw the camera texture.   textureId = cameraFilter.drawFrameBuffer(mTextures[0],mVertexBuffer,mTextureBuffer);   // Draw the sticker texture.   textureId = stickerFilter.drawFrameBuffer(textureId,mVertexBuffer,mTextureBuffer);   // Draw on the screen.   screenFilter.drawFrame(textureId , mDisplayVertexBuffer, mDisplayTextureBuffer);   if(drawFacePoints){       facePointsFilter.drawFrame(textureId, mDisplayVertexBuffer, mDisplayTextureBuffer);   } } 

Получилось! Ваш стикер с изображением лица готов.
Давайте проверим его в действии!
image
Для получения подробной информации перейдите на наш официальный сайт.
Вы также можете посмотреть пример кода.

ссылка на оригинал статьи https://habr.com/ru/post/516032/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *