一、简介
本篇文章为对焦系列文章的第一篇:主要讲解UI坐标系和相机坐标系。后续其他相关文章如下:
相关文章:
- Camera1 对焦(二) 对焦区域计算的几种方式(Touch to Focus)
- Camera1 对焦(三) 对焦功能标准化流程
- Camera1 Parameters参数详解(二)—— 3A算法 (对焦、曝光、白平衡)
- Android AF Work Flow安卓自动对焦工作流程
- Camera.Area相关知识 -> 【Android Camera1】Camera1源码分析
【2.1】Camera.Area
- AF对焦模式相关知识 -> 【Android Camera1】Camera1 Parameters参数详解(二)—— 3A算法 (对焦、曝光、白平衡)
【2】AF对焦
二、对焦和区域测光
日常使用照片拍照有如下几种场景:
- 默认自动对焦【视频、拍照连续对焦】
- 点击某一个区域单次对焦
从 Android 4.0(API 级别 14)开始,在拍摄图片或视频时,能够在图片中指定区域,并将这些值传递给相机硬件用于控制固定区域进行对焦和测光。区域对焦和区域测光可通过Parameters对应的Key进行设置。
2.1 区域相关设置代码
/**
* <p>Gets the current focus areas. Camera driver uses the areas to decide
* focus.</p>
*
* <p>Before using this API or {@link #setFocusAreas(List)}, apps should
* call {@link #getMaxNumFocusAreas()} to know the maximum number of
* focus areas first. If the value is 0, focus area is not supported.</p>
*
* <p>Each focus area is a rectangle with specified weight. The direction
* is relative to the sensor orientation, that is, what the sensor sees.
* The direction is not affected by the rotation or mirroring of
* {@link #setDisplayOrientation(int)}. Coordinates of the rectangle
* range from -1000 to 1000. (-1000, -1000) is the upper left point.
* (1000, 1000) is the lower right point. The width and height of focus
* areas cannot be 0 or negative.</p>
*
* <p>The weight must range from 1 to 1000. The weight should be
* interpreted as a per-pixel weight - all pixels in the area have the
* specified weight. This means a small area with the same weight as a
* larger area will have less influence on the focusing than the larger
* area. Focus areas can partially overlap and the driver will add the
* weights in the overlap region.</p>
*
* <p>A special case of a {@code null} focus area list means the driver is
* free to select focus targets as it wants. For example, the driver may
* use more signals to select focus areas and change them
* dynamically. Apps can set the focus area list to {@code null} if they
* want the driver to completely control focusing.</p>
*
* <p>Focus areas are relative to the current field of view
* ({@link #getZoom()}). No matter what the zoom level is, (-1000,-1000)
* represents the top of the currently visible camera frame. The focus
* area cannot be set to be outside the current field of view, even
* when using zoom.</p>
*
* <p>Focus area only has effect if the current focus mode is
* {@link #FOCUS_MODE_AUTO}, {@link #FOCUS_MODE_MACRO},
* {@link #FOCUS_MODE_CONTINUOUS_VIDEO}, or
* {@link #FOCUS_MODE_CONTINUOUS_PICTURE}.</p>
*
* @return a list of current focus areas
*/
public List<Area> getFocusAreas() {
return splitArea(get(KEY_FOCUS_AREAS));
}
public void setFocusAreas(List<Area> focusAreas) {
set(KEY_FOCUS_AREAS, focusAreas);
}
/**
* Gets the maximum number of focus areas supported. This is the maximum
* length of the list in {@link #setFocusAreas(List)} and
* {@link #getFocusAreas()}.
*
* @return the maximum number of focus areas supported by the camera.
* @see #getFocusAreas()
*/
public int getMaxNumFocusAreas() {
return getInt(KEY_MAX_NUM_FOCUS_AREAS, 0);
}
分析:
- getMaxNumFocusAreas()获取当前Camera Lens支持对焦区域的个数。如果为0则表示不支持对焦固定的输入区域
- 通过设置focus-area来控制Camera Lens针对特定的区域进行对焦
- focus-area是一个rect。范围为【-1000,1000】,weight:【1,1000】,可参看Camera1源码分析【Java层】
【2.1】
- setFocusAreas(null) -> 交给Camera自己控制
- 和zoom值没关系。区域对应的始终是zoom=1.0x的画面。详细可参看后续Camera1对焦之zoom
2.2 代码举例
官网示例代码如下:
// Create an instance of Camera
// Create an instance of Camera
camera = getCameraInstance();
// set Camera parameters
Camera.Parameters params = camera.getParameters();
if (params.getMaxNumMeteringAreas() > 0){ // check that metering areas are supported
List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
Rect areaRect1 = new Rect(-100, -100, 100, 100); // specify an area in center of image
meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60%
Rect areaRect2 = new Rect(800, -1000, 1000, -800); // specify an area in upper right of image
meteringAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40%
params.setMeteringAreas(meteringAreas);
}
if (params.getMaxNumFocusAreas() > 0){ // check that focus areas are supported
List<Camera.Area> focusAreas = new ArrayList<Camera.Area>();
Rect areaRect1 = new Rect(-100, -100, 100, 100); // specify an area in center of image
focusAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60%
Rect areaRect2 = new Rect(800, -1000, 1000, -800); // specify an area in upper right of image
focusAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40%
params.setFocusAreas(focusAreas);
}
camera.setParameters(params);
分析
- 首先通过getMaxNumFocusAreas()和getMaxNumMeteringAreas()来判断是否支持区域对焦和区域测光。
- 设置了2个不同权重的Rect进行区域对焦和区域测光。
三、不同坐标系
3.1 相机坐标系
图一
图一中,给出了相机的坐标系,注意这里是横屏的。相机的坐标系中值的范围是[-1000,1000]
。因此在左上角是[-1000, 1000]。右下角是[1000,1000]。
图一中也给出了要设置的rect(333,333,667,667)。如果调用代码1则会在该区域对焦。如果调用代码2,则会在该区域测光AE
代码1:
************
params.setFocusAreas(new Camera.Area(rect))
代码2:
************
params.setMeteringAreas(new Camera.Area(rect))
3.2 UI坐标系
3.1我们阐述了相机坐标系,但是图是横的,实际使用手机,大部分的场景是竖直的。因此我们参看图二。
图二
图二有左右2个图,不同的orientation。这里一定要明白:
相机的输出流会和后置Camera Lens有90的的夹角;和前置Camera Lens有270度的夹角
因此在右侧整的的UI坐标系中,左上角是(0,0),右下角是(mPreviewWidth, mPreviewHeight),orientation:90度。
那么对应到相机的坐标系中,
3.1
横屏:左上角是(-1000, -1000),右下角是(1000,1000)。- 竖直:右上角是(-1000, -1000),左下角是(1000,1000)。
所以当点击某个区域对焦时,需要做的工作就是:把UI坐标系的点坐标转换成为相机坐标系下的点坐标对应的rect区域
四、总结
这里总结一下【手机竖直】
:
- UI坐标系:左上角是(0,0),右下角是(mPreviewWidth, mPreviewHeight)
- 相机坐标系:右上角是(-1000, -1000),左下角是(1000,1000)
- 点击对焦测光:Point(x, y)[ui] -> Point(x, y)[camera] -> Rect(l, t, r, b)[camera]
具体的点击对焦测光计算算法如下:
- 获取点击对应的Point(x, y)
- Point(x, y)根据相机的orient方向,来判断是否进行x, y互换【后置从UI到相机参考系需要逆时针旋转-90度】
- Point(x, y) 从(0, 0, mPreviewWidth, mPreviewHeight) => (-1000, -1000, 1000, 1000)
- Point(x, y) [camera] 根据AspectRatio和区域Size => Rect[Camera]
下一篇将讲解Camera1对焦区域具体的计算算法和相关代码。