Comment intégrer des autocollants faciaux dans des applications avec HUAWEI ML Kit

informations générales



De nos jours, nous voyons des autocollants de visage mignons et drôles partout. Ils sont utilisés non seulement dans les applications de caméra, mais également dans les applications de médias sociaux et de divertissement. Dans cet article, je vais vous montrer comment créer des autocollants 2D à l'aide de l'outil HUAWEI ML Kit. Nous couvrirons également bientôt le processus de développement de l'autocollant 3D, alors restez à l'écoute!



Les scripts



Les applications de capture et d'édition de photos telles que les caméras selfie et les réseaux sociaux (TikTok, Weibo, WeChat, etc.) proposent souvent un ensemble d'autocollants pour personnaliser les images. Avec ces autocollants, les utilisateurs peuvent créer et partager du contenu attrayant et dynamique.



Entraînement



Ajouter le référentiel Maven Huawei au fichier de niveau projet build.gradle



Ouvrez le fichier build.gradle dans le répertoire racine de votre projet Android Studio .



image



Ajoutez l'adresse du référentiel Maven.



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


Ajouter des dépendances du SDK au fichier au niveau de l'application 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'


Demander des autorisations pour la caméra, le réseau et la mémoire dans le fichier 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" />


Développement de code



Configurez votre analyseur de visage



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);


Obtenez des points de contour du visage et transmettez-les à FacePointEngine



Utilisez le rappel de la caméra pour obtenir les données de la caméra, puis appelez l'analyseur de visage pour obtenir les points de contour du visage et transmettre ces points à FacePointEngine . Le filtre autocollant pourra les utiliser plus tard.



@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));
}


L'image ci-dessous montre comment les points de contour du visage sont renvoyés à l'aide de l'API ML Kit.



image



Définition des données d'autocollants au format 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.
...
}


Faire un autocollant avec une photo d'un chat



Créez un fichier JSON pour l'autocollant de chat et définissez le point central entre les sourcils (84) et le bout du nez (85) à l'aide de l'index du visage. Collez les oreilles et le nez du chat, puis placez le fichier JSON et l'image dans le dossier des ressources .



{
  "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
  }]
}


Rendu d'un autocollant sur une texture



Nous rendons l'autocollant en une texture à l'aide de la classe GLSurfaceView - c'est plus simple que TextureView . Instanciez le filtre autocollant dans onSurfaceChanged , passez le chemin de l'autocollant et démarrez la caméra.



@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();
}


Initialisez le filtre d'autocollants sur 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);
}


Dessinez un autocollant sur l'écran en utilisant 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);
  }
}


Arrivé! Votre autocollant de visage est prêt.



Voyons-le en action!



image



Veuillez visiter notre site officiel pour plus de détails .

Vous pouvez également consulter l' exemple de code .



All Articles