android 呼叫Camera,獲取預覽幀中的影象
阿新 • • 發佈:2019-02-10
1:說明
android開發實現Camera自定義的話,也並不是件難事,主要步驟如下:
- 開啟相機,即例項化Camera物件,Camera camera = Camera.open();
- 設定Camera的相關引數,Camera.Parameters parameters = camera.getParameters();
- 開啟預覽,camera.setPreviewDisplay(surfaceholder); camera.startPreview();
- 獲取圖片,這裡只是從預覽中獲取因此使用,camera.setPreviewCallback(new Camera.PreviewCallback(){……..});
- 停止預覽,釋放相機,camera.stopPreview();camera.release();
2:那麼問題來了,僅僅這樣就行了嗎?
當然,我們還需要顯示Camera預覽的影象的地方。因此需要一個叫做SurfaceView的控制元件,和一個用來控制顯示的SurfaceHolder的東西。步驟如下:
- 定義SurfaceView控制元件; SurfaceView mySurfaceView = (SurfaceView)findViewById(R.id.id_mySurfaceView);
- 例項化SurfaceHolder,這個是實現預覽處理的地方,相機開啟預覽的時候要設定camera.setPreviewDisplay(surfaceholder); 表明在SurfaceHolder 上面實現預覽。當然例項化是這樣實現的:SurfaceHolder surfaceHolder = mySurfaceView .getHolder();
- 給SurfaceHolder設定回撥,也就是類似於監聽,只不過它主要是監聽Camera的相關狀態;surfaceHolder.addCallback(this);
- 實現SurfaceHolder.Callback介面,類似於定於監聽就要實現相對應的監聽介面。然後就會有三個方法要實現。
3:詳細講解SurfaceHolder.Callback介面對應的三個函式:
(1) surfaceCreated方法:
@Override
public void surfaceCreated(SurfaceHolder holder) {
//一般在這裡實現相機開啟
//相機在這裡設定相關引數也是可以的
}
(2)surfaceChanged方法:
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
//在這裡也可以設定Camera的引數
}
(3)surfaceDestroyed方法:
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
//主要在這裡實現Camera的釋放
if (camera!=null) {
camera.release();
camera=null;
}
}
4:在哪裡獲取圖片呢?
這要是我們的主要任務,不獲取圖片貌似我們也沒有必要開啟相機哈。
可以定義一個按鈕來獲取圖片,呼叫獲取圖片的方法不就好了嘛,那麼就開始獲取預覽幀圖片的獲取的方法吧:
private void getPreViewImage() {
camera.setPreviewCallback(new Camera.PreviewCallback(){
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
Size size = camera.getParameters().getPreviewSize();
try{
YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
if(image!=null){
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, stream);
Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
//**********************
//因為圖片會放生旋轉,因此要對圖片進行旋轉到和手機在一個方向上
rotateMyBitmap(bmp);
//**********************************
stream.close();
}
}catch(Exception ex){
Log.e("Sys","Error:"+ex.getMessage());
}
}
});
}
這裡就是圖片旋轉函式:
public void rotateMyBitmap(Bitmap bmp){
//*****旋轉一下
Matrix matrix = new Matrix();
matrix.postRotate(90);
Bitmap bitmap = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888);
Bitmap nbmp2 = Bitmap.createBitmap(bmp, 0,0, bmp.getWidth(), bmp.getHeight(), matrix, true);
//*******顯示一下
imageView.setImageBitmap(nbmp2);
};
5:到此好像圖片的預覽幀獲取也就實現了。
但是還有幾個問題:
(1)Camera的引數設定:
public void initCamera(){
//CameraID表示0或者1,表示是前置攝像頭還是後置攝像頭
camera = Camera.open(CameraID);
camera.setDisplayOrientation(90);
//引數設定
Camera.Parameters parameters = camera.getParameters();
//設定放大倍數
parameters.setZoom(12);
//開啟閃光燈 parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
//引數設定賦給Camera物件
camera.setParameters(parameters);
}
(2)獲取預覽幀問題
camera.setPreviewCallback(new Camera.PreviewCallback(){……..});
獲取的預覽幀就是攝像頭實時獲取的影象,而實際上我只是想線割一秒中獲取一張圖片而已,因此設定了
Handler handle = new Handler(){
public void handleMessage(android.os.Message msg) {
switch(msg.what){
case BUFFERTAG:
if(isGetBuffer){
getPreViewImage();
btnGetBuffer.setText("開始圖片1");
handler.sendEmptyMessageDelayed(BUFFERTAG1, 300);
}else{
camera.setPreviewCallback(null);
}
break;
case BUFFERTAG1:
camera.setPreviewCallback(null);
handler.sendEmptyMessageDelayed(BUFFERTAG, 5000);
break ;
}
};
};
(3)切換攝像頭的時候
首先將已經存在的攝像頭釋放,然後再重新開啟就可以了;
(4)關閉閃光燈的問題
就是設定Camera的對應的引數重新設定一遍就可以了。
Camera.Parameters parameters = camera.getParameters();
//開啟閃光燈
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
//關閉攝像頭 //parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(parameters);
6:結束
到這裡,就可以實現選擇性的獲取攝像頭的預覽幀的圖片了。