やりたいこと
画像認識、画像処理ライブラリOpenCVをAndroidのプロジェクトに組み込んで、カメラ映像に簡単な処理を加えてみます。一度組み込みに成功すれば、画像処理は変更可能と思いますので、簡単な例としてカメラ映像をグレースケールで出力する例を記述致します。
準備
以下のサイトからダウンロード可能です
http://sourceforge.net/projects/opencvlibrary/files/opencv-android/
今回は Version 3.0.0を選択しました。
準備は以下のサイトがとても詳しいので、以下の記事を参考にして頂き、OpenCVを使いたいプロジェクトにライブラリを追加します。
http://smartphone-zine.com/android/use-opencv-for-android-in-the-android-studio.html
1点異なる点は、この記事ではjniLibraryをコピーしているのですが、OpenCV Managerをインストールすれば動作可能なので必要ありません。jniLibraryを組み込むとアプリケーションサイズが大きくなってしまいますので、OpenCV Managerの使用をオススメします。
アプリケーション実行前にインストールしても良いですが、インストールされていない場合も、OpenCVの機能を使う前に以下のようなダイアログが表示されますので、そこからインストールが可能です。
アプリケーションの作成
カメラを使いますのでPermissionの追加をAndroidManifest.xmlに行います。
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
次にカメラの映像をOpenCVライブラリに渡す方法なのですが、OpenCV SDKには専用のViewが用意されています。ActivityもしくはFragmentのレイアウトファイルにJavaCameraViewを追加して下さい。
<org.opencv.android.JavaCameraView
android:id="@+id/camera_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="visible"/>
今回はFragmentにJavaCameraViewを貼付けた場合の例でコードを追記していきます。
まず、Viewが生成後にJavaCameraViewのインスタンスを取得します。またカメラのフレームを受けるためにリスナーを追加します。ここでは、Fragment自体でCvCameraViewListener2を実現します。Fragmentクラスの定義は以下のようになります
public class HogeFragment extends Fragment implements CvCameraViewListener2 {
...
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mCameraView = (CameraBridgeViewBase)view.findViewById(R.id.camera_view);
mCameraView.setCvCameraViewListener(this);
}
@Override
public void onDestroyView() {
super.onDestroyView();
mCameraView = null;
}
@Override
public void onCameraViewStarted(int width, int height) {
}
@Override
public void onCameraViewStopped() {
}
@Override
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
...
}
次にonResumeの段階でOpenCVライブラリの読み込みを行います。読み込みが完了した時点で、JavaCameraViewをEnableにしてフレームを受信し始めます。読み込み完了を知るためにはListenerを登録する必要があります。
private static class OpenCVLoaderCallback extends BaseLoaderCallback {
private final CameraBridgeViewBase mCameraView;
private OpenCVLoaderCallback(Context context, CameraBridgeViewBase cameraView) {
super(context);
mCameraView = cameraView;
}
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
mCameraView.enableView();
break;
default:
super.onManagerConnected(status);
break;
}
}
}
@Override
public void onResume() {
super.onResume();
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, getActivity(),
new OpenCVLoaderCallback(getActivity(), mCameraView));
}
@Override
public void onPause() {
super.onPause();
mCameraView.disableView();
}
これでonCameraFrameにフレームがきます。グレーアウトする場合は、実は何もする必要がなくて、入力されたフレームからグレースケールのデータだけを以下のように返せば実現が可能です。
@Override
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
return inputFrame.gray();
}