自定义摄像机应用实现之预览界面展示

本文主要是Apress.Pro.Android.Media.Dec.2010书籍的读书笔记,加上自己的一些理解

要创建一个自定义的摄像机应用,就需要调用android的Camera这个类。这个类可以帮助我们调用手机的内置摄像头,并通过设置各种参数达到我们的要求,比如显示的大小,曝光度等。

摄像头权限

为了能够调用Camera类捕捉画面,我们需要在AndroidManifest.xml文件中指定权限

<uses-permission android:name="android.permission.CAMERA" />

预览界面

在布局中利用surfaceView控件来展示摄像头界面,以下是一个基本的布局(surfaceView由于可以直接从内存或者DMA等硬件接口取得图像数据,因此是个非常重要的绘图容器

 

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <SurfaceView android:id="@+id/CameraView" android:layout_width="fill_parent" android:layout_height="fill_parent"></SurfaceView> </LinearLayout>

 

在代码中利用surfaceholder来监听摄像头的创建、销毁、改变的事件
创建预览界面分一下几个步骤
1、在surfaceCreated中获取Camera对象
2、设置camera的预览监听
3、启动摄像头预览
4、在surfaceDestroyed中当控件销毁时,关闭摄像头预览,并释放资源

package com.camerademo;

import java.util.Iterator; import java.util.List;

import android.app.Activity; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.hardware.Camera; import android.os.Bundle; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.ViewGroup.LayoutParams; import android.widget.LinearLayout;

public class Main extends Activity implements SurfaceHolder.Callback{

 SurfaceView cameraView;  SurfaceHolder surfaceHolder;  Camera camera;    public static final int LARGEST_WIDTH = 300;  public static final int LARGEST_HEIGHT = 300;    @Override     public void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);         setContentView(R.layout.main);         cameraView = (SurfaceView) this.findViewById(R.id.CameraView);         surfaceHolder = cameraView.getHolder();         surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);         surfaceHolder.addCallback(this);         System.out.println("oncreate");     }

 /* (non-Javadoc)   * @see android.app.Activity#onStart()   */  @Override  protected void onStart() {   super.onStart();   System.out.println("onstart");  }    @Override  public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {   System.out.println("surfaceChanged");  }

 @Override  public void surfaceCreated(SurfaceHolder holder) {   System.out.println("surfaceCreated");   camera = Camera.open();//获取Camera对象   try{    camera.setPreviewDisplay(holder);//设置预览监听    Camera.Parameters parameters = camera.getParameters();    if(this.getResources().getConfiguration().orientation!=Configuration.ORIENTATION_LANDSCAPE){     parameters.set("orientation", "portrait");     camera.setDisplayOrientation(90);//针对android2.2和之前的版本     parameters.setRotation(90);//去掉android2.0和之前的版本    }else{     parameters.set("orientation", "landscape");     camera.setDisplayOrientation(0);     parameters.setRotation(0);    }    camera.setParameters(parameters);        int bestWidth = 0;    int bestHeight = 0;    List<Camera.Size> previewSizes = parameters.getSupportedPictureSizes();    if(previewSizes.size()>1){     Iterator<Camera.Size> cei = previewSizes.iterator();     while(cei.hasNext()){      Camera.Size aSize = cei.next();      System.out.println(aSize.width+","+aSize.height);      if(aSize.width>bestWidth  && aSize.width<=LARGEST_WIDTH        && aSize.height>bestHeight && aSize.height<=LARGEST_HEIGHT){       bestWidth = aSize.width;       bestHeight = aSize.height;      }      if(bestHeight!=0 && bestWidth != 0){       Log.v("SNAPSHOT", "Using"+bestWidth+"x"+bestHeight);       parameters.setPreviewSize(bestWidth, bestHeight);       cameraView.setLayoutParams(new LinearLayout.LayoutParams(bestWidth,bestHeight));      }     }    }

camera.startPreview();//启动摄像头预览   }catch(Exception e){    camera.release();//如果在设置摄像头的时候出现异常,在这里释放资源   }    }

 @Override  public void surfaceDestroyed(SurfaceHolder arg0) {//当要销毁时,先停止预览,并释放资源   System.out.println("surfaceDestroyed");   camera.stopPreview();   camera.release();  } }

 
这里要注意下,手机的摄像头资源是唯一的,如果你不需要再使用时,应及时释放其资源,不然会导致其应用程序无法调用摄像头的。
所以在上上面的代码中,当控件要销毁时surfacedestroyed方法中,释放了资源。在设置设置摄像头预览监听时有可能发生io异常所以用try/catch包裹camera.setPreviewDisplay(holder);方法,如果出现异常也释放资源。
刚才指介绍了创建预览界面,那么如何创建我们要求的预览界面呢,比如大小什么的,关键就在surfaccreated方法中设置camera的属性了。
1、预览界面的横竖屏展示
在进行摄像头的相关开发时,最常遇到的就是如何设置摄像头的正确方向是横向的或是竖向的。可以通过设置carmera的属性的来实现,由于官方并没有提供统一的方法进行设置,所以不同版本的设置方法都不太一样。

camera.setPreviewDisplay(holder);    Camera.Parameters parameters = camera.getParameters();    if(this.getResources().getConfiguration().orientation!=Configuration.ORIENTATION_LANDSCAPE){     parameters.set("orientation", "portrait");     camera.setDisplayOrientation(90);//针对android2.2和之前的版本     parameters.setRotation(90);//去掉android2.0和之前的版本    }else{     parameters.set("orientation", "landscape");     camera.setDisplayOrientation(0);     parameters.setRotation(0);    }    camera.setParameters(parameters);

先判断当前的界面是横向还是竖向的,针对2.2以上的版本可以设置
parameters.set("orientation", "portrait")或 parameters.set("orientation", "landscape");
2.2和之前的版本可以设置
camera.setDisplayOrientation(90)和camera.setDisplayOrientation(0)
2.0和之前的可以设置
parameters.setRotation(90) 和parameters.setRotation(0)
 
2、预览界面的效果设置
android api中可选择的颜色效果有许多种:
EFFECT_NONE 无效果
EFFECT_MONO 黑白效果
EFFECT_NEGATIVE 负面效果
EFFECT_SOLARIZE 曝光效果
EFFECT_SEPIA Sephia效果
EFFECT_POSTERIZE 多色调分色印效果

EFFECT_WHITEBOARD 白板效果
EFFECT_BLACKBOARD 黑板效果
EFFECT_AQUA 浅绿色效果
这么多的效果专业名词对于我这种非图像专业的还是看不懂啊,只有没有都试下才明白,不过要注意的是这么多效果并不是没款手机都支持的,因此我们在调用的时候应当先获取该手机支持的效果类型,再来设置,这些效果在不同的手机上还不太一样,比如在我的G7上这样设置都没有效果。如下:

List<String> colorEffects = parameters.getSupportedColorEffects();   Iterator<String> cei = colorEffects.iterator();   while(cei.hasNext()){    String currentEffect = cei.next();    System.out.println("Checking:"+currentEffect);    if(currentEffect.equals(Camera.Parameters.EFFECT_SOLARIZE)){     parameters.setColorEffect(Camera.Parameters.EFFECT_SOLARIZE);//曝光效果     break;    }   }

 
3、预览界面的大小设置
预览界面大小的设置和效果设置类似,你也必须先判断手机支持哪几种比例的大小在进行设置,不然获得的图像会变形的。如下:

int bestWidth = 0;   int bestHeight = 0;   List<Camera.Size> previewSizes = parameters.getSupportedPictureSizes();   if(previewSizes.size()>1){    Iterator<Camera.Size> cei = previewSizes.iterator();    while(cei.hasNext()){     Camera.Size aSize = cei.next();     System.out.println(aSize.width+","+aSize.height);     if(aSize.width>bestWidth  && aSize.width<=LARGEST_WIDTH       && aSize.height>bestHeight && aSize.height<=LARGEST_HEIGHT){      bestWidth = aSize.width;      bestHeight = aSize.height;     }     if(bestHeight!=0 && bestWidth != 0){      Log.v("SNAPSHOT", "Using"+bestWidth+"x"+bestHeight);      parameters.setPreviewSize(bestWidth, bestHeight);      cameraView.setLayoutParams(new LinearLayout.LayoutParams(bestWidth,bestHeight));     }    }   }

LARGEST_WIDTH 和 LARGEST_HEIGHT 为我们设置的预期的预览界面的大小比如300*300。

你可能感兴趣的:(自定义摄像机应用实现之预览界面展示)