SHOEISHA iD

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

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

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

誰でも手軽にNTTドコモのサービスのような機能を持つアプリが作れる ~Androidアプリから画像認識APIを実行する

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

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

画像認識APIとカメラ機能を連携する

 サンプルアプリは、画像のパス名を入力し、画像認識のボタンをタップすると、APIを実行して商品情報を表示します。また、その結果が妥当だったかどうかを、フィードバック(報告)することもできます。

 今回は、このサンプルを少し改造してみましょう。Androidのカメラ機能や画像ギャラリーと連携するようにして、すぐに画像認識を試せるようにしてみます。

AndroidManifest.xmlへの追加

 撮影したカメラ画像を保存するために、マニフェストファイルのPermission属性に、INTERNET、READ_EXTERNAL_STORAGEと共に、保存用のWRITE_EXTERNAL_STORAGEを追加します。

リスト1 AndroidManifest.xmlの一部
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

RecognitionActivity.javaの変更

 次に、RecognitionActivity.javaを変更します。最初に、カメラで撮影した画像ファイルのURI用に、RecognitionActivityクラスのフィールドを追加します。

リスト2 RecognitionActivity.javaの一部
private Uri bitmapUri; // 画像ファイルのURI

 そして、pushExecButtonメソッドを変更し、onActivityResultメソッドのオーバーライドを追加します。元のpushExecButtonメソッドでは、APIを実行するようになっていますが、これをカメラ撮影と画像ギャラリーと連携する処理に変更します。また、onActivityResultメソッドでは、撮影した画像または画像ギャラリーの画像ファイルのURIを用いて、APIを実行するようにします。

リスト3 RecognitionActivity.javaの一部
@SuppressLint("NewApi")
private void pushExecButton() {

    // ギャラリー選択のIntent1
    Intent intent = new Intent();

    // APIレベル19(Kit)以降と区別する2
    intent.setAction((Build.VERSION.SDK_INT < 19) ?
                    Intent.ACTION_GET_CONTENT: Intent.ACTION_OPEN_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("image/*");

    // カメラ撮影して保存する画像ファイル名を設定しておく3
    File mediaFile = new File(
            Environment.getExternalStoragePublicDirectory(
                                        Environment.DIRECTORY_DCIM),
                                        System.currentTimeMillis() + ".jpg");
    bitmapUri = Uri.fromFile(mediaFile);

    // カメラ撮影のIntent4
    Intent intent_camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    intent_camera.putExtra(MediaStore.EXTRA_OUTPUT, bitmapUri);

    // ギャラリー選択でcreateChooserし、カメラ撮影のIntentを追加する5
    Intent chooserIntent = Intent.createChooser(intent, "画像の選択");
    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS,
                                            new Intent[] { intent_camera });
    startActivityForResult(chooserIntent, 1);
}

@SuppressLint("NewApi")
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == 1) {
        if (resultCode == RESULT_OK) {
            String path = bitmapUri.getPath(); // カメラ画像のパス名
            if (data != null) {
                // カメラ画像でない場合は、画像ギャラリーから取得する6
                if (!data.getData().getPath().equals(bitmapUri.getPath())) {

                    // APIレベル19(Kit)以降と区別する7
                    Cursor cursor;
                    if (Build.VERSION.SDK_INT < 19) {
                        String[] columns = { MediaColumns.DATA };
                        cursor = getContentResolver().query(data.getData(),
                                                    columns, null, null, null);
                    }
                    else {
                        String id = DocumentsContract.getDocumentId(
                                                                data.getData());
                        String selection = "_id=?";
                        String[] selectionArgs = new String[]{id.split(":")[1]};
                        cursor = getContentResolver().query(
                                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                                    new String[]{MediaColumns.DATA},
                                    selection, selectionArgs, null);
                    }
                    if (cursor.moveToFirst()) {
                        path = cursor.getString(0);
                    }
                }
            }

            // 画像のパス名を表示する
            EditText editText = (EditText)findViewById(R.id.edit_path);
            editText.setText(path);

            AlertDialog.Builder dlg = new AlertDialog.Builder(this);

            // パラメータを設定する
            ImageRecognitionRequestParam requestParam =
                                            new ImageRecognitionRequestParam();
            requestParam.setRecog(Recog.ALL);

            // 画像のパスを設定する
            requestParam.setFilePath(path);

            // 実行
            task = new RecognitionAsyncTask(dlg);
            task.execute(requestParam);
        }
    }
}

 この変更でのポイントは、次の3点です。

  • カメラ機能と画像ギャラリーの連携に、intent機能を使う
  • intentで呼び出した処理の戻り値を、onActivityResultで処理する
  • KitKat以降では、画像ギャラリーの扱いが異なる

 Androidでは、カメラ機能を直接操作することもできますが、標準のカメラアプリを使う方がかんたんです。ここでは、カメラアプリと画像ギャラリーを呼び出すために、intent機能を使っています(コメント行の14)。また、Intent.createChooserを使って、カメラアプリと画像ギャラリーの両方に対応したintentを発行しています5

 intentで呼び出した処理(Activity)の戻り値は、onActivityResultメソッドをオーバーライドすることで処理することができます。onActivityResultメソッドの3つめの引数に、intentの戻り値(画像ファイルのURI)が格納されています。

 ただし、カメラ画像では、この値がNULLとなる機種がほとんどです。そのため、これがNULLか、あるいは設定したURI3と同じであれば、カメラ画像、そうでなければ、画像ギャラリーのURIと判断しています6

 Android 4.4(KitKat、APIレベル19)から、Storage Access Frameworkという機能が搭載され、画像ギャラリーから戻される画像URIが変更されました。そのため、Build.VERSION.SDK_INTで、実行している機種のAPIレベルを調べ、レベルに応じて処理を変更しています27

実行してみよう

 変更したアプリを起動し、「画像認識要求実行」をボタンをタップすると、カメラ撮影か、ギャラリーかを選択できるダイアログが表示されるようになります。

 カメラで撮影するか、ギャラリーの画像を選択すると、元の画面に戻ります。しばらくすると画像が認識され、次のような表示になります。身近にある商品なら、たいてい認識できるのではないでしょうか。

サンプルアプリの結果画面
サンプルアプリの結果画面

最後に

 今回は、APIの呼び出し方と、画像認識APIを例にしてSDKの使い方を解説しました。次回も、提供されているSDKを利用して楽しいAndroidアプリを作ってみます。

「Developer Application Contest 3rd」開催

 docomo Developer supportではアプリケーション・アプリケーションアイデアを対象としたコンテストを開催しています。応募要項や募集期間などの詳細はサイトにてご確認ください。

 

 なお、ドコモはdocomo Developer supportからAPI提供を検討される企業様を募集しており、オープンイノベーションを加速する良質で実績の高いAPIの提供プラットフォームを目指しております。詳細は上記サイトに随時掲載していきます。

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

  • X ポスト
  • このエントリーをはてなブックマークに追加
スマホアプリを豊かにする「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 X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

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

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

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

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/8299 2014/12/12 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング