My code sets all the exposure characteristics.
Two issues:

  1. When I run the code on a Pixel 3 (Android 10), the resulting image appears nearly 2 stops lighter than the same scene captured on an OnePlus 6T (Android 9.0). Inspection of the resulting EXIF data shows identical exposure settings in both images.

  2. I tried to force the gamma curve by setting tonemmap curves, thinking that may be the source of the difference, but that does not seem to work on either device (based on setting gamma to 1, which should lead to a very flat image).

Any / all suggestions are welcome! I am STUMPED.

    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,curveSize), //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;
}
1

There are 1 answers

0
Eddy Talvala On

You're not setting the ISO sensitivity value, so that may have a different default on the two devices. In addition, the OnePlus 6T has a camera aperture of f/1.7, while the Pixel 3 aperture is f/1.8.

These are both fixed-aperture devices, so they will introduce a 1.8^2/1.7^2 = 1.12x brightness difference between the two images, even with identical exposure and sensitivity settings.

Post-processing can also be a factor, so the best comparison would be with RAW output. Mainly this would be a concern if the device implements automatic HDR or similar processing, but with manual control, that's unlikely.