检测可用的特性
// get Camera parameters
Camera.Parameters params = mCamera.getParameters();
List<String> focusModes = params.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
// Autofocus mode is supported
}
你可以对大多数相机特性使用以上所示方法.Camera.Parameters对象提供了一个getSupported...(),is...Supported()orgetMax...()方法来确定一个特性是否被支持.
如果你的应用需要特定的相机特性,你可以通过在你的应用的manifest文件中添加请求.当你声明要使用特定相机特性,比如闪光灯和自动对焦,GooglePlay就会阻止你的应用被安装到不支持这些特性的设备上.
使用相机特性
当设置要使用的相机特性时,首先要理解的是不是所有的设备都支持所有的特性.另外,一个特性可能被在不同的级别上支持或带有不同的选项.因此,当你开发一个相机应用时,需要决定支持哪些特性以及支持到什么级别.当决定之后,你应在代码中包含检测设备是否支持所需特性,然后在不支持时要有优雅的錯误处理.
你可以通过获取一个相机参数对象的实例来检测,并且检测相关的方法们.下面的代码向你展示了如何得到一个Camera.Parameters对象并检测是否支持自动对焦特性:
大多数相机特性都可以通过Camera.Parameters进行管理.你要获取此对象,首先获取一个相机对象的实例,然后调用getParameters()方法.改变所获取的parameter对象,然后把它设置回相机对象,就像下面所演示的:
// 获取Camera parameters
Camera.Parameters params = mCamera.getParameters();
// 设置聚焦模式
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// 设置Camera parameters
mCamera.setParameters(params);
此方法对于绝大多数相机特性都有效,并且大多数参数可以在任何时刻进行改变.对于参数的改变通常都是马上在应用的相机预览中表现出来.在软件解度看,参数的改变可能经过多帧后才能生效,因为硬件要处理新的指令然后发送更新的图像数据.
重要:一些相机特性不能被任务改变.特别的,改变相机预览的大小或方向需要你首先停止预览,改变预览大小或方向,然后重启预览.从Android4.0(APILevel14),预览方向可以不用重启而改变.
其它的相机特性需要更多的代码,包括:
lMeteringandfocusareas
lFacedetection
limelapsevideo
测光与聚焦区域
在一些情况下摄像,自动对焦和测光不能产生期望的结果.从Android4.0(APILevel14)开始,你的相机应用可以提供额外的控制,允许你的应用或用户指定图像中的某块区域进行聚焦或曝光级别设置,然后把这些值传给相机,以应用于抓取像片或录制视频.
测光和聚焦区域的工作方式与其它相机特性十分相似,你通过Camera.Parameters对象控制它们.下面的代码演示了为一个相机实例设置两个测光区域:
//创建一个相机实例
mCamera = getCameraInstance();
// 设置相机参数们
Camera.Parameters params = mCamera.getParameters();
if (params.getMaxNumMeteringAreas() > 0){ // 检查是否支持测光区域
List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
Rect areaRect1 = new Rect(-100, -100, 100, 100); // 在图像的中心指定一个区域
meteringAreas.add(new Camera.Area(areaRect1, 600)); // 设置宽度到60%
Rect areaRect2 = new Rect(800, -1000, 1000, -800); // 在图像的右上角指定一个区域
meteringAreas.add(new Camera.Area(areaRect2, 400)); // 收置宽度为40%
params.setMeteringAreas(meteringAreas);
}
mCamera.setParameters(params);
Camera.Area对象包含两个数据参数:一个Rect对象指定了相机视口中的一块区域,还有一个宽度,告诉相机在测光或聚焦计算中此区域的重要程度.
Camera.Area对象的Rect字段描述了一个矩形区域在一个2000x2000个单元格组成的区域中的映射位置.坐标-1000,-1000代表了top,left,并且坐标1000,1000代表了bottom,right,如下面示意图所示:
图1.红线表示在相机预览中指定一个Camera.Area所在的坐标系.蓝框表示一个相机区域的位置和形状,其坐标值为:333,333,667,667.
此坐标系的边界总是与相机预览图像的外边界一至,并且不会随着变焦变大或变小.同样的,使用Camera.setDisplayOrientation()旋转预览图像也不会改变做标系.
人脸检测
对于包含人的图像,脸往往是图像中最重要的部分,并且在拍照时,脸部被用于对焦和白平衡.Android4.0(APILevel14)框架提供了识别面部的和跟据其计算图像设置的API们.
注:当启用面部检测特性时,setWhiteBalance(String),setFocusAreas(List)和setMeteringAreas(List)不再起作用.
使用面部检测特性通常需要以下几步:
l检查设备是否支持面部检测
l创建一个面部检测监听器
l添加面部检测监听器到你的相机对象.
l预览开始后开始面部检测(并且每次重启预览后同样)
面部检测特性不是在所有的设备上都支持.你可以调用getMaxNumDetectedFaces()来检测是否支持.
为了接收到面部检测的通知并作出响应,你的相机应用中必须为面部检测事件设置一个监听器.所以你必须创建一个监听类,它实现Camera.FaceDetectionListener接口,如下代码所示:
class MyFaceDetectionListener implements Camera.FaceDetectionListener {
@Override
public void onFaceDetection(Face[] faces, Camera camera) {
if (faces.length > 0){
Log.d("FaceDetection", "face detected: "+ faces.length +
" Face 1 Location X: " + faces[0].rect.centerX() +
"Y: " + faces[0].rect.centerY() );
}
}
}
创建此类后,你就可以把它设置给你的应用的相机对象,如下代码所示:
mCamera.setFaceDetectionListener(new MyFaceDetectionListener());
你的应用必须在每次启动(或重启)预览时启动面部检测.创建一个方法专用于开启面部检测,你便可以在需要时调用它,如下例如示:
public void startFaceDetection(){
// Try starting Face Detection
Camera.Parameters params = mCamera.getParameters();
// start face detection only *after* preview has started
if (params.getMaxNumDetectedFaces() > 0){
// camera supports face detection, so can start it:
mCamera.startFaceDetection();
}
}
你必须在每次开始(或重启)预览时开启脸部检测.如果你使用"创建一个预览类"一节中的预览类,把你的 startFaceDetection() 方法添加到你的预览类的 surfaceCreated() 和 surfaceChanged() 方法中,如下面代码所示:
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
startFaceDetection(); // start face detection feature
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (mHolder.getSurface() == null){
// preview surface does not exist
Log.d(TAG, "mHolder.getSurface() == null");
return;
}
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
Log.d(TAG, "Error stopping camera preview: " + e.getMessage());
}
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
startFaceDetection(); // re-start face detection feature
} catch (Exception e){
// ignore: tried to stop a non-existent preview
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
注:记住在调用startPreview()后要调用此函数.不要试图在你的应用的actvitiy的onCreate()中启动脸部检测,因为此时预览还没有启动呢.