C/C++プログラマの管理者が, Androidプログラムにチャレンジ. AndroidプログラミングのTipsをメモっていく予定です.

カメラのプレビュー画像を取得するには, カメラプレビューコールバック(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がフレーム画像のデータである.
      • サンプルでは, プレビュー画像の明瞭度をグレースケール画像に変換し, 表示している.
   注) 画像はYCbCr_420_SP (NV21)フォーマット.
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);
    }
  }
}
  • 動作例
端末:SHARP SHL-22 / Android 4.2.2




このページへのコメント

チャゲです

前項のプレビュー画像を取得するを実際に打ち込んでみましたが動きません

開発環境:android studio 3.1です

あと、どうでもよくないですが
サンプルコードをコピペするとスペースが半角ではなく全角になります。
修正おねがいします。

1
Posted by チゃゲ 2018年06月27日(水) 13:48:01 返信

お答えいただきありがとうございます。
丁寧なご説明でよく理解できました。
他の記事を拝見させていただくこともあります。
併せて感謝しております。

0
Posted by 伊奈博史 2017年05月16日(火) 09:38:42 返信

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ビットのビットデータとして扱っています.

0
Posted by  moonlight_aska moonlight_aska 2017年05月16日(火) 01:16:37 返信

こういうコメントを書くのは初めてです。礼儀やルールを外れているようでしたらお許しください。

私プログラム初心者です。

「プレビュー画像を取得する」を拝見させていただきました。その中(onPreviewFrame)でバイト変数に対して「&0xff」しているのですが必要性がわからないのですが教えていただけないでしょうか?
(もともと8ビットであるバイト変数に対して8ビット分有効化するということが必要なのでしょうか?)

0
Posted by 伊奈博史 inachi07@gmail.com 2017年05月13日(土) 11:05:24 返信

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu


逆引き(基礎編)

画面表示/操作(49)

フラグメント(1)

逆引き(応用編)

Firebase(2)

AD



管理人/副管理人のみ編集できます