简体   繁体   English

Android相机应用:点测光

[英]Android Camera App: Spot Metering

I'm trying to implement Spot Metering using an android phone. 我正在尝试使用Android手机实现Spot Metering。 parameters.set("auto-exposure", "spot-metering"); parameters.set(“自动曝光”,“点测光”);

However, I'm a bit confused as to how the metering works. 但是,我对计量的工作方式感到有些困惑。 If I understand correctly, Spot Metering works by selecting a region that it uses to set exposure values. 如果我理解正确,Spot Metering通过选择用于设置曝光值的区域来工作。

However, when flattening the Camera.Parameters class and displaying the results, metering area was (0, 0, 0, 0, 0) [meaning it has zero width, height, and weight] while the auto-exposure setting was correctly "spot-metering". 但是,当展平Camera.Parameters类并显示结果时,计量区域为(0,0,0,0,0)[意味着它具有零宽度,高度和重量],而自动曝光设置正确“点-metering”。 In the API, however, "getMeteringAreas()" documentation says that the metering area CANNOT have zero width and height. 但是,在API中,“getMeteringAreas()”文档说计量区域的宽度和高度不能为零。

So how can I be using "spot-metering" while metering-area is size 0? 那么,当测光面积为0时,如何使用“点测光”? I tried setting the metering-area to the upper right hand corner but it didn't have any effect on exposure. 我尝试将测光区域设置在右上角,但它对曝光没有任何影响。

This leads me to believe that auto-exposure=spot-metering doesn't have anything to do with the metering areas....which is strange. 这让我相信自动曝光=点测光与测光区域没有任何关系....这很奇怪。

If that's not the case, can someone please help me understand what I'm doing wrong? 如果情况并非如此,有人可以帮助我理解我做错了什么吗? If you need more information, I'll be happy to include code. 如果您需要更多信息,我将很乐意提供代码。

If that is the case (as in, metering areas has nothing to do with spot metering), can someone help me figure out how to CHOOSE the spot that auto-exposure meters from? 如果是这种情况(如计量区域与点测光无关),有人可以帮我弄清楚如何选择自动曝光测光仪的位置吗? I think it defaults to the center. 我认为它默认为中心。

Thanks! 谢谢!

MeteringAreas parameter is for auto-focus metering. MeteringAreas参数用于自动对焦测光。

There is no Android api for the exposure metering modes. 曝光测光模式没有Android api。 You need to find proper undocumented parameter name and values to set it (for example, by dumping all parameters via native_getParameters ). 您需要找到适当的未记录的参数名称和值来设置它(例如,通过native_getParameters转储所有参数)。

For example, for the Samsung Galaxy Note 3 parameter name is metering and accepted values are center , matrix and spot . 例如,对于Samsung Galaxy Note 3参数名称是metering和接受的值是centermatrixspot So you just call set("metering", "spot"); 所以你只需要调用set("metering", "spot"); and it magically works. 它神奇地起作用。

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. 在API级别14之前,没有用于管理计量的标准API,我认为有些品牌选择自己的方式来管理它(在您的情况下:“自动曝光”关键字),但不是通过标准API。 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: parameters.flatten()中的计量区域(0,0,0,0,0)表示不支持计量区域(权重= 0),我猜getMaxNumMeteringAreas()返回0:

apps should call getMaxNumMeteringAreas() to know the maximum number of metering areas first. 应该首先调用getMaxNumMeteringAreas()来了解最大计量区域数。 If the value is 0, metering area is not supported. 如果值为0,则不支持计量区域。

By now there are few devices that support metering areas (in my experience 3/20). 到目前为止,很少有设备支持计量区域(根据我的经验3/20)。

This answer is for Camera API 1 这个答案适用于Camera API 1

First check if setting metering areas is supported on your device, using: 首先检查设备是否支持设置测量区域,使用:

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

Then, if supported, create a Rect object with your ROI (region of interest). 然后,如果支持,则使用您的ROI(感兴趣的区域)创建一个Rect对象。
You need to account for camera rotation, since on different devices cameras can be oriented differently. 您需要考虑相机的旋转,因为在不同的设备上,相机的方向可能不同。 Finding out the camera rotation is out of scope of this answer, sorry :) 找出相机旋转超出了这个答案的范围,抱歉:)

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);
}

Note that instead of using absolute values for X and Y coordinates, 请注意,不要使用X和Y坐标的绝对值,
the camera API uses coordinates from (-1000, -1000) to (1000, 1000). 相机API使用从(-1000,-1000)到(1000,1000)的坐标。

So you have to scale your Rect so that (-1000, -1000) represents the top-left corner 所以你必须缩放你的Rect,以便(-1000,-1000)代表左上角
and (1000, 1000) represents the bottom-right corner of the camera. 和(1000,1000)代表相机的右下角。

Example: if your camera preview size is 800x480 and your ROI is Rect(200, 120, 600, 360), 示例:如果您的相机预览尺寸为800x480且您的ROI为Rect(200,120,600,360),
you should create a new Rect(-500, -500, 500, 500). 你应该创建一个新的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);
}

Then finally set the new Rect as the metering area. 然后最后将新的Rect设置为计量区域。
You can set the weight for your metering area (int from 0 to 1000) which determines how much your defined area influences the final exposure calculation. 您可以设置计量区域的权重(int从0到1000),它决定了您定义的区域对最终曝光计算的影响程度。

To sum it all up: 总而言之:

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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM