HUAWEI ML Kitを使用して、ID用写真のDIYアプレットを作成する方法

## 概要
以前の投稿で、HUAWEI ML Kitを使用したSmile-Cameraの作成方法を検討しました。今回は、HUAWEI ML Kitの新機能をご紹介します。
 
学校や会社からIDカード用に特定の背景色で撮影された1インチか2インチのポートレート写真を用意するよう頼まれたことはないでしょうか？多くの場合、そのような用途に適した写真は手元にないでしょう。以前、私が通っていた学校が個人用入室カードを学生のために申請する必要がありました。ところが、フォトスタジオは閉店していました。そこで私は、ベッドのシーツを背景にして、自分のスマートフォンを使い写真を撮りました。その結果、担任の先生から叱られる羽目になりました。しかし、HUAWEI ML Kitを使用すれば、画像分割SDKをアプリに統合して、ID用写真のDIYアプレットを開発し、このような問題を解決することができます。

さらに良いことに、このSDKは完全に無償であり、Android端末で動作します。
## ID用写真のDIYアプレットの開発
### 1.準備
#### 1.1 Huawei Mavenリポジトリをプロジェクトレベルのbuild.gradleファイルに追加する
Android Studioプロジェクトのルートディレクトリにある**build.gradle**ファイルを開きます。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696852/fb40128c-75a1-50ae-edaa-fb12c348eb00.png)
この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 base SDK. 
  implementation 'com.huawei.hms:ml-computer-vision:1.0.2.300' 
  // Import the face detection SDK. 
  implementation 'com.huawei.hms:ml-computer-vision-image-segmentation-body-model:1.0.2.301'   }
```

#### 1.3 自動モデルダウンロード機能をAndroidManifest.xmlファイルに追加する
アプリがHUAWEI AppGalleryからダウンロードされた際に、アプリの機械学習モデルが自動的に最新版に更新されるようにするには、以下の内容を**AndroidManifest.xml**ファイルに追加します。

```javascript

<manifest    
   <application  
       <meta-data                     
           android:name="com.huawei.hms.ml.DEPENDENCY"          
           android:value= "imgseg "/>                 
   </application></manifest> 
```

#### 1.4 AndroidManifest.xmlファイルでカメラとストレージの権限を適用する

```javascript
<!--Storage permission --><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
```
### 2.コードの開発
#### 2.1 動的な権限の申請を送信する

```java
@Overrideprotected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if (!allPermissionsGranted()) {
        getRuntimePermissions();
    }}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                       @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    if (requestCode != PERMISSION_REQUESTS) {
        return;
    }
    boolean isNeedShowDiag = false;
    for (int i = 0; i < permissions.length; i++) {
        if (permissions[i].equals(Manifest.permission.READ_EXTERNAL_STORAGE) && grantResults[i] != PackageManager.PERMISSION_GRANTED) {
            // If camera or storage permissions are unauthorized, an authorization dialog box will be displayed.
            isNeedShowDiag = true;
        }
    }
    if (isNeedShowDiag && !ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CALL_PHONE)) {
        AlertDialog dialog = new AlertDialog.Builder(this)
                .setMessage(getString(R.string.camera_permission_rationale))
                .setPositiveButton(getString(R.string.settings), new DialogInterface.OnClickListener() {
                    @Override                    public void onClick(DialogInterface dialog, int which) {
                        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                        intent.setData(Uri.parse("package:" + getPackageName())); // Open the corresponding settings page based on the package name.
                        startActivityForResult(intent, 200);
                        startActivity(intent);
                    }
                })
                .setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
                    @Override                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                }).create();
        dialog.show();
    }}
```
#### 2.2 画像分割分析機能を作成する
**MLImageSegmentationSetting**を使用して、画像分割分析機能を作成します。

```java
MLImageSegmentationSetting setting = new MLImageSegmentationSetting.Factory()
                .setAnalyzerType(MLImageSegmentationSetting.BODY_SEG)
                .setExact(true)
                .create();        this.analyzer = MLAnalyzerFactory.getInstance().getImageSegmentationAnalyzer(setting);
```
#### 2.3 android.graphics.Bitmapを使用してMLFrameオブジェクトを作成して、分析機能が画像を検出できるようにする

```java
MLFrame mlFrame = new MLFrame.Creator().setBitmap(this.originBitmap).create();
```
#### 2.4 asyncAnalyseFrameメソッドを呼び出して画面分割を実行する

```java
// Create a task to process the results returned by the image segmentation analyzer.
Task<MLImageSegmentation> task = analyzer.asyncAnalyseFrame(frame); // Asynchronously process the results returned by the image segmentation analyzer. Task<MLImageSegmentation> task = this.analyzer.asyncAnalyseFrame(mlFrame);
            task.addOnSuccessListener(new OnSuccessListener<MLImageSegmentation>() {
                @Override                public void onSuccess(MLImageSegmentation mlImageSegmentationResults) {
                    // Transacting logic for segment success.
                    if (mlImageSegmentationResults != null) {
                        StillCutPhotoActivity.this.foreground = mlImageSegmentationResults.getForeground();
                        StillCutPhotoActivity.this.preview.setImageBitmap(StillCutPhotoActivity.this.foreground);
                        StillCutPhotoActivity.this.processedImage = ((BitmapDrawable) ((ImageView) StillCutPhotoActivity.this.preview).getDrawable()).getBitmap();
                        StillCutPhotoActivity.this.changeBackground();
                    } else {
                        StillCutPhotoActivity.this.displayFailure();
                    }
                }
            }).addOnFailureListener(new OnFailureListener() {
                @Override                public void onFailure(Exception e) {
                    // Transacting logic for segment failure.
                    StillCutPhotoActivity.this.displayFailure();
                    return;
                }
            });
```
#### 2.5 画像の背景を変更する

```java
this.backgroundBitmap = BitmapUtils.loadFromPath(StillCutPhotoActivity.this, id, targetedSize.first, targetedSize.second);BitmapDrawable drawable = new BitmapDrawable(backgroundBitmap);this.preview.setDrawingCacheEnabled(true);this.preview.setBackground(drawable);this.preview.setImageBitmap(this.foreground);this.processedImage = Bitmap.createBitmap(this.preview.getDrawingCache());this.preview.setDrawingCacheEnabled(false);
```
## 結果
以上で終わりです。ID用写真のDIYアプレットは使用可能です。早速、使ってみましょう。
![20200321104442628.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696852/7c3bf3d3-afc2-1660-dbac-d8b81774c120.gif)

ソースコードを[GitHub](https://github.com/HMS-Core/hms-ml-demo/tree/master/ID-Photo-DIY)アップロードしているので、機能の向上などお気軽にお試しください。コーディングスキルを強化したい場合、ポートレートをスーツに着せ替えるなどの機能を追加してみてはいかがでしょうか？
このID用写真のDIYアプレットを作成したように、画面分割機能を利用してあらゆる種類の便利な機能を持つアプリを作成することができます。例えば、以下のような機能が挙げられます。 
1.ポートレートを切り取り、背景を変えることにより、ユーザーは面白い設定を色々と楽しんだり、ぼやけた画像を背景にして芸術的な写真を作成したりする。 
2.画像内で空、植物、食品、猫、犬、花、水、砂、建物、山を識別して修正する。ユーザーが空をより青くしたり、水をより透明にしたりして写真を改善したいと思う場合、このような機能が役に立ちます。 
3.ビデオストリーム内でオブジェクトを認識したり、ビデオストリームの背景を編集・変更したりする。
詳しくは、当社の[公式ウェブサイト](https://developer.huawei.com/consumer/en/doc/development/HMS-Guides/ml-introduction-4)をご覧ください。 
## 近日公開予定
さらに実用的な場面でHUAWEI ML Kitをお使いいただけるようになります。ワクワクするような内容に是非ご注目ください。