techyian / MMALSharp

C# wrapper to Broadcom's MMAL with an API to the Raspberry Pi camera.
MIT License
195 stars 33 forks source link

Configuring ISO and shutter speed fails #138

Closed Spontifixus closed 4 years ago

Spontifixus commented 4 years ago

I am somewhat sorry to open so many issues right now - but here's another one. I try to reconfigure my camera like this:

MMALCameraConfig.ISO = 800;
MMALCameraConfig.ShutterSpeed = 2000000;
camera.ConfigureCameraSettings();

I think this is as you documented it here and here. According to the raspistill docs both 800 for ISO and 2000000 for the shutter speed should be perfectly fine (and work well, I if I use raspistill directly).

I set these values however after I have captured the first image.

Doing so yields an exception however:

MMALSharp.MMALInvalidException: Argument is invalid. Unable to set camera config.
  at MMALSharp.MMALNativeExceptionHelper.MMALCheck(MMAL_STATUS_T status, String message)
  at MMALSharp.MMALCameraComponentExtensions.SetCameraConfig(MMALCameraComponent camera, MMAL_PARAMETER_CAMERA_CONFIG_T value)
  at MMALSharp.Components.MMALCameraComponent.Initialise(IOutputCaptureHandler stillCaptureHandler, IOutputCaptureHandler videoCaptureHandler)
  at MMALSharp.MMALCamera.ConfigureCameraSettings(IOutputCaptureHandler stillCaptureHandler, IOutputCaptureHandler videoCaptureHandler)

Here's additional debug logging:

117898.253: mmal: mmal_ril_param_set_cam_config: mmal_ril_param_set_cam_config: Set OMX_IndexParamCameraImagePool failed status 3

Do I do anything wrong there?

techyian commented 4 years ago

Please could you provide a code snippet? I have tried to reproduce but no errors are thrown for me.

Below is the code I have tested with:

MMALCameraConfig.ISO = 800;
MMALCameraConfig.ShutterSpeed = 2000000;

using (var imgCaptureHandler = new ImageStreamCaptureHandler("/home/pi/images/test.jpg"))
using (var imgEncoder = new MMALImageEncoder())
using (var nullSink = new MMALNullSinkComponent())
{
    cam.ConfigureCameraSettings();

    var portConfig = new MMALPortConfig(MMALEncoding.JPEG, MMALEncoding.I420, 90);

    imgEncoder.ConfigureOutputPort(portConfig, imgCaptureHandler);

    cam.Camera.StillPort.ConnectTo(imgEncoder);
    cam.Camera.PreviewPort.ConnectTo(nullSink);

    await Task.Delay(2000);

    await cam.ProcessAsync(cam.Camera.StillPort);
}

I've also tested taking an image using the default settings then immediately afterwards taken another using your shutter speed and ISO values and that works as expected - the 2nd image is much brighter and the filesize is reduced.

From seeing your example code here, I have a feeling it may be due to the way you're handling the lifetimes of your components. If you are reconfiguring the camera you should be doing it from a clean state, i.e. any components connected should be disposed of and re-created once you've reconfigured.

Spontifixus commented 4 years ago

Ah - I did not recreate the pipeline. Do I need to disconnect the StillPort explicitly or is it enough to just dispose and rebuild the affected components (i.e. the imageEncoder, the resizer and the portConfigs)?

(EDIT: I just implemented it using CleanPortPools and disposing of all related instances, and will give this a try now)

(EDIT2: That did not work. I will create a small working example tonight to demonstrate what I am trying.)

techyian commented 4 years ago

Disposing of the components will handle the closing of connections so you don't need to explicitly do this.

(EDIT: I just implemented it using CleanPortPools and disposing of all related instances, and will give this a try now)

What are you trying to do here? The MMALCamera.ProcessAsync method handles the CleanPortPools call after each run.

(EDIT2: That did not work. I will create a small working example tonight to demonstrate what I am trying.)

Ok no problem, I think an example will help explain where you might be going wrong.

Spontifixus commented 4 years ago

I created a demo according to your code snippet, and that both worked as expected and failed. You can find the code I used in the in the config-demo branch in my repository.

What worked: No exceptions. What didn't work: My image remains black. When capturing the image using the raspistill command I see a brightly infrared-lid image.

Here's the log file. As far as I can see, the parameters are being set. Additionally I have captured the "internal" logs.

techyian commented 4 years ago

I've cloned your example repository and when I run the code 3 images are saved, 1 with normal exposure and 2 which are over-exposed due to the ISO and shutter speed settings. Could you explain your test setup to me in more detail? What are you using to provide the IR light and is that light source constantly available or is it turned on programatically? If you are providing IR to your scene I would certainly expect there to be something visible. Finally, what parameters are your passing to Raspistill?

Spontifixus commented 4 years ago

Hm. I have just shot three pics just as you did, with correct results: one normal and two overexposed. I will try this again tonight, when its dark. The IR light source I use is custom made, and active constantly.

One question though: I set the exposure mode to auto for the third photo. The raspistill docs state, that exposure settings override ISO and shutter speed settings, so I would expect a normal image as the third one. If that "reset" does not happen when setting exposure to auto: How do I reset ISO and shutter speed to automatic values?

techyian commented 4 years ago

The value you're setting to MMALCameraConfig.ExposureMode is actually the default value if you look at the source code so you're third image will be the same as the second. Setting automatic exposure and a non-zero shutter speed will disable automatic exposure control, you're then setting ISO to a non-zero value which then disables automatic gain control. To answer your question, setting ISO and Shutter Speed to 0 (default) will force them to use automatic values.

Spontifixus commented 4 years ago

Thanks for the hint! I think the IR light in the bunny's cage might be broken - so I'll drop it for today and try again tomorrow night after fixing the light...

Spontifixus commented 4 years ago

Here we go. I made a slight modification to my demo program (set shutter speed and ISO to 0 for the 3rd capture) and tried again. The result were three black images, whereas using the raspistill command produces a correct image. Here are the raspistill parameters I use:

raspistill -o test.jpg -ss 2000000 -ISO 800 -rot 180

And if I am not mistaken my configuration should be just the same:

MMALCameraConfig.Rotation = 180;
MMALCameraConfig.ISO = 800;
MMALCameraConfig.ShutterSpeed = 2000 * 1000;

The MMALSharp-libraries I used were built from commit 6be66ce.

And to give you an impression of what an infrared lit rabbit cage looks like, here is the photo taken with raspistill: test.jpg

techyian commented 4 years ago

Good news at last.

This is being caused due to the preview port's framerate being set to match the video port's framerate. I did this as it follows raspivid's behaviour but this in turn appears to limit the maximum shutter speed you can set as it'll be constrained by the framerate. In raspistill both the preview and still ports use a variable framerate of 0.

Short term fix as you're not using video is to set MMALCameraConfig.VideoFramerate = new MMAL_RATIONAL_T(0, 1);. However in the longer term I need to think about how best to sort this :)

Spontifixus commented 4 years ago

Thank you for the quick response. I tested this with your proposed short term fix with MMALSharp libraries built on commit d9b11a6. Aaaaand: It works! So I guess you can close this issue now! 👍

It might be that I open another issue though, because the camera shows behaviour I don't fully understand: await camera.ProcessAsync(...) takes just a few milliseconds to execute, but the shutter speed is set to two seconds, and the image looks correct. Is the camera continuously "looking" and when I call ProcessAsync just the result of the last two seconds is used?

Spontifixus commented 4 years ago

Thanks again for your support! The application has now uploaded several hundred images without a glitch. Could you publish the current version of the libraries as a prerelease to MyGet or NuGet? That would make development a lot easier... :)

techyian commented 4 years ago

No problem at all and I'm glad it's working for you now. Each successful build is uploaded to MyGet so you can grab the latest from there. Regarding your previous question, there certainly should be a noticable delay and there is for me when setting the shutter speed to 2s. The RPi camera has a rolling shutter so when it is enabled it is constantly doing things in the background such as white balance, automatic gain control and others. There is a lot of info on the web (especially over at the picamera docs) about the camera's hardware in more detail if you're interested. I've been reluctant on adding hardware documentation myself as I'll be simply duplicating what's already available which doesn't help anyone!

techyian commented 4 years ago

I'm going to close this issue now and track the relevant changes required in #140.