3

我正在尝试使用 Android 手机实现 Spot Metering。parameters.set("自动曝光", "点测光");

但是,我对测光的工作方式有点困惑。如果我理解正确,点测光通过选择用于设置曝光值的区域来工作。

但是,在展平 Camera.Parameters 类并显示结果时,测光区域为 (0, 0, 0, 0, 0) [意味着它的宽度、高度和重量为零],而自动曝光设置正确“点” -计量”。然而,在 API 中,“getMeteringAreas()”文档说计量区域的宽度和高度不能为零。

那么,当测光面积为 0 时,如何使用“点测光”呢?我尝试将测光区域设置在右上角,但它对曝光没有任何影响。

这让我相信自动曝光=点测光与测光区域没有任何关系……这很奇怪。

如果不是这样,有人可以帮我理解我做错了什么吗?如果您需要更多信息,我很乐意提供代码。

如果是这种情况(例如,测光区域与点测光无关),有人可以帮我弄清楚如何选择自动曝光测光的点吗?我认为它默认为中心。

谢谢!

4

3 回答 3

2

MeteringAreas参数用于自动对焦测光。

曝光测光模式没有 Android api。您需要找到正确的未记录参数名称和值来设置它(例如,通过转储所有参数native_getParameters)。

例如,三星 Galaxy Note 3 的参数名称是metering,接受的值是center,matrixspot。所以你只需打电话set("metering", "spot");,它就会神奇地起作用。

于 2014-06-09T01:00:30.413 回答
1

Metering is a device-dependant matter.

Prior to API level 14 there wasn't a standard API for managing metering, I think that some brands chose their own way to manage it (in your case: "auto-exposure" keyword), but not through the standard APIs. This is why you cannot obtain a valid area. The metering area (0, 0, 0, 0, 0) in your parameters.flatten() means that metering areas are not supported (weight=0), i guess that getMaxNumMeteringAreas() returns 0:

apps should call getMaxNumMeteringAreas() to know the maximum number of metering areas first. If the value is 0, metering area is not supported.

By now there are few devices that support metering areas (in my experience 3/20).

于 2014-05-08T23:32:27.010 回答
1

此答案适用于 Camera API 1

首先检查您的设备是否支持设置测光区域,使用:

Camera.Parameters params = mCamera.getParameters();
if (params.getMaxNumMeteringAreas() > 0) {
    // Supported!
} else {
    // Not supported
}

然后,如果支持,Rect使用您的 ROI(感兴趣区域)创建一个对象。
您需要考虑相机旋转,因为在不同的设备上,相机的方向可能不同。找出相机旋转超出了这个答案的范围,对不起:)

private Rect getRotatedRect(Rect rect, int previewWidth, int previewHeight, int cameraRotation) {

    int resultLeft = rect.left;
    int resultTop = rect.top;
    int resultRight = rect.right;
    int resultBottom = rect.bottom;

    switch (cameraRotation) {
        case 90:
            resultLeft = top;
            resultTop = previewHeight - right;
            resultRight = bottom;
            resultBottom = previewHeight - left;
            break;
        case 180:
            resultLeft = previewWidth - right;
            resultTop = previewHeight - bottom;
            resultRight = previewWidth - left;
            resultBottom = previewHeight - top;
            break;
        case 270:
            resultLeft = previewWidth - bottom;
            resultTop = left;
            resultRight = previewWidth - top;
            resultBottom = right;
            break;
    }

    return new Rect(resultLeft, resultTop, resultRight, resultBottom);
}

请注意,相机 API 不使用 X 和 Y 坐标的绝对值,而是使用
从 (-1000, -1000) 到 (1000, 1000) 的坐标。

因此,您必须缩放 Rect 以便 (-1000, -1000) 代表相机的左上角
, (1000, 1000) 代表相机的右下角。

示例:如果您的相机预览尺寸为 800x480,并且您的 ROI 为 Rect(200, 120, 600, 360),
您应该创建一个新的 Rect(-500, -500, 500, 500)。

private Rect getScaledRect(Rect rect, int previewWidth, int previewHeight) {
    float widthUnit = previewWidth / 2000f;
    float heightUnit = previewHeight / 2000f;

    int adjustedLeft = Math.max((int) (rect.left / widthUnit - 1000), -1000);
    int adjustedTop = Math.max((int) (rect.top / heightUnit - 1000), -1000);
    int adjustedRight = Math.max((int) (rect.right / widthUnit - 1000), -1000);
    int adjustedBottom = Math.max((int) (rect.bottom / heightUnit - 1000), -1000);

    return new Rect(adjustedLeft, adjustedTop, adjustedRight, adjustedBottom);
}

然后最后将新的 Rect 设置为测光区域。
您可以设置测光区域的权重(int 从 0 到 1000),这决定了您定义的区域对最终曝光计算的影响程度。

总结一下:

Camera.Parameters params = mCamera.getParameters();
if (params.getMaxNumMeteringAreas() > 0) {
    // Supported!

    // Create rotated Rect
    Rect rotatedRect = getRotatedRect(yourAbsoluteCoordinatesROIRect, mPreviewSize.width, mPreviewSize.height, mCameraOrientation);

    // Scale Rect to make it appropriate for Camera API
    Rect scaledRect = getScaledRect(rotatedRect, mPreviewSize.width, mPreviewSize.height);

    // Create metering area with maximum weight
    Camera.Area meteringArea = new Camera.Area(scaledRect, 1000);

    // Create a list because setMeteringAreas() expects a List
    List<Camera.Area> meteringAreaList = new ArrayList<>();
    meteringAreaList.add(meteringArea);

    // Set metering area
    params.setMeteringAreas(meteringAreaList);
    mCamera.setParameters(params);
} else {
    // Not supported
}
于 2019-04-16T15:17:09.330 回答