SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

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

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

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

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

モザイクカメラを作ろう(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クラスを参照してください。

次のページ
モザイクカメラを作ろう(2)

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加
スマホアプリを豊かにする「docomo Developer support」で遊ぼう連載記事一覧

もっと読む

この記事の著者

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

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

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

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

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

【AD】本記事の内容は記事掲載開始時点のものです 企画・制作 株式会社翔泳社

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/8430 2015/02/05 11:05

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング