Android Camera聚焦區域和測光區域的設定
阿新 • • 發佈:2019-02-08
先盜圖一張(來自安卓官網),如圖所示,無論螢幕是橫屏豎屏,預覽檢視的中心點座標一直都是(0,0),四個角的座標也都固定如圖所示,不會因為橫豎屏而發生變化。從這張圖可以看出:
1:聚焦以及測光的座標和手指觸控的螢幕真實座標所選座標系是不同的,它的值在(-1000,1000)之間變化。
2:我們觸控到的是一個點,而聚焦及測光需要反饋給相機的是一個區域,所以就要以觸控點為中心來合理的選擇一個區域。
另外要提到的一點是,聚焦及測光是相對獨立的兩個引數,可以設定不同區域,不僅如此,測光還可以同時選擇多個區域,通過權重來分配這些區域的測光比重。
既然聚焦、測光與我們的手指在螢幕上的觸控點用的不是同一個座標系,那就得通過一定方法來轉化座標,首先要做的是,給我們的預覽VIEW設定onTouch事件,獲取手指擡起時的座標位置。之後將這個座標按上圖進行座標系轉換,並以轉換後的座標點為中心擴充套件一個合適的矩形區域,然後將這個區域傳給對應的相機引數,返回給相機即可。核心程式碼如下(注意我的是固定豎屏,即AndroidManifest該頁面方向設定為portrait,橫屏時對於同一點獲取到的點選座標與此不同,但是聚焦以及測光的座標橫豎屏保持一致):
/** * 清除自動對焦 */ private static void clearCameraFocus() { camera.cancelAutoFocus(); parameters = camera.getParameters(); parameters.setFocusAreas(null); parameters.setMeteringAreas(null); try { camera.setParameters(parameters); } catch (Exception e) { Log.e(TAG, "failed to set parameters.\n" + e); } }
Rect focusRect = calculateTapArea(event.getX(), event.getY(), 1f); Rect meteringRect = calculateTapArea(event.getX(), event.getY(), 1f); // To start tap focus, should cancel auto focus first. List<Camera.Area> mFocusList = new ArrayList<>(); mFocusList.add(new Camera.Area(focusRect, 1000)); List<Camera.Area> mMeteringList = new ArrayList<>(); mMeteringList.add(new Camera.Area(meteringRect, 1000)); parameters = camera.getParameters(); parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // Setting new camera parameters to indicate focus area. if (parameters.getMaxNumFocusAreas() > 0) { // Check if it is safe to set focusArea. parameters.setFocusAreas(mFocusList); } if (parameters.getMaxNumMeteringAreas() > 0) { // Check if it is safe to set meteringArea. parameters.setMeteringAreas(mMeteringList); } camera.setParameters(parameters);
private static Rect calculateTapArea(float x, float y, float coefficient) {
int FOCUS_AREA_SIZE = 300;
// //計算點選座標點在新的座標系中的位置
Log.e(TAG, "focus position : " + x + " : " + y);
int areaSize = Float.valueOf(FOCUS_AREA_SIZE * coefficient).intValue();
int left = clamp(Float.valueOf((y / ScreenUtils.getScreenHeight()) * 2000 - 1000).intValue(), areaSize);
int top = clamp(Float.valueOf(((ScreenUtils.getScreenWidth() - x) / ScreenUtils.getScreenWidth()) * 2000 - 1000).intValue(), areaSize);
Log.d("CameraFocus", "measure width:" + previewSize.getWidth() + " measure height:" + previewSize.getHeight());
Log.d(TAG, "previewArea:" + left + " " + top + " " + (left + areaSize) + " " + (top + areaSize));
return new Rect(left, top, left + areaSize, top + areaSize);
}
/**
* 確保所選區域在合理範圍內,不會超過邊界值
*/
private static int clamp(int touchCoordinateInCameraReper, int focusAreaSize) {
int result;
if (Math.abs(touchCoordinateInCameraReper) + focusAreaSize > 1000) {
if (touchCoordinateInCameraReper > 0) {
result = 1000 - focusAreaSize ;
} else {
result = -1000 + focusAreaSize ;
}
} else {
result = touchCoordinateInCameraReper - focusAreaSize / 2;
}
return result;
}