Android Camera2 API - Set AE-regions not working - android

In my Camera2 API project for Android, I want to set a region for my Exposure Calculation. Unfortunately it doesn't work. On the other side the Focus region works without any problems.
Device: Samsung S7 / Nexus 5
1.) Initial values for CONTROL_AF_MODE & CONTROL_AE_MODE
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
2.) Create the MeteringRectangle List
meteringFocusRectangleList = new MeteringRectangle[]{new MeteringRectangle(0,0,500,500,1000)};
3.) Check if it is supported by the device and set the CONTROL_AE_REGIONS (same for CONTROL_AF_REGIONS)
if (camera2SupportHandler.cameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE) > 0) {
camera2SupportHandler.mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_REGIONS, meteringFocusRectangleList);
}
4.) Tell the camera to start Exposure control
camera2SupportHandler.mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CameraMetadata.CONTROL_AE_PRECAPTURE_TRIGGER_START);
The CONTROL_AE_STATE is always in CONTROL_AE_STATE_SEARCHING, but doesn't use the configured regions...

After long testing & development I've found an answer.
The coordinate system - Camera 1 API VS Camera 2 API
RED = CAM1; GREEN = CAM2; As shown in the image below, the blue rect are the coordinates for a possible focus/exposure area for the Cam1. By using the Cam2 API, there must be firstly queried the max of the height and the width. Please find more info here.
Initial values for CONTROL_AF_MODE & CONTROL_AE_MODE: See in the question above.
Set the CONTROL_AE_REGIONS: See in the question above.
Set the CONTROL_AE_PRECAPTURE_TRIGGER.
// This is how to tell the camera to start AE control
CaptureRequest captureRequest = camera2SupportHandler.mPreviewRequestBuilder.build();
camera2SupportHandler.mCaptureSession.setRepeatingRequest(captureRequest, captureCallbackListener, camera2SupportHandler.mBackgroundHandler);
camera2SupportHandler.mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
camera2SupportHandler.mCaptureSession.capture(captureRequest, captureCallbackListener, camera2SupportHandler.mBackgroundHandler);
The ''captureCallbackListener'' gives feedback of the AE control (of course also for AF control)
So this configuration works for the most Android phones. Unfortunately it doesn't work for the Samsung S6/7. For this reason I've tested their Camera SDK, which can be found here.
After deep investigations I've found the config field ''SCaptureRequest.METERING_MODE''. By setting this to the value of ''SCaptureRequest.METERING_MODE_MANUAL'', the AE area works also the Samsung phones.
I'll add an example to github asap.

Recently I had the same problem and finally found a solution that helped me.
All I needed to do was to step 1 pixel from the edges of the active sensor rectangle. In your example instead of this rectangle:
meteringRectangleList = new MeteringRectangle[]{new MeteringRectangle(0,0,500,500,1000)};
I would use this:
meteringRectangleList = new MeteringRectangle[]{new MeteringRectangle(1,1,500,500,1000)};
and it started working as magic on both Samsung and Nexus 5!
(note that you should also step 1 pixel from right/bottom edges if you use maximum values there)
It seems that many vendors have poorly implemented this part of documentation
If the metering region is outside the used android.scaler.cropRegion returned in capture result metadata, the camera device will ignore the sections outside the crop region and output only the intersection rectangle as the metering region in the result metadata. If the region is entirely outside the crop region, it will be ignored and not reported in the result metadata.

Related

Adjustable but consistent/raw feed from Camera X (no AE or AWB)

*Note: I figured out why the image was too dark at max SENSOR_SENSITIVITY: it was just a matter of EXPOSURE_TIME being too short, had to pump it up to 8 digits. Now all I have to do is save the values for SENSOR_SENSITIVITY and EXPOSURE_TIME. So, this question is answered, unless there's a better way?
Using Camera X (Camera2Interop) I want to turn off auto-exposure and white balance. Because I want to manually adjust the brightness, and ideally have it locked at that value until I adjust it again.
I'm not capturing an image but just working with the preview, and image analysis.
When turning CONTROL_MODE off or AE off the preview & analysis are black (unless pointed directly at light bulb), and I can get an image by adjusting SENSOR_SENSITIVITY, but the image is still too dark at maximum and has noise in it. When I modify EXPOSURE_TIME the image goes 100% black no matter what.*
Using AE_LOCK + AE_EXPOSURE_COMPENSATION instead fixes the issue of the black preview and prevents auto-correction, but isn't consistent, for I don't have a way to reset the brightness to what was set previously. For example: if I open the main camera app and go back to mine the brightness is now locked at a different value.
Camera2Interop.Extender extender = new Camera2Interop.Extender(builder);
//extender.setCaptureRequestOption(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_OFF);
//extender.setCaptureRequestOption(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION,-1);
extender.setCaptureRequestOption(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_MACRO);
//extender.setCaptureRequestOption(CaptureRequest.SENSOR_EXPOSURE_TIME,10);
//extender.setCaptureRequestOption(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF);
//extender.setCaptureRequestOption(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
extender.setCaptureRequestOption(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_OFF);
//extender.setCaptureRequestOption(CaptureRequest.SENSOR_SENSITIVITY,99999);
extender.setCaptureRequestOption(CaptureRequest.CONTROL_AWB_LOCK,true);
extender.setCaptureRequestOption(CaptureRequest.CONTROL_AE_LOCK,true);
//extender.setCaptureRequestOption(CaptureRequest.BLACK_LEVEL_LOCK,true);
Another issue is When adjusting brightness via EXPOSURE_COMPENSATION it seems to compound. For example, if it's set to -3 the image gets a little darker with every start of the application, or probably every time startCameraX is run. Perhaps this is an easy fix by moving it out of startcamera, but I was attempting to start or reset to it's previously set value.
ExposureState exposureState = camera.getCameraInfo().getExposureState();
if (!exposureState.isExposureCompensationSupported()) return;
Range<Integer> range = exposureState.getExposureCompensationRange();
int index = exposureState.getExposureCompensationIndex();
if (range.contains(1) && index != -3) {
camera.getCameraControl().setExposureCompensationIndex(-3);
}
Also, all the warning that come along with the camera2 interop extender makes it seem odd that's the official solution.
Other failed attempts: Canceling focus and metering, and set the metering point to 0x0 pixels.
camera.getCameraControl().cancelFocusAndMetering();//.setExposureCompensationIndex(12);
MeteringPointFactory meteringPointFactory = previewView.getMeteringPointFactory();
MeteringPoint meteringPoint = meteringPointFactory.createPoint(0,0, 0);
FocusMeteringAction action = new FocusMeteringAction.Builder(meteringPoint).build();
//.setAutoCancelDuration(1, TimeUnit.MICROSECONDS).build();
cameraControl.startFocusAndMetering(action);

Samsung S9: Reports rounded RggbChannelVector values

I'm attempting to extract the white balance parameters from the auto white balance algorithm in the S9. On every other device I've tested, it gives meaningful parameters back (the numbers have a floating point precision of like 6 digits and are constantly changing) but the S9 appears to round it's result parameters to the nearest whole number which ends up being giving some very poor results in terms of color balance. Here's the code I am using to do this:
if (result.get(CaptureResult.COLOR_CORRECTION_GAINS) != null) {
channelVector = result.get(CaptureResult.COLOR_CORRECTION_GAINS);
}
Anybody else run into this issue and if so... any solutions to it out there???
Consider working with custom Samsung Camera API. These days, it is based on camera2.
Specifically, they provide their COLOR_CORRECTION_GAINS. They also explain that
… the camera device may do additional processing but android.colorCorrection.gains and android.colorCorrection.transform will still be provided by the camera device (in the results) and be roughly correct.
(the emphasis is mine)

Android camera : Set metering spot position

I'm trying to implement tap to focus on a Samsung Xcover4 for an industrial application (specific to this device).
The idea is to have the device stuffed into a kind of box with a hole where the camera is, and to use it to scan cards with qr codes on it.
So the "scan zone" is always the same, and should be set when the app start with a tap. Once it's done, camera should always focus on that zone and compute exposure on that spot
I'm using Xzing library, so I hacked the CameraManager manager class a little and it's working ok for the fixed focus zone.
I found the "spot" metering value by dumping native camera parameters, but one thing I can't figure out is how to set its position. I guess it can be done, since samsung does it in the native camera app.
ArrayList<Camera.Area> focusAreas = new ArrayList<Camera.Area>();
focusAreas.add(new Camera.Area(focusArea, 1000));
cameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
cameraParameters.setFocusAreas(focusAreas);
cameraParameters.setMeteringAreas(focusAreas);
cameraParameters.setZoom(0);
cameraParameters.set("metering", "spot");
camera.setParameters(cameraParameters);
camera.autoFocus(autoFocusManager);
Below is the list of natvie camera paremeters.
3dnr=false;
Infinity=Infinity;
antibanding=50hz;
antibanding-values=auto,50hz;
auto-exposure-lock-supported=true;
auto-whitebalance-lock-supported=true;
best-capture=0;
brightness=0;
brightness-max=2;
brightness-min=-2;
burst-capture=0;
burstshot-fps-values=(4,4);
constant-growth-rate-zoom-supported=true;
contrast=auto;
drc=false;
dual_mode=-1;
dualrecording-hint=-1;
dynamic-range-control=off;
effect=none;
effect-available-fps-values=(10000,15000);
effect-values=none,mono,negative,sepia,posterize;
effectrecording-hint=0;
exposure-compensation=0;
exposure-compensation-step=0.1;
fast-fps-mode=-1;
flash-mode=off;
flash-mode-values=off,auto,on,torch;
fnumber-value-denominator=10;
fnumber-value-numerator=19;
focal-length=3.70;
focallength-35mm-value=28;
focallength-value-denominator=100;
focallength-value-numerator=370;
focus-areas=(257,416,263,422,1000);
focus-distances=0.10,1.20,Infinity;
focus-mode=auto;
focus-mode-values=auto,macro,continuous-video,continuous-picture;
hdr-mode=0;
horizontal-view-angle=62.2;
hue=0;
hue-max=2;
hue-min=-2;
imageuniqueid-value=V13LLIA02PM V13LLKB16SA
;
intelligent-mode=-1;
iso=auto;
iso-values=auto,100,200,400,800;
jpeg-quality=96;
jpeg-thumbnail-height=384;
jpeg-thumbnail-quality=100;
jpeg-thumbnail-size-values=512x384,512x288,384x384,320x240,0x0;
jpeg-thumbnail-width=512;
max-exposure-compensation=20;
max-num-detected-faces-hw=16;
max-num-detected-faces-sw=0;
max-num-focus-areas=1;
max-num-metering-areas=0;
max-zoom=30;
maxaperture-value-denominator=100;
maxaperture-value-numerator=185;
metering=center;
metering-areas=;
metering-values=matrix,center,spot;
min-exposure-compensation=-20;
odc=false;
phase-af=off;
phase-af-values=off;
picture-format=jpeg;
picture-format-values=jpeg;
picture-size=4128x3096;
picture-size-values=4128x3096,4128x2322,3264x2448,3264x1836,3088x3088,2160x2160,2048x1536,2048x1152,1920x1080,1440x1080,1280x720,960x720,640x480,320x240;
preferred-preview-size-for-video=1280x720;
preview-format=yuv420sp;
preview-format-values=yuv420sp,yuv420p;
preview-fps-range=15000,30000;
preview-fps-range-values=(15000,15000),(24000,24000),(15000,30000),(30000,30000);
preview-frame-rate=30;
preview-frame-rate-values=15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30;
preview-size=1280x720;
preview-size-values=1280x720,1056x704,960x720,880x720,720x720,720x480,640x480,352x288,320x240,176x144;
rotation=0;
rt-hdr=off;
rt-hdr-values=off;
saturation=0;
saturation-max=2;
saturation-min=-2;
scene-mode=auto;
scene-mode-values=auto,action,portrait,landscape,night,night-portrait,theatre,beach,snow,sunset,steadyphoto,fireworks,sports,party,candlelight;
sharpness=0;
sharpness-max=2;
sharpness-min=-2;
smooth-zoom-supported=false;
vertical-view-angle=39.4;
video-frame-format=nv21;
video-size=1920x1080;
video-size-values=1920x1080,1440x1080,1072x1072,1280x720,960x720,800x450,720x480,640x480,480x320,352x288,320x240,176x144;
video-snapshot-supported=true;
video-stabilization-supported=false;
vrmode=-1;
wdr=0;
whitebalance=auto;
whitebalance-values=auto,incandescent,fluorescent,daylight,cloudy-daylight;
zoom=0;
zoom-ratios=100,104,109,114,120,125,131,138,144,151,158,166,174,182,190,200,209,219,229,240,251,263,276,289,303,317,332,348,364,381,400;
zoom-supported=true
Thank you.

Android camera API blurry image on Samsung devices

After implementing the camera2 API for the inApp camera I noticed that on Samsung devices the images appear blurry. After searching about that I found the Sasmung Camera SDK (http://developer.samsung.com/galaxy#camera). So after implementing the SDK on Samsung Galaxy S7 the images are fine now, but on Galaxy S6 they are still blurry. Someone experienced those kind of issues with Samsung devices?
EDIT:
To complement #rcsumners comment. I am setting autofocus by using
mPreviewBuilder.set(SCaptureRequest.CONTROL_AF_TRIGGER, SCaptureRequest.CONTROL_AF_TRIGGER_START);
mSCameraSession.capture(mPreviewBuilder.build(), new SCameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(SCameraCaptureSession session, SCaptureRequest request, STotalCaptureResult result) {
isAFTriggered = true;
}
}, mBackgroundHandler);
It is a long exposure image where the use has to take an image of a static non moving object. For this I am using the CONTROL_AF_MODE_MACRO
mCaptureBuilder.set(SCaptureRequest.CONTROL_AF_MODE, SCaptureRequest.CONTROL_AF_MODE_MACRO);
and also I am enabling auto flash if it is available
requestBuilder.set(SCaptureRequest.CONTROL_AE_MODE,
SCaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
I am not really an expert in this API, I mostly followed the SDK example app.
There could be a number of issues causing this problem. One prominent one is the dimensions of your output image
I ran Camera2 API and the preview is clear, but the output was quite blurry
val characteristics: CameraCharacteristics? = cameraManager.getCameraCharacteristics(cameraId)
val size = characteristics?.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)?.getOutputSizes(ImageFormat.JPEG) // The issue
val width = imageDimension.width
val height = imageDimension.height
if (size != null) {
width = size[0].width; height = size[0].height
}
val imageReader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 5)
The code below was returning a dimension about 245*144 which was way to small to be sent to the image reader. Some how the output was stretching the image making it end up been blurry. Therefore I removed this line below.
val size = characteristics?.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)?.getOutputSizes(ImageFormat.JPEG) // this was returning a small
Setting the width and height manually resolved the issue.
You're setting the AF trigger for one frame, but then are you waiting for AF to complete? For AF_MODE_MACRO (are you verifying the device lists support for this AF mode?) you need to wait for AF_STATE_FOCUSED_LOCKED before the image is guaranteed to be stable and sharp. (You may also receive NOT_FOCUSED_LOCKED if the AF algorithm can't reach sharp focus, which could be because the object is just too close for the lens, or the scene is too confusing)
On most modern devices, it's recommended to use CONTINUOUS_PICTURE and not worry about AF triggering unless you really want to lock focus for some time period. In that mode, the device will continuously try to focus to the best of its ability. I'm not sure all that many devices support MACRO, to begin with.

Android Camera2 API manual exposure change

According to offical google team statement the CONTROL_AE_EXPOSURE_COMPENSATION manual change is broken on Android 5.1. I'm lookin for a workaround for couple of days and the only one I found is connected to SENSOR_INFO_SENSITIVITY_RANGE. However, I found some difficulties in using it. My code look like this:
if(!modeDisabled){
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
modeDisabled=true;
}
range1 = characteristics.get(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);
minmin = range1.getLower();
maxmax = range1.getUpper();
int iso = ((i * (maxmax - minmin)) / 100 + minmin);
mPreviewRequestBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, iso);
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, mBackgroundHandler);
Of course the 'i' value is a progress value taken from the seekbar and everyting is closed in OnProgressChanged function.
The problem is that there are no visible changes when manipulating the seekbar. I'd be really gratetful for any help.
CONTROL_AE_EXPOSURE_COMPENSATION isn't broken in Android 5.1 in general, it was disabled on the Nexus 6 only (and will be re-enabled in a future update).
If you're disabling auto-exposure, you probably also need to set the exposure time, in addition to the sensitivity. You also preferably need to set the frame duration, though the defaults for both are probably 1/30s, which is reasonable. You can also copy the latest values for those from the most-recent capture result that did you auto-exposure.
That said, you should still see some sort of change here. Is it possible that you're overwriting your capture request elsewhere right after you set this one as the repeating request? You can check the returned capture results to see what the sensitivity setting the camera device is receiving is.

Categories

Resources