前段時間,需要開發一個人臉識別的程序,實現如下功能:程序通過攝像機實時獲取圖像,但是不直接顯示獲取的圖像,而是顯示處理過後的圖像。
就這個如何不顯示處理前只顯示處理後的圖像,糾結了很久,網上搜索了很多,對於這個問題,網上的信息都是重複無用的,根本無法解決。接下來我詳細的說明遇見的問題和解決方法。
一開始程序見程序段1,這麼寫的話,屏幕上面只會顯示攝像頭獲取到的圖片,處理過後的圖片完全不會顯示,後面要是強行的向這個surfaceholder控制的surfaceview來輸出圖片,程序會報錯。
public void surfaceCreated(SurfaceHolder holder) {
//開啓相機
camera=Camera.open();
try
{
camera.setPreviewDisplay(surfaceholder);
ShowMessage("開啓相機成功");//toast提示
}
catch(Exception e)
{
ShowMessage("開啓相機失敗");//toast提示
camera.release();
camera=null;
}
}//程序段1
後來發現可能是camera.setPreviewDisplay(surfaceholder)這句有問題,相機一直在用這個holder像surfaceview輸出圖像,後面程序中再使用surfaceholder來繪製新的圖片,就會衝突,然後報錯。
也試過用兩個重疊的surfaceview來實現,一個給相機用,一個給處理後的圖片用,通過程序控制將其中給相機用的那個隱藏掉,但是這麼做行不通,後面再說爲什麼不行。也嘗試過camera.setPreviewDisplay(null);這麼寫的話,在模擬器中是可以運行的,但是到了真機上面就不行了。在真機上,這兩種辦法都不會調用 onPreviewFrame(byte[] data, Camera arg1) ,查資料發現,android的相機獲取的圖片必須有一個surfaceview來顯示,否則就不會調用 onPreviewFrame(byte[] data, Camera arg1) 方法。看到這裏都會都會覺得Android好神煩。
在較新的apk版本中可以用camera.setPreviewTexture(surfacetexture)來替代camera.setPreviewDisplay(surfaceholder)。camera.setPreviewTexture(surfacetexture)這個方法允許相機將獲取的圖片在一個隱藏的surfacetexture上顯示,這麼一來,便可以實現一開始提到的那個功能。
下面是一個基本的框架:
package com.example.atest01;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.graphics.YuvImage;
import android.graphics.drawable.BitmapDrawable;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.os.Bundle;
import android.app.Activity;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.Menu;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;
public class MainActivity extends Activity implements SurfaceHolder.Callback {
SurfaceHolder surfaceholder;
SurfaceView surfaceview;
Canvas canvas;
Camera camera;
SurfaceTexture surfacetexture;
int counter=0;
int width,height,sum;
Bitmap img1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
img1=((BitmapDrawable)getResources().getDrawable(R.drawable.ic_launcher)).getBitmap();
surfaceview=(SurfaceView)findViewById(R.id.sv1);
//獲得控件 添加surfaceholder
surfaceholder=surfaceview.getHolder();
surfaceholder.addCallback(this);
surfacetexture=new SurfaceTexture(10);
//surfaceholder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
//獲得屏幕的長寬像素點數,這邊的長寬像素要修改,不然會報錯,
//因爲有的機型的長寬像素點數,不是setpreviewSize支持的長寬。
DisplayMetrics dm=new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
width=dm.widthPixels;
height=dm.heightPixels;
sum=width*height;
/*/顯示屏幕的長寬像素點數
String s=Integer.toString(width)+"\n"+Integer.toString(height);
ShowMessage(s);//*/
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void ShowMessage(String text)
{
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
Camera.Parameters parameters=camera.getParameters();
parameters.setPictureSize(width, height);
parameters.setPreviewSize(width, height);
previewcallback pre = new previewcallback();//建立預覽回調對象
camera.setPreviewCallback(pre);
//camera.setPreviewCallback(pre); //設置預覽回調對象
camera.setParameters(parameters);
camera.startPreview();
ShowMessage("開啓相機成功22323");
counter++;
ShowMessage(Integer.toString(counter));
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
//開啓相機
camera=Camera.open();
try
{
camera.setPreviewTexture(surfacetexture);
ShowMessage("開啓相機成功");
}
catch(Exception e)
{
ShowMessage("開啓相機失敗");
camera.release();
camera=null;
}
}
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
camera.stopPreview();
camera.release();
camera=null;
}
class previewcallback implements Camera.PreviewCallback
{
byte tmp;
public previewcallback()
{
}
@Override
public void onPreviewFrame(byte[] data, Camera arg1) {
// TODO Auto-generated method stub
//ShowMessage("開啓相機成功qwe");
try
{
ShowMessage("here go");
}
catch(Exception e)
{
ShowMessage("Err 001");
e.printStackTrace();
}
//*///此代碼顯示出每次都在調用這個onPreviewFrame方法
}
}
}