這裏爲了介紹如何處理Camera的圖像並繪製處理的結果,舉這樣一個例子:
對一幀圖像,計算它的清晰度,然後把清晰度顯示出來。
假設有一幀1280x960的圖像,我們取中間400x400的區域,計算這塊區域的清晰度,示意圖如下:
計算清晰度的方法非常簡單,它不是我們的重點。計算的方法如圖所示:
對於圖中的這九個點,中間點的像素值*10,其他點的像素值按照途中標註的係數進行加權,然後把所有的結果相加。相加的結果的平方運算就是我們的清晰度。
代碼如下:
private long clarityCalculator(byte[] data,int width,int height){
long rest = 0;
long restF = 0;
if(width<400 || height< 400)return 0;
int startX = (width-400)/2;
int startY = (height-400)/2;
int startBase = startY*1280+startX;
for(int i=0;i<100;i+=4){
for(int j=0;j<100;j+=4){
rest = 10*data[startBase+j*width+i];
rest -= 4*data[startBase+j*width+i+1];
rest -= 4*data[startBase+(j+1)*width+j];
rest -= data[startBase+(j-1)*width+i+1];
rest -= data[startBase+(j+1)*width+i+1];
restF+=rest*rest;
}
}
return restF/10000;
}
最後除以10000是因爲這個數可能很大。
那麼我們怎麼實現這個項目呢?
第一步,獲取一幀圖像
獲取一幀圖像需要做如下事情。
首先,創建一個Surfaceview
mCameraSuface = (SurfaceView) findViewById(R.id.camera_surface);
它在佈局文件中佔滿屏幕的。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.sharenew.cameraclarity.MainActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="@+id/camera_surface"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</RelativeLayout>
其次,獲得它的Surface的holder,並給它設置事件回調接口
holder = mCameraSuface.getHolder();
holder.addCallback(this);
addCallback設置好以後,當SurfaceView裝備好了以後,就會回調下面的三個方法:
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height){
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
接下來,我們要在這三個方法中打開攝像頭並出示參數。一般的,我們會在surfaceCreated方法中打開攝像頭, surfaceChanged中設置參數並開啓預覽,在surfaceDestroyed中關閉攝像頭並釋放資源。這三個方法可能會寫成下面的樣子,更詳細的細節請參考api文檔:
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.i("jw_liu","surfaceCreated");
if(mCamera==null)
mCamera = Camera.open();
try {
mCamera.setPreviewDisplay(holder);
initCamera();
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
Camera.Size csize;
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
// Log.i("sharenew","onPreviewFrame");
csize = mCamera.getParameters().getPreviewSize();
long clarity = clarityCalculator(data,csize.width,csize.height);
mDraw.setClarity(clarity);
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i("jw_liu","surfaceChanged");
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
if(success){
initCamera();//實現相機的參數初始化
camera.cancelAutoFocus();//只有加上了這一句,纔會自動對焦。
}
}
});
}
//相機參數的初始化設置
private void initCamera()
{
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPictureFormat(PixelFormat.JPEG);
parameters.setPreviewFormat(PixelFormat.YCbCr_420_SP);
parameters.setColorEffect(Camera.Parameters.EFFECT_MONO);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);//1連續對
parameters.setPreviewSize(1280,960); // ָ
mCamera.setDisplayOrientation(0);
mCamera.setParameters(parameters);
mCamera.startPreview();
mCamera.cancelAutoFocus();// 2如果要實現連續的自動對焦,這一句必須加上
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i("jw_liu","surfaceDestroyed");
mCamera.stopPreview();
mCamera.release();
}
很重要的就是我們給camera設置了PreviewCallback回調方法,對於每一幀的圖像,都會回調這裏的onPreviewFrame方法。我們在這裏處理圖像。處理的方法就是調用我們一開始介紹的計算清晰度的方法。處理結果保存在一個View的變量中,接下來我們會在這個View中顯示清晰度。
更新繪製
我們每隔一秒鐘更新一次結果,這使用的是Handler:
Handler mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what){
case 11:
mDraw.invalidate();
mHandler.sendEmptyMessageDelayed(11,1000);
break;
}
return true;
}
});
繪製處理結果
因爲我們已經讓SurfaceView佔滿屏幕了,那麼我們怎麼繪製呢?這裏用到了Activity的addContentView方法。這個方法定義如下:
/**
* Add an additional content view to the activity. Added after any existing
* ones in the activity -- existing views are NOT removed.
*
* @param view The desired content to display.
* @param params Layout parameters for the view.
*/
public void addContentView(View view, ViewGroup.LayoutParams params) {
getWindow().addContentView(view, params);
initWindowDecorActionBar();
}
他能讓Activity顯示另一view,和已經存在的views一同被顯示。
我們添加的參數如下:
addContentView(mDraw, new ActionBar.LayoutParams(ActionBar.LayoutParams.MATCH_PARENT, ActionBar.LayoutParams.MATCH_PARENT));
添加的是一個mDraw的View,這個View就是一個普通的View,如下:
public class Draw_Tips extends View {
long clarity=0;
public Draw_Tips(Context context) {
super(context);
}
public void setClarity(long clarity){
this.clarity = clarity;
}
@Override
protected void onDraw(Canvas canvas)
{
// TODO Auto-generated method stub
Paint mPaint = new Paint();
mPaint.setTextSize(40);
mPaint.setColor(Color.BLUE);
canvas.drawText(String.valueOf(clarity),200,60,mPaint);
super.onDraw(canvas);
}
}
這樣,我們把每一幀圖像的清晰度保存在Draw_Tips 類的clarity變量中,然後使用Handler每隔一秒鐘繪製一次清晰度。整個界面如下:
最後,完整的代碼如下:
MainActivity.java
import java.io.IOException;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.hardware.Camera;
import android.hardware.Camera.CameraIrisCallback;
import android.hardware.Camera.Parameters;
import android.util.Log;
import android.view.SurfaceHolder;
public class Iris_Camera {
private static Camera myCamera;
private static Iris_Camera myInstance=null;
private Boolean isPreview=false;
private String Tag="IrisCameraManager";
public static Iris_Camera getInstance()
{
if(myInstance == null)
{
synchronized(Iris_Camera.class)
{
myInstance = new Iris_Camera();
}
}
return myInstance;
}
@SuppressWarnings("deprecation")
private Iris_Camera()
{
myCamera = Camera.open();
}
@SuppressWarnings("deprecation")
public void InitCamera(int nWorkMode,int nDisplayMode,CameraIrisCallback mIrisCallback)
{
if (isPreview && myCamera!=null)
{
myCamera.stopPreview(); //stopCamera();
}
if(null!= myCamera)
{
try
{
Parameters parameters = myCamera.getParameters();
parameters.setPictureFormat(PixelFormat.JPEG);
parameters.setPreviewFormat(PixelFormat.YCbCr_420_SP);
parameters.setColorEffect(Parameters.EFFECT_MONO);
parameters.setPreviewSize(1280, 960); // ָ
if (nDisplayMode==0)
{
parameters.set("orientation", "portrait"); //
parameters.set("rotation", 90);
myCamera.setDisplayOrientation(90);
}
else
{
parameters.set("orientation", "landscape"); //
myCamera.setDisplayOrientation(0);
}
myCamera.setParameters(parameters);
myCamera.setIrisCallback(mIrisCallback);
//myCamera.setPreviewCallback(mPreviewCallback);
myCamera.startPreview();
isPreview = true;
Camera.Size csize = myCamera.getParameters().getPreviewSize();
}
catch (Exception e)
{
e.printStackTrace();
}
}
else
{
RefreshCamera();
}
}
@SuppressWarnings("deprecation")
private void RefreshCamera()
{
if(myCamera!=null)
{
myCamera.release();
}
myCamera = Camera.open();
}
@SuppressWarnings("deprecation")
public void ReleaseCamera()
{
if(myCamera!=null)
{
myCamera.setIrisCallback(null);
myCamera.stopPreview();
Log.i(Tag,"ThomasYang Stop View finish");
isPreview =false;
myCamera.release();
myCamera=null;
}
}
@SuppressWarnings("deprecation")
public void OpenCamera(SurfaceHolder holder)
{
if(myCamera==null)
{
Log.i(Tag,"open camera");
myCamera = Camera.open();
}
try
{
if(myCamera!=null)
myCamera.setPreviewDisplay(holder);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Draw_Tips.java
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.View;
public class Draw_Tips extends View {
long clarity=0;
public Draw_Tips(Context context) {
super(context);
}
public void setClarity(long clarity){
this.clarity = clarity;
}
@Override
protected void onDraw(Canvas canvas)
{
// TODO Auto-generated method stub
Paint mPaint = new Paint();
mPaint.setTextSize(40);
mPaint.setColor(Color.BLUE);
canvas.drawText(String.valueOf(clarity),200,60,mPaint);
super.onDraw(canvas);
}
}
佈局文件-activity_mian.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.sharenew.cameraclarity.MainActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="@+id/camera_surface"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</RelativeLayout>