DEV Community

ShuGang Zhou
ShuGang Zhou

Posted on • Edited on

05-HarmonyOS5-FaceComparator-Case

Case Description

This is a face comparison case implemented based on AI basic vision services. By selecting two images from the device's photo album, it performs face feature comparison and displays the similarity calculation result.

Implementation Steps:

1. Module Import

// Import functional modules
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { fileIo } from '@kit.CoreFileKit';
import { image } from '@kit.ImageKit';
import { faceComparator } from '@kit.CoreVisionKit';
import { promptAction } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
Enter fullscreen mode Exit fullscreen mode

2. Dual-Image Selection Function

// Create a common image selection method
async chooseImage (): Promise<PixelMap> {
  const photoPicker = new photoAccessHelper.PhotoViewPicker();
  const photoResult = await photoPicker.select({
    MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
    maxSelectNumber: 1
  })
  // Get the file handle of the selected image
  const fileSource = await fileIo.open(photoResult.photoUris[0], fileIo.OpenMode.READ_ONLY);
  // Generate pixel map format data
  return await image.createImageSource(fileSource.fd).createPixelMap();
}
Enter fullscreen mode Exit fullscreen mode

3. Image Processing Flow

// Define dual-image storage variables
@Local chooseImage1?: PixelMap
@Local chooseImage2?: PixelMap

// Image click processing logic
.onClick(async () => {
  const chooseImage = await this.chooseImage()
  this.chooseImage1 = chooseImage // Store the first image
})

.onClick(async () => {
  const chooseImage = await this.chooseImage()
  this.chooseImage2 = chooseImage // Store the second image
})
Enter fullscreen mode Exit fullscreen mode

4. Core Implementation of Face Comparison

// Configure dual-image comparison parameters
let visionInfo: faceComparator.VisionInfo = {
  pixelMap: this.chooseImage1,
};

let visionInfo1: faceComparator.VisionInfo = {
  pixelMap: this.chooseImage2,
};

// Perform face feature comparison
faceComparator.compareFaces(visionInfo, visionInfo1)
  .then(result => {
    // Show the similarity result in a dialog
    promptAction.showDialog({ message: JSON.stringify(result) })
  })
  .catch((e: BusinessError) => {
    // Show error information
    promptAction.showToast({ message: e.message })
  })
Enter fullscreen mode Exit fullscreen mode

5. Display of Detection Results

// Show the structured comparison result in a dialog
promptAction.showDialog({
  message: JSON.stringify({
    similarity: 0.92, // Example similarity value
    isSamePerson: true // Whether it's the same person
  })
})
Enter fullscreen mode Exit fullscreen mode

Implementation Code:

1. UI Component Definition

@Entry
@ComponentV2
struct FaceComparator {
  @Local chooseImage1?: PixelMap
  @Local chooseImage2?: PixelMap
Enter fullscreen mode Exit fullscreen mode

2. Main Function Method

// Integrate the complete logic of dual-image selection and feature comparison
async chooseImage(): Promise<PixelMap> {
  // Complete selection logic...
}
Enter fullscreen mode Exit fullscreen mode

3. Interface Construction

build() {
  Column({ space: 20 }) {
    Image(this.chooseImage1)
      .onClick(/* Select the first image */)
    Image(this.chooseImage2)
      .onClick(/* Select the second image */)
    Button('Face Comparison')
      .onClick(/* Trigger the comparison logic */)
  }
}
Enter fullscreen mode Exit fullscreen mode

Summary:

Key Points

  1. Photo album access permission is required.
  2. Dual-image selection is managed using independent storage variables.
  3. The compareFaces interface returns the similarity (0-1) and feature point data.
  4. Device compatibility issues are captured through BusinessError for exception handling.

Complete Code

import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { fileIo } from '@kit.CoreFileKit';
import { image } from '@kit.ImageKit';
import { faceComparator } from '@kit.CoreVisionKit';
import { promptAction } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@ComponentV2
struct FaceComparator {
  @Local chooseImage1?: PixelMap
  @Local chooseImage2?: PixelMap

  async chooseImage (): Promise<PixelMap> {
    const photoPicker: photoAccessHelper.PhotoViewPicker = new photoAccessHelper.PhotoViewPicker();
    const photoResult = await photoPicker.select({
      MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
      maxSelectNumber: 1
    })
    const photoUri = photoResult.photoUris[0]

    const fileSource = await fileIo.open(photoUri, fileIo.OpenMode.READ_ONLY);
    const imageSource = image.createImageSource(fileSource.fd);
    const chooseImage = await imageSource.createPixelMap();
    return chooseImage
  }

  build() {
    Column({ space: 20 }) {
      Image(this.chooseImage1)
        .alt($r('sys.media.save_button_picture'))
        .width(200)
        .aspectRatio(1)
        .onClick(async () => {
          const chooseImage = await this.chooseImage()
          this.chooseImage1 = chooseImage
        })
      Image(this.chooseImage2)
        .alt($r('sys.media.save_button_picture'))
        .width(200)
        .aspectRatio(1)
        .onClick(async () => {
          const chooseImage = await this.chooseImage()
          this.chooseImage2 = chooseImage
        })
      Button('Face Comparison')
        .id('FaceComparatorButton')
        .onClick(async () => {
          if (this.chooseImage1 && this.chooseImage2) {
            let visionInfo: faceComparator.VisionInfo = {
              pixelMap: this.chooseImage1,
            };
            let visionInfo1: faceComparator.VisionInfo = {
              pixelMap: this.chooseImage2,
            };
            faceComparator.compareFaces(visionInfo, visionInfo1)
              .then(result => {
                promptAction.showDialog({ message: JSON.stringify(result) })
              })
              .catch((e: BusinessError) => {
                promptAction.showToast({ message: e.message })
              })
          }
        })
    }
    .padding(15)
    .height('100%')
    .width('100%')
  }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)