AndroidCamera-TouchToFocusMeteringZoom
AndroidCamera-TouchToFocusMeteringZoom copied to clipboard
后置摄像头聚焦位置与实际点击位置不符合
后置摄像头聚焦位置与实际点击位置不符合,需要做更进一步的坐标系变换
我在此代码基础上做了一定改动,有需要的同学可以自取。
仅三个函数有改动
private void handleFocusMetering(MotionEvent event, Camera camera) {
int viewWidth = getWidth();
int viewHeight = getHeight();
Camera.Parameters parameters = camera.getParameters();
android.hardware.Camera.CameraInfo camInfo =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, camInfo);
int displayOrientation = camInfo.orientation;
boolean mirror = (camInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT ? true : false); //
Rect focusRect = calculateTapArea(event.getX(), event.getY(), 1f, viewWidth, viewHeight, mirror, displayOrientation);
Rect meteringRect = calculateTapArea(event.getX(), event.getY(), 2.0f, viewWidth, viewHeight, mirror, displayOrientation);
Log.i(TAG, String.format("handleFocusMetering: mirror=%s,displayOrientation=%s,focusRect=%s", mirror, displayOrientation, focusRect.toString()));
camera.cancelAutoFocus();
Camera.Parameters params = camera.getParameters();
if (params.getMaxNumFocusAreas() > 0) {
List<Camera.Area> focusAreas = new ArrayList<>();
focusAreas.add(new Camera.Area(focusRect, 800));
params.setFocusAreas(focusAreas);
} else {
Log.i(TAG, "focus areas not supported");
}
if (params.getMaxNumMeteringAreas() > 0) {
List<Camera.Area> meteringAreas = new ArrayList<>();
meteringAreas.add(new Camera.Area(meteringRect, 800));
params.setMeteringAreas(meteringAreas);
} else {
Log.i(TAG, "metering areas not supported");
}
final String currentFocusMode = params.getFocusMode();
params.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);
camera.setParameters(params);
camera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
Camera.Parameters params = camera.getParameters();
params.setFocusMode(currentFocusMode);
camera.setParameters(params);
}
});
}
private static Rect calculateTapArea(float x, float y, float coefficient, int width, int height, boolean mirror, int displayOrientation) {
float focusAreaSize = 300;
int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue();
int centerX = (int) (x / width * 2000 - 1000);
int centerY = (int) (y / height * 2000 - 1000);
int halfAreaSize = areaSize / 2;
RectF rectF = new RectF(clamp(centerX - halfAreaSize, -1000, 1000)
, clamp(centerY - halfAreaSize, -1000, 1000)
, clamp(centerX + halfAreaSize, -1000, 1000)
, clamp(centerY + halfAreaSize, -1000, 1000));
Matrix matrix = new Matrix();
prepareMatrix(matrix, mirror, displayOrientation);
matrix.mapRect(rectF);
return new Rect(Math.round(rectF.left), Math.round(rectF.top), Math.round(rectF.right), Math.round(rectF.bottom));
}
public static void prepareMatrix(Matrix matrix, boolean mirror, int displayOrientation) {
if (matrix == null) {
return;
}
Matrix _matrix = new Matrix();
matrix.reset();
// Need mirror for front camera.
_matrix.setScale(mirror ? -1 : 1, 1);
// This is the value for android.hardware.Camera.setDisplayOrientation.
_matrix.postRotate(displayOrientation);
_matrix.invert(matrix);//求逆矩阵
}
private static int clamp(int x, int min, int max) {
if (x > max) {
return max;
}
if (x < min) {
return min;
}
return x;
}
参考 谷歌官方相机https://android.googlesource.com/platform/packages/apps/Camera 项目中的FocusOverlayManager
另外发现好多手机前置摄像头都不支持对焦,也就是走了 Log.i(TAG, "focus areas not supported");这条分支。
另外,请注意上述代码没有在生成环境中稳定使用,对于可能出现的问题概不负责。
谢谢你的反馈~
之前有注意到触摸对焦位置有偏移的问题,并进行了修正,但不知还存在问题,班门弄斧了。
我是发现右上角和左下角好像对换了,不过我吧xy坐标对换一下发现x轴上有镜像的情况,又做了x镜像。不过楼主的方式比较正规,我是没考虑屏幕方向了,固定竖屏