这里为了介绍如何处理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>