Androidのカメラ機能を活用し、リアルタイムに画像処理をしてみましょう。
Android SDKでカメラを扱うにはandroid.hardware.cameraパッケージを利用します。cameraパッケージではカメラからの入力映像をそのまま簡単に画面に表示する「プレビュー」機能があります。
画像を編集する前段階として、プレビュー画面に表示したカメラ画像をキャプチャする方法を紹介します。
便利なことにAndroid SDKのAPI Demos内でカメラ機能について纏まっていますので、このGraphics/CameraPreview.javaをベースに改造を加えていきましょう。サンプルではプレビューしている画像データをキャプチャ、保存する機能を追加します。
Cameraクラスの主なメソッドと関連クラス
メソッド名 | 説明 |
---|---|
getNumberOfCameras() | Android端末のカメラデバイス数を取得する |
getCameraInfo(i, camerainfo) | 指定デバイスNoのCameraInfoを取得する。 |
open() | カメラデバイスリソースの取得 |
release() | カメラデバイスリソースの解放 |
setPreviewCallback() | プレビュー完了時のコールバックメソッドの登録 |
Camera.PreviewCallback | プレビュー完了時に呼び出されるコールバックメソッド |
Camera.PreviewCallback.onPreviewFrame(byte[] data, Camera camera) | プレビュー更新時のフレーム情報 |
startPreview() | プレビューの開始 |
stopPreview() | プレビューの終了 |
複数のカメラを使う https://techbooster.org/andriod/device/2358/
カメラの使用方法(2) https://techbooster.org/andriod/device/362/
パーミッションの設定
カメラ機能を利用するにはパーミッションの設定が必要です。忘れないように、はじめに追加しておくとよいでしょう
■AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.jpn.techbooster.sample.camerapreviews" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="10" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> ...省略... </manifest>
カメラ機能を利用する権限を取得するため、7行目にuses-permission要素を追加しています。このサンプルでは外部ディスクへのデータ保存を行うため、WRITE_EXTERNAL_STORAGEも付与しています。
カメラ情報の取得
カメラプレビューを表示するため、ActivityのonCreateメソッド内でカメラ数の取得や利用するカメラの種類(フロントカメラ・バックカメラ)など初期設定を行います。
■src/CameraPreviewsActivity.java
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //タイトルを非表示 requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); // プレビュー画面を作成 mPreview = new Preview(this); setContentView(mPreview); // カメラ数を取得 numberOfCameras = Camera.getNumberOfCameras(); // 複数カメラがあった場合に備えて、BACKカメラを指定 CameraInfo cameraInfo = new CameraInfo(); for (int i = 0; i < numberOfCameras; i++) { Camera.getCameraInfo(i, cameraInfo); if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) { defaultCameraId = i; } } }
10行目のPreviewクラスはApiDemosのGraphics/CameraPreview.java内にあるカメラプレビュー用のクラスです。カメラ制御にかかわる機能がまとめられており、11行目のsetContentViewメソッドの引数にできるように、Viewクラスを継承しています。
14行目 CameraクラスのgetNumberOfCamerasメソッドでAndroid端末のカメラ数を取得し、20行目でバックカメラを探します
カメラリソースの取得と解放
カメラリソースの取得/解放は、onResumeメソッドとonPauseメソッドで行います。
まれに、デバッグ中に強制終了した場合、リソースを解放できずにリソースを再取得できないケースがあります。リソース取得/解放ができていないと不具合に繋がるため、Tipsとして覚えておくとよいでしょう。最悪、Android端末の再起動が必要になります。
■src/CameraPreviewsActivity.java
@Override protected void onResume() { super.onResume(); // カメラを開く mCamera = Camera.open(); cameraCurrentlyLocked = defaultCameraId; mPreview.setCamera(mCamera); } @Override protected void onPause() { super.onPause(); // カメラを停止する if (mCamera != null) { mPreview.setCamera(null); mCamera.release(); mCamera = null; } }
6行目 mCameraインスタンスはandroid.hardware.Cameraクラスです。18行目 mCameraがnullでなければリソースを取得していますので、必ずonPause時に解放(Releaseメソッド)するようにしましょう。
カメラプレビューの取得と保存
最後に、プレビュー画像を取得するためにPreviewクラスを変更します。
画像データを取得するtakePreviewRawDataメソッドを作成します。
■src/CameraPreviewsActivity.java
class Preview extends ViewGroup implements SurfaceHolder.Callback { ...省略... private boolean mProgressFlag = false; public void takePreviewRawData() { if (!mProgressFlag) { mProgressFlag = true; mCamera.setPreviewCallback(editPreviewImage); //プレビューコールバックをセット } }
8行目 CameraクラスのsetPreviewCallbackメソッドはプレビューする度に呼ばれるコールバックメソッドです。PreviewCallbackを設定すると、毎プレビューごとに画像データを取得できます。
以下のサンプルコードは、プレビュー時のコールバックの内容になります。
editPreviewImage内部の処理で画像を保存しています。保存した画像はjpegなど一般的なフォーマットではなく、搭載されたカメラ制御デバイスに依存し、YUVデータなどハードウェアデバイスごとに最適化された生データになります。
これらはAndroid端末ごとに異なる可能性があり、互換性の少ない固有のフォーマット(Sony Xperia arcなどはYUVデータですが、色の格納順番が異なります)になります。
■src/CameraPreviewsActivity.java
private final Camera.PreviewCallback editPreviewImage = new Camera.PreviewCallback() { public void onPreviewFrame(byte[] data, Camera camera) { mCamera.setPreviewCallback(null); // プレビューコールバックを解除 mCamera.stopPreview(); // 画像の保存処理 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MMddHH_mmss_SSS"); // 画像を保存 String path = Environment.getExternalStorageDirectory().getPath() + '/' + dateFormat.format(new Date()) + ".raw"; FileOutputStream fos = null; try { fos = new FileOutputStream(path); fos.write(data); fos.close(); } catch (IOException e) { Log.e("CAMERA", e.getMessage()); } mCamera.startPreview(); mProgressFlag = false; } };
5行目、処理を継続しない場合は、コールバックを解除しておくといいでしょう。今回は一度かぎりの実行ということでsetPreviewCallbackメソッドにnullを設定します。
7行目から25行目にかけてプレビューを一端停止~画像処理~プレビュー再開します。プレビュー表示中に画像データ(onPreviewFrameメソッドの第1引数data)を編集すると、描画が乱れるためです。
以上で画像データの取得は完成です。お疲れ様でした!