カメラプレビューをキャプチャする
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)を編集すると、描画が乱れるためです。
以上で画像データの取得は完成です。お疲れ様でした!