最終更新:
moonlight_aska 2015年04月19日(日) 18:23:04履歴
カメラのプレビュー画像を取得するには, カメラプレビューコールバック(Camera.PreviewCallback)インタフェースを利用する.
「プレビュー画像を表示する」を参照して, カメラでプレビュー画像を表示できるようにする.

- src/MainActivity.java
- SurfaceHolder.Callbackインタフェースの実装
- surfaceCreatedメソッド内で, Camera#setPreviewTextureメソッドで, SurfaceTextureを設定する. (API Level 11以上) または, Camera#setPreviewDisplayメソッドで, SurfaceHolderを設定する. (API Level 11未満)
- surfaceChangedメソッド内で, Camera#setPreviewCallbackメソッドで, プレビュー時のコールバック関数を登録する.
- Camera#startPreviewメソッドで, プレビュー表示を開始する.
- surfaceDestroyedメソッド内で, Camera#stopPreviewメソッドで, プレビュー表示を停止する.
- Camera#setPreviewCallbackメソッドで, 登録済のコールバック関数を削除する.
- Camera.PreviewCallbackインタフェースの実装
- プレビュー表示を開始すると, onPreviewFrameメソッドがコールされ, 引数のdataがフレーム画像のデータである.
- サンプルでは, プレビュー画像の明瞭度をグレースケール画像に変換し, 表示している.
- SurfaceHolder.Callbackインタフェースの実装
package com.moonlight_aska.android.camera02;
import java.io.IOException;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.SurfaceTexture;
import android.graphics.Bitmap.Config;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MainActivity extends Activity
implements SurfaceHolder.Callback, Camera.PreviewCallback {
private static int PREVIEW_WIDTH = 640;
private static int PREVIEW_HEIGHT = 480;
private Camera mCamera = null;
private SurfaceHolder mHolder = null;
private SurfaceTexture mSurface = null;
private int[] mGrayImg = null;
private Bitmap mBitmap = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SurfaceView preview = (SurfaceView)findViewById(R.id.preview_id);
mHolder = preview.getHolder();
mHolder.addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
mCamera = Camera.open();
// グレースケル画像バッファ (NV21 -> ARGB_8888)
mGrayImg = new int[PREVIEW_WIDTH * PREVIEW_HEIGHT];
mBitmap = Bitmap.createBitmap(PREVIEW_WIDTH, PREVIEW_HEIGHT, Config.ARGB_8888);
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // API Level 11以上
mSurface = new SurfaceTexture(0);
mCamera.setPreviewTexture(mSurface);
}
else {
mCamera.setPreviewDisplay(null);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
mCamera.stopPreview();
// プレビュー画面のサイズ設定
Camera.Parameters params = mCamera.getParameters();
params.setPreviewSize(PREVIEW_WIDTH, PREVIEW_HEIGHT);
mCamera.setParameters(params);
// プレビュー開始
mCamera.setPreviewCallback(this);
mCamera.startPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
// TODO Auto-generated method stub
int p;
// グレースケル画像に変換
for (int i=0; i<mGrayImg.length; i++) {
p = data[i] & 0xff;
mGrayImg[i] = 0xff000000 | p << 16 | p << 8 | p;
}
mBitmap.setPixels(mGrayImg, 0, PREVIEW_WIDTH, 0, 0, PREVIEW_WIDTH, PREVIEW_HEIGHT);
// 描画処理
Canvas canvas = mHolder.lockCanvas();
if(canvas != null){
canvas.drawBitmap(mBitmap, 0, 0, null);
mHolder.unlockCanvasAndPost(canvas);
}
}
}
- 動作例

このページへのコメント
チャゲです
前項のプレビュー画像を取得するを実際に打ち込んでみましたが動きません
開発環境:android studio 3.1です
あと、どうでもよくないですが
サンプルコードをコピペするとスペースが半角ではなく全角になります。
修正おねがいします。
お答えいただきありがとうございます。
丁寧なご説明でよく理解できました。
他の記事を拝見させていただくこともあります。
併せて感謝しております。
askaです.
byte型は8ビットの整数ですが, 符号付きの為最上位ビットが符号(+/-)を表し,
値の範囲は0〜255ではなく-128〜127となります.
byte型の負数をint型に代入する際には, 符号拡張により上位24ビットが
全て符号ビットと同じ値1で埋められ, その結果負値のままとなります.
例として, 以下をjava環境で試してみてください.
byte a = -1;
int a1 = a;
int a2 = a & 0xff;
a1とa2を16進数で表示すると, 以下のような値になります.
a1 = 0xffffffff
a2 = 0xff
今回は画像データなので, 0xffをANDして8ビットのビットデータとして扱っています.
こういうコメントを書くのは初めてです。礼儀やルールを外れているようでしたらお許しください。
私プログラム初心者です。
「プレビュー画像を取得する」を拝見させていただきました。その中(onPreviewFrame)でバイト変数に対して「&0xff」しているのですが必要性がわからないのですが教えていただけないでしょうか?
(もともと8ビットであるバイト変数に対して8ビット分有効化するということが必要なのでしょうか?)