Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

誰でも手軽にNTTドコモのサービスのような機能を持つアプリが作れる ~顔検出APIでモザイクカメラを作ろう

スマホアプリを豊かにする「docomo Developer support」で遊ぼう(3)

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加
2015/02/04 14:00
目次

モザイクカメラを作ろう(1)

 では次に、顔検出APIを利用してモザイクカメラを作ってみましょう。認識した顔情報を元に、撮影した画像にモザイク加工を施します。

カメラAPI

 今回のアプリでは、前回と異なりカメラの制御も自前で行うことにします。カメラの制御は、Android SDKに含まれているCamera API(android.hardware.Cameraパッケージ)を利用します。このAPIは、Android 5.0(APIレベル21)では非推奨となり、camera2(android.hardware.camera2)が公開されています。ただ新しいAPIは、Android 5.0でしか動作しませんので、本稿では、対応機種の多い従来のCamera APIを使うアプリとしています。

カメラのプレビューを表示する

 SDKとともに配布されているサンプルプログラムに、カメラからの入力映像を全画面でプレビュー表示するプログラムがあります。APIレベル19のSDKであれば、インストールしたSDKのsamplesフォルダ以下の\android-19\legacy\ApiDemosというフォルダに納められています。

カメラプレビューのサンプルソース
\samples\android-19\legacy\ApiDemos\src\com\example\android\apis\graphics\CameraPreview.java

 今回のアプリは、このサンプルプログラムを元に、必要なコードを追加していくことにします。なお、紙面に限りがありますので、追加したコードを抜粋して解説します。アプリ全体は、別途ダウンロードして参照してみてください。

Manifestファイルの設定

 最初に、パーミッションの設定をしておきましょう。カメラ機能の利用と、外部ディスクへのデータ保存、そして、Web APIのためのインターネット接続許可の設定を追加します。

 また、今回のアプリは、screenOrientation属性に、横向き(landscape)専用の設定を追加しています。これは、元のサンプルプログラムでは、縦向きの場合に、プレビュー画面のアスペクト比が少しおかしくなるためです。

リスト3 AndroidManifest.xmlの一部
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application>
    <activity android:screenOrientation="landscape"></activity>
</application>

主な処理の流れ

 元のプレビュープログラムは、カメラの入力データを、リアルタイムに全画面のSurfaceViewに描画するものです。SurfaceViewは、通常のViewとは異なり、メインスレッド以外のスレッドからも高速に描画可能なため、カメラ画像や動きの速いゲーム画面に適しています。

 サンプルプログラムは、単にSurfaceViewに描画するだけなので、プレビューを保存する処理を追加します。本アプリでは、プレビュー画面をタッチしたときに、オートフォーカスを行い、その画像を加工、保存します。

 主な処理の流れは、次のようになります。

  1. カメラ画像をSurfaceViewに描画する
  2. 画面をタッチすると、OnTouchListenerが呼ばれる
  3. オートフォーカス(autoFocus)を実行する
  4. オートフォーカスの実行後、AutoFocusCallbackが呼ばれる
  5. 撮影(takePicture)する
  6. 撮影後、画像のJPEGデータができたら、PictureCallbackが呼ばれる
  7. 画像データから、顔検出APIを使って顔の位置座標を検出する
  8. 検出結果の座標を元に、モザイク処理を行う
  9. 加工した画像を保存する
リスト4 MainActivity.javaの一部
public class MainActivity extends Activity {

~中略~

    // 二重起動防止フラグ
    private boolean mIsTake = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
~中略~
        // 画面をタッチすると、OnTouchListenerが呼ばれる(1)
        mPreview.setOnTouchListener(new OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                if (!mIsTake && event.getAction() == MotionEvent.ACTION_DOWN) {
                    mIsTake = true;             // 二重起動防止フラグON
                    // オートフォーカスを実行する(2)
                    mCamera.autoFocus(mAutoFocusListener);
                }
                return true;
            }
        });
    }

    // オートフォーカス動作後に呼ばれる(3)
    private Camera.AutoFocusCallback mAutoFocusListener =
        new Camera.AutoFocusCallback() {
            public void onAutoFocus(boolean success, Camera camera) {
                // 撮影する(4)
                mCamera.takePicture(null, null, mPicJpgListener);
        }
    };

    // JPEGイメージ生成後に呼ばれる(5)
    private Camera.PictureCallback mPicJpgListener =
        new Camera.PictureCallback() {
            public void onPictureTaken(final byte[] data, Camera camera) {
                if (data == null)   return;

                // 画像データから顔を検出する(6)
                new ImageRecognitionClient().faceDetection(data,
                    new JsonHttpResponseHandler() {
                        @Override
                        public void onSuccess(int statusCode, Header[] headers,
                            JSONObject response) {
                            saveMosaic(data, response); // モザイク処理(7、8)
                            mCamera.startPreview();     // プレビュー表示の再開
                            mIsTake = false;        // 二重起動防止フラグ解除
                            Toast.makeText(MainActivity.this,
                                "保存しました", Toast.LENGTH_LONG).show();
                        }
                });
            }
     };

~後略~
}

 元のMainActivityクラスに、画面をタッチした際のハンドラであるOnTouchListener(1)と、オートフォーカスした際のハンドラのmAutoFocusListener(3)、撮影後のハンドラのmPicJpgListener(5)を追加しています。

 実際の撮影は、Camera APIのtakePictureメソッドで行います。このメソッドの引数にコールバックを指定すると、撮影した画像データを受け取ることができます。ここで指定している第3引数のコールバックでは(4)、JPEG形式の画像データが渡されます。

 なお、一度タッチされると、一連の処理が終わるまでは、再度実行されないように、二重起動防止フラグ(mIsTake)で制御しています。また、オートフォーカスや撮影を実行すると、プレビュー表示がいったん停止しますので、startPreviewメソッドで、再開するようにしています。

画像データから顔を検出する

 顔検出APIの呼び出しは、ImageRecognitionClientというクラスを作り、その中のfaceDetectionメソッドで行っています。

リスト5 ImageRecognitionClient.javaの一部
public class ImageRecognitionClient {
    // 顔検出API
    private final String APIURL = "https://api.apigw.smt.docomo.ne.jp/puxImageRecognition/v1/faceDetection";
    private final String APIKEY = "XXXXXX";
    private AsyncHttpClient client = new AsyncHttpClient();

    public void faceDetection(byte[] data, AsyncHttpResponseHandler responseHandler) {
        RequestParams params = new RequestParams();
        params.put("response", "json");

        // 画像データからBase64変換した文字列を設定する(1)
        params.put("inputBase64", Base64.encodeToString(data, Base64.DEFAULT));

        // POSTメソッドでAPIを呼び出す(2)
        this.client.post(APIURL + "?APIKEY=" + APIKEY, params, responseHandler);
    }
}

 実際のHTTP通信は、Android Asynchronous Http Clientというオープンソースのライブラリを使っています。サイトからライブラリ本体(執筆時点では、android-async-http-1.4.6.jar)をダウンロードして、プロジェクトのlibsフォルダにコピーしておきます。このライブラリのおかげで、HTTP通信部分もメソッドを呼び出すだけのシンプルな実装になっています。

 ImageRecognitionClientクラスのfaceDetectionメソッドのdataパラメータには、撮影した画像のビットマップデータが渡されますので、Base64の文字列に変換してパラメータに設定しています(1)。そして、顔検出APIを、AsyncHttpClientクラスのpostメソッドで呼び出します(2)

 APIが実行されてレスポンスが返されると、responseHandlerが呼ばれます。レスポンスデータの処理は、AsyncHttpResponseHandlerオブジェクト(responseHandler)のonSuccessメソッドに記述します。MainActivityクラスを参照してください。


  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • WINGSプロジェクト 高江 賢(タカエ ケン)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XMLD...

バックナンバー

連載:スマホアプリを豊かにする「docomo Developer support」で遊ぼう
All contents copyright © 2005-2019 Shoeisha Co., Ltd. All rights reserved. ver.1.5