最近一周都在做文通車號識別的調(diào)研和測試工作,這里除了文通SDK集成相關(guān)的東西外,主要都是android攝像頭相關(guān)的知識,包括獲取當(dāng)前手機支持的預(yù)覽和拍照尺寸,實現(xiàn)Camera的預(yù)覽,以及相應(yīng)數(shù)據(jù)的采集和轉(zhuǎn)換
??1.Camera所對應(yīng)的屬性(支持的預(yù)覽和拍照尺寸):
Camera camera = Camera.open();
if(camera !=null) {
Camera.Parameters parameters = camera.getParameters();
List<Camer.size> previewSizes = parameters.getSupportedPreviewSizes();
List<Camera.size> PictureSizes = parameters.getSupportedPictureSizes();
Camera.Size size;}
previewSizes獲取的就是當(dāng)前支持的預(yù)覽尺寸PictureSize就是支持的拍照尺寸,這里要注意預(yù)覽尺寸和照片尺寸都不止一個而且手機不通支持的尺寸也是不一樣的
** 2.實現(xiàn)攝像預(yù)覽:**
** 攝像預(yù)覽主要是用到了SurfaceView來進(jìn)行展示Camera捕獲的圖像**
** 涉及到的類SurfaceHolder**
SurfaceHolder holder=surfaceView.getHolder(); //幫定 surfaceview的holder
holder.addCallback(context);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
//需要實現(xiàn)的幾個方法
public voidsurfaceCreated(SurfaceHolder holder) //surfaceview創(chuàng)建時會回調(diào)的方法
public voidsurfaceChanged(finalSurfaceHolder holder, intformat, intwidth, intheight)//當(dāng)surfaceview發(fā)生變化時的回調(diào)
public voidsurfaceDestroyed(SurfaceHolder holder)//surface銷毀
//識別sdk中的代碼,以后做個參考
@Override
public voidsurfaceCreated(SurfaceHolder holder) {
if(camera==null) {
try{
camera= Camera.open();
}catch(Exception e) {
e.printStackTrace();
return;
}
}
try{
camera.setPreviewDisplay(holder);//可以理解 為將surfaceview和 camera綁定到一起,這樣camera的數(shù)據(jù)就會顯示到綁定的holder的 surfaceview上,并且相應(yīng)的數(shù)據(jù)通過 onPreviewFrame(byte[] data,Camera camera)的回調(diào)就能夠獲取到
initCamera(holder,rotation);
re.addView(myview);
if(timer==null) {
timer=newTimerTask() {
public voidrun() {
// isSuccess=false;
if(camera!=null) {
try{
camera.autoFocus(newAutoFocusCallback() {
public voidonAutoFocus(booleansuccess,Camera camera) {
// isSuccess=success;
}
});
}catch(Exception e) {
e.printStackTrace();
}
}
}
;
};
}
time.schedule(timer,500,2500);//延遲0.5秒,2.5秒一次的自動對焦
}catch(IOException e) {
e.printStackTrace();
}
}
@Override
public voidsurfaceChanged(finalSurfaceHolder holder, intformat, intwidth, intheight) {
if(camera!=null) {
try{
camera.autoFocus(newAutoFocusCallback() {
@Override
public voidonAutoFocus(booleansuccess,Camera camera) {
if(success) {
synchronized(camera) {
newThread() {
public voidrun() {
initCamera(holder,rotation);
super.run();
}
}.start();
}
}
}
});
}catch(Exception e) {
//TODO: handle exception
}
}
}
@Override
public voidsurfaceDestroyed(SurfaceHolder holder) {
try{
if(camera!=null) {
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
camera=null;
}
}catch(Exception e) {
}
}
Camera.Parameters parameters =camera.getParameters();//參數(shù)設(shè)置
parameters.setPictureFormat(PixelFormat.JPEG);//設(shè)置圖片格式
parameters.setPreviewSize(preWidth,preHeight);//設(shè)置預(yù)覽的尺寸,這里就用到之前獲取的支持預(yù)覽的尺寸,根據(jù)自己的需求來進(jìn)行選擇
camera.setParameters(parameters);
camera.setDisplayOrientation(r);//這里有一個小坑,我這里當(dāng)時只想驗證豎屏情況下的識別,所以直接設(shè)置角度為90度,然后相機第一次怎么連接都是失敗,然后再重新打開就沒有問題了...后來是做了camera.stopPreview();
//camera.setPreviewCallback(null);然后在從新設(shè)置PreviewCallback就可以直接打來了
camera.setPreviewDisplay(holder);
camera.setPreviewCallback(MemoryCameraActivity.this);//這里就是設(shè)置預(yù)覽數(shù)據(jù)的回調(diào)
camera.startPreview();//開啟預(yù)覽
//這里攝像頭還是使用的舊Api,主要是為了兼容嘛,新的Api為Camera2
@Override
public voidonPreviewFrame(byte[] data,Camera camera) { //Camera的Preview的回調(diào)
//實時監(jiān)聽屏幕旋轉(zhuǎn)角度
intuiRot = getWindowManager().getDefaultDisplay().getRotation();//獲取屏幕旋轉(zhuǎn)的角度
if(uiRot !=tempUiRot) {
System.err.println("uiRot:"+ uiRot);
Message mesg =newMessage();
mesg.what= uiRot;
handler.sendMessage(mesg);
tempUiRot= uiRot;
}
if(setRecogArgs) {
Intent authIntent =newIntent(MemoryCameraActivity.this,RecogService.class);
bindService(authIntent,recogConn,Service.BIND_AUTO_CREATE);
setRecogArgs=false;
}
if(iInitPlateIDSDK==0) {
nums++;
if(nums==1) {
nums= -1;
prp.height=preHeight;//
prp.width=preWidth;//
prp.picByte= data;
picData= data;
// prp.isCheckDevType = true;
//開發(fā)碼
prp.devCode= Devcode.DEVCODE;
if(rotation==0) {
//通知識別核心,識別前圖像應(yīng)先旋轉(zhuǎn)的角度
prp.plateIDCfg.bRotate=0;
setHorizontalRegion();
}else if(rotation==90) {
prp.plateIDCfg.bRotate=1;
setLinearRegion();
}else if(rotation==180) {
prp.plateIDCfg.bRotate=2;
setHorizontalRegion();
}else if(rotation==270) {
prp.plateIDCfg.bRotate=3;
setLinearRegion();
}
// System.out.println("實際區(qū)域" + preWidth +
// " " + preHeight);
// System.out.println("邊長:"+ViewfinderView.length*2);
// System.out.println("敏感區(qū)域:" +
// prp.plateIDCfg.left + " "
// + prp.plateIDCfg.right + " " +
// prp.plateIDCfg.top
// + " " + prp.plateIDCfg.bottom);
if(isCamera) {
//進(jìn)行授權(quán)驗證 并開始識別
fieldvalue=recogBinder.doRecogDetail(prp);
nRet=recogBinder.getnRet();
if(nRet!=0) {
String[] str = {""+nRet};
getResult(str);
}else{
getResult(fieldvalue);
intentNV21data= data;
}
}
}
}
}
3.獲取的數(shù)據(jù)轉(zhuǎn)換:
//android攝像頭獲取的數(shù)據(jù)為NV21的格式,我們要使用的話,需要將這個數(shù)據(jù)轉(zhuǎn)為jpeg,bitmap啊之類的,這里用到的是Android的提供的YuvImage類
ByteArrayOutputStream baos =newByteArrayOutputStream();
YuvImage yuvimage =newYuvImage(tempData,ImageFormat.NV21,Width,Height, null);//預(yù)覽時獲取的數(shù)據(jù),數(shù)據(jù)的格式,寬,高
yuvimage.compressToJpeg(newRect(0,0,Width,Height),100,baos);//轉(zhuǎn)為jpeg的流
bitmap= BitmapFactory.decodeByteArray(baos.toByteArray(),0,baos.size(),options);
//流到bitmap
4.這里在加一個閃光燈的操作:
if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) {//沒有閃光燈
Toast.makeText(MemoryCameraActivity.this,
getResources().getString(
getResources().getIdentifier("no_flash","string",
getPackageName())),Toast.LENGTH_LONG).show();
}else{
if(camera!=null) {
Camera.Parameters parameters =camera.getParameters();
String flashMode = parameters.getFlashMode();
if(flashMode.equals(Camera.Parameters.FLASH_MODE_TORCH)) {
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
parameters.setExposureCompensation(0);
}else{
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);//閃光燈常亮
parameters.setExposureCompensation(-1);
}
try{
camera.setParameters(parameters);
}catch(Exception e) {
Toast.makeText(MemoryCameraActivity.this,
getResources().getString(
getResources().getIdentifier("no_flash",
"string",getPackageName())),
Toast.LENGTH_LONG).show();
}
camera.startPreview();
}
}
```