使用Android camera2 API,即使所有曝光参数都相同,不同的设备也会产生不同的曝光图像

问题描述

我的代码设置了所有曝光特征。
两个问题:

  1. 当我在Pixel 3(Android 10)上运行代码时,与在OnePlus 6T(Android 9.0)上捕获的同一场景相比,生成的图像几乎要 2亮。检查生成 EXIF数据,在两张图像中显示相同的曝光设置。

  2. 我试图通过设置tonemmap曲线来强制伽玛曲线,认为这可能是差异的根源,但这似乎不适用于任何一种设备(基于将伽玛设置为1,这应该导致非常平坦的图像)。

任何/所有建议都欢迎!我被困住了。

    set(requestBuilder,CaptureRequest.CONTROL_MODE,CONTROL_MODE_AUTO );
set(requestBuilder,CaptureRequest.CONTROL_CAPTURE_INTENT,CONTROL_CAPTURE_INTENT_MANUAL);
set(requestBuilder,CaptureRequest.CONTROL_AE_MODE,CONTROL_AE_MODE_OFF);
set(requestBuilder,CaptureRequest.FLASH_MODE,CaptureRequest.FLASH_MODE_OFF);
set(requestBuilder,CaptureRequest.SENSOR_EXPOSURE_TIME,(long) (exposureSettings.shutterSpeed * nanosPerSecond));
set(requestBuilder,CaptureRequest.LENS_APERTURE,exposureSettings.fStop);
set(requestBuilder,CaptureRequest.SENSOR_SENSITIVITY,Math.round(exposureSettings.iso));
setGamma(requestBuilder,1.0f); //fixme:
set(requestBuilder,CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION,0);
set(requestBuilder,CaptureRequest.CONTROL_AF_MODE,CONTROL_AF_MODE_OFF);
set(requestBuilder,CaptureRequest.LENS_FOCUS_disTANCE,0.0f);// infinity
set(requestBuilder,CaptureRequest.CONTROL_AWB_MODE,CONTROL_AWB_MODE_DAYLIGHT);
set(requestBuilder,CaptureRequest.LENS_FOCAL_LENGTH,availableFocalLengths[0]);//todo:support multiple focal lengths.
requestBuilder.addTarget(imageCaptureSurface);
imageCaptureRequest = requestBuilder.build();
//
//
public <T> void set(@NonNull CaptureRequest.Builder requestBuilder,@NonNull CaptureRequest.Key<T> key,T value)
{ Log.d(TAG,String.format("requestBuilder.set(key:%s = %s)",key.getName(),value));
    requestBuilder.set(key,value);
}
//
static CaptureRequest.Builder setGamma(CaptureRequest.Builder builder,float gamma)
{ int curveSize = 16;
    builder.set(CaptureRequest.TONEMAP_MODE,CaptureRequest.TONEMAP_MODE_CONTRAST_CURVE);
    setToneMapCurves(builder,gammaCurve(gamma,curveSize),//red
                                     gammaCurve(gamma,//green
                                     gammaCurve(gamma,curveSize)); //blue all same.
    return builder;
}
//
static CaptureRequest.Builder setToneMapCurves(CaptureRequest.Builder builder,float[] redCurve,float[] greenCurve,float[] blueCurve)
{ TonemapCurve toneMapCurve = new TonemapCurve(redCurve,greenCurve,blueCurve);
    builder.set(CaptureRequest.TONEMAP_CURVE,toneMapCurve);
    return builder;
}
//
private static float[] gammaCurve(float gamma,int numPoints)
{ int idx = 0;
    Log.i(TAG,String.format("Using gamma of %f to build tone map curve.",gamma));
    if (gamma > 0)
        {   float curve[] = new float[numPoints*2];//
            for (float inValue = 0f; inValue <= 1.0f; inValue += 1.0f / (numPoints - 1))
                {
                    curve[idx++] = inValue;
                    curve[idx++] = (float) Math.pow(inValue,gamma);
                    if (debug)
                        Log.d(TAG,String.format("Added tone curve point [%d]:(%f,%f)",idx - 2,inValue,curve[idx - 1]));
                }
            return curve;
        }

    // sRGB curve approximates gamma = 1/2.2,with small linear front.
    if (gamma == -1.0f) //sRGB
        {   float curve[] =
                { 0.0000f,0.0000f,//stick the small linear section in here
                    0.0667f,0.2864f,0.1333f,0.4007f,0.2000f,0.4845f,0.2667f,0.5532f,0.3333f,0.6125f,0.4000f,0.6652f,0.4667f,0.7130f,0.5333f,0.7569f,0.6000f,0.7977f,0.6667f,0.8360f,0.7333f,0.8721f,0.8000f,0.9063f,0.8667f,0.9389f,0.9333f,0.9701f,1.0000f,1.0000f
                };
            return curve;
        }
    return null;
}

解决方法

您没有设置ISO sensitivity value,因此这两个设备上的默认设置可能不同。此外,OnePlus 6T的相机光圈为f / 1.7,而Pixel 3的光圈为f / 1.8。

这些都是固定光圈设备,因此即使在相同的曝光和感光度设置下,它们也会在两个图像之间引入1.8 ^ 2 / 1.7 ^ 2 = 1.12x的亮度差。

后处理也可能是一个因素,因此最好的比较是与RAW输出。如果设备执行自动HDR或类似处理,但采用手动控制,则不太可能会出现这种情况。