HUAWEI ML Kitを使用してわずか30分でSmile-Cameraを作成する方法

Huawei HMS Core 4.0発表イベントで最も注目を集めたサービスの1つに、Machine Learning (ML) Kitがあります。
では、ML Kitとはどのようなサービスでしょうか？このキットは、開発工程でどのような問題を解決できるのでしょうか？
今日は、ML Kitの最も強力な機能の1つ、顔検出をご紹介します。
## 顔検出の概要
![1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696852/7e3a21fb-c898-1217-b303-839662b33be6.gif)

このサービスは、顔の向き、表情（幸せ、嫌悪、驚き、悲しみ、または怒り）、属性（性別、年齢、服飾品や装身具）、眼を開いているか閉じているかを検出できます。鼻、眼、唇、眉毛の座標をマッピングすることもでき、複数の顔のグループ全体を一度に検出することさえできます。
特に、顔検出サービスは完全に無償であり、Android端末で動作します。
##複数の顔に対応するSmile-Cameraの開発
上記の機能をどのように使用して、Smile-Cameraデモを作成するかお見せします。デモのソースコードは[GitHub](https://github.com/HMS-Core/hms-ml-demo)からダウンロードできます。
### 1. 準備
HMS Coreキットを統合する場合、準備工程はほぼ同じです。Mavenリポジトリを追加してSDKをインポートするだけです。
#### 1.1 Huawei Mavenリポジトリをプロジェクトレベルのbuild.gradleファイルに追加する
Mavenリポジトリアドレスを追加します。

```javascript

buildscript {
    repositories {        
        maven {url 'http://developer.huawei.com/repo/'}
    }    }allprojects {
    repositories {       
        maven { url 'http://developer.huawei.com/repo/'}
    }}
```
#### 1.2 SDK依存関係をアプリレベルのbuild.gradleファイルに追加する
顔検出SDKと基本SDKをインポートします。

```javascript
dependencies{ 
  // import the basic SDK 
  implementation 'com.huawei.hms:ml-computer-vision:1.0.2.300' 
  // Import the face detection SDK
  implementation 'com.huawei.hms:ml-computer-vision-face-recognition-model:1.0.2.300'   
 }
```
#### 1.3 自動モデルダウンロード機能をAndroidManifest.xmlファイルに追加する
この機能は主にモデルの更新に使用します。モデルは自動的にダウンロードされ、最適化アルゴリズムに基づいてモバイル端末上で更新されます。

```javascript
<manifest    
   <application  
       <meta-data                     
           android:name="com.huawei.hms.ml.DEPENDENCY"          
           android:value= "face"/>                 
   </application></manifest> 
```
#### 1.4 AndroidManifest.xmlファイルでカメラとストレージの権限を適用する

```javascript
<!--Camera permission-->
<uses-permission android:name="android.permission.CAMERA" />
<!--Storage permission-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
```
### 2.コードの開発
#### 2.1 顔分析機能を作成して、笑顔を検出した場合に撮影する
まず、笑顔が検出された場合に写真を撮影するようカメラを設定するには、以下の手順を実行します。 
(1) 分析機能のパラメータを設定します。 
(2) パラメータを分析機能に渡します。 
(3) **analyzer.setTransacto**の**transactResult**をオーバーライドし、顔を検出した場合に返される内容を処理します。具体的には、信頼値（笑顔になっている確率）が返されます。この信頼値が事前に設定された閾値に達すると、カメラが自動的に撮影します。

```java

private MLFaceAnalyzer analyzer;private void createFaceAnalyzer() {
    MLFaceAnalyzerSetting setting =
            new MLFaceAnalyzerSetting.Factory()
                    .setFeatureType(MLFaceAnalyzerSetting.TYPE_FEATURES)
                    .setKeyPointType(MLFaceAnalyzerSetting.TYPE_UNSUPPORT_KEYPOINTS)
                    .setMinFaceProportion(0.1f)
                    .setTracingAllowed(true)
                    .create();                 
    this.analyzer = MLAnalyzerFactory.getInstance().getFaceAnalyzer(setting);
    this.analyzer.setTransactor(new MLAnalyzer.MLTransactor<MLFace>() {
        @Override        public void destroy() {
        }

        @Override        public void transactResult(MLAnalyzer.Result<MLFace> result) {
            SparseArray<MLFace> faceSparseArray = result.getAnalyseList();
            int flag = 0;
            for (int i = 0; i < faceSparseArray.size(); i++) {
                MLFaceEmotion emotion = faceSparseArray.valueAt(i).getEmotions();
                if (emotion.getSmilingProbability() > smilingPossibility) {
                    flag++;
                }
            }
            if (flag > faceSparseArray.size() * smilingRate && safeToTakePicture) {
                safeToTakePicture = false;
                mHandler.sendEmptyMessage(TAKE_PHOTO);
            }
        }
    });}
```
次に、撮影された写真を保存します。

```java
private void takePhoto() {
    this.mLensEngine.photograph(null,
            new LensEngine.PhotographListener() {
                @Override                public void takenPhotograph(byte[] bytes) {
                    mHandler.sendEmptyMessage(STOP_PREVIEW);
                    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
                    saveBitmapToDisk(bitmap);
                }
            });}
```
#### 2.2 LensEngineのインスタンスを作成し、動的カメラストリームをキャプチャしてストリームを分析機能に渡す

```java
private void createLensEngine() {
    Context context = this.getApplicationContext();
    // Create LensEngine
    this.mLensEngine = new LensEngine.Creator(context, this.analyzer).setLensType(this.lensType)
            .applyDisplayDimension(640, 480)
            .applyFps(25.0f)
            .enableAutomaticFocus(true)
            .create();}
```

#### 2.3 動的な権限の申請を送信し、分析機能およびLensEngine作成コードを添付する

```java
@Overridepublic void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.setContentView(R.layout.activity_live_face_analyse);
    if (savedInstanceState != null) {
        this.lensType = savedInstanceState.getInt("lensType");
    }
    this.mPreview = this.findViewById(R.id.preview);
    this.createFaceAnalyzer();
    this.findViewById(R.id.facingSwitch).setOnClickListener(this);
    // Checking Camera Permissions
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
        this.createLensEngine();
    } else {
        this.requestCameraPermission();
    }}
    private void requestCameraPermission() {
    final String[] permissions = new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE};

    if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
        ActivityCompat.requestPermissions(this, permissions, LiveFaceAnalyseActivity.CAMERA_PERMISSION_CODE);
        return;
    }}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                       @NonNull int[] grantResults) {
    if (requestCode != LiveFaceAnalyseActivity.CAMERA_PERMISSION_CODE) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        return;
    }
    if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        this.createLensEngine();
        return;
    }}
``````

## フォローアップ
とても簡単でしょう？開発工程にそれほど詳しくなくても、30分ほどで便利な新機能を作成できます。では、その機能を見てみましょう。
1人の笑顔のスナップショット\
![2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696852/7364c7f2-9bed-ef5c-63cc-bc725080dcd2.gif)


複数人の笑顔のスナップショット
![3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696852/eb06a126-6104-9328-9480-ea8a26cf2eb2.gif)
顔検出機能で他に何ができるでしょうか？いくつか考えてみましょう。
1.顔の特徴を装飾する。 
2.顔の輪郭や特徴を誇張したり、強調したりして面白い効果を生み出す。 
3.子供が不適切なコンテンツにアクセスできないよう、年齢識別機能を開発する。 
4.ユーザーが画面を見つめていた時間を検出して、眼の保護機能を開発する。 
5.ランダムコマンド（頭部を振る、瞬きをする、口を開けるなど）を使用して、ライブネスを検出する。 
6.年齢や性別に応じてユーザーに製品を勧める。
詳しくは、当社の公式ウェブサイトをご覧ください。[HUAWEI ML Kit - About the Service](https://developer.huawei.com/consumer/en/doc/development/HMS-Guides/ml-introduction-4)
## 近日公開予定
さらに実用的な場面でHUAWEI ML Kitをお使いいただけるようになります。ワクワクするような内容に是非ご注目ください。