Sensor fixed gain/exposure not working

Setting a fixed gain and fixed exposure is not working. With set_auto_exposure and set_auto_gain both False, it appears that some auto gain/exposure is still occurring.

sensor.set_auto_exposure(False, exposure_us=10000)
sensor.set_auto_gain(False, gain_db=3)

The fixed gain and exposure settings were confirmed using get_gain_db and get_exposure_us.

Sensor actual gain = 3.152235 db
Sensor actual exposure = 19992 us

To demonstrate this I have started the test code below in two scenarios - one with the camera lens cap on (dark) and one with the camera pointing at an LED light (bright). The subsequent images of a PCBA show the difference in exposure and/or gain depending on whether the application starts with the camera in the dark, or bright light.

First Image Dark:


Images after first image Dark:

First Image Bright:

Images after first image Bright:

Here is the Code to recreate issue.
Camera Test V1.py (1.33 KB)

OpenMV H7. Firmware Version 3.6.7

You’re hitting a race condition, please add a delay after the camera starts up before setting the gain/exposure. The camera chips internally update their state automatically on startup and if you force settings right then and there the logic onboard will override the value you set. See the camera control example scripts.

In the sensor_exposure_control_1.py example there are three different delays: (1) 2000ms delay after setting pixformat and framesize, (2) 500ms after set_auto_gain(False) and set_auto_whitebal(False), and (3) no delay after set_auto_exposure(False). In my test code I had 1000ms delay after all settings and readback of sensor gain and exposure settings was correct. I increased delay to 2000ms delay and issue still exists. How much delay is necessary? Is a delay necessary after each individual setting or just after all sensor settings?

I tried adding 2000ms delay in three places during sensor setup. Readback of gain and exposure is consistent with the values set.
However, the gain/exposure of the subsequent images are still different depending on if the camera is in dark or bright light when the application starts.

Setup Image Sensor

sensor.reset()
sensor.set_framesize(sensor.QVGA)
sensor.set_pixformat(sensor.GRAYSCALE)
sensor.skip_frames(time = 2000) # Wait for settings to take effect

Setup Image Sensor manual gain, exposure, and white balance

sensor.set_auto_exposure(False, exposure_us=10000) # exposure in us
sensor.set_auto_gain(False, gain_db=3) # gain in db
sensor.set_auto_whitebal(False)
sensor.skip_frames(time = 2000) # Wait for settings to take effect

Setup contrast, brightness and saturation

sensor.set_contrast(3) # range -3 to +3
sensor.set_brightness(0) # range -3 to +3
sensor.set_saturation(0) # range -3 to +3
sensor.skip_frames(time = 2000) # Wait for settings to take effect

Actual can be different due to sensor conversions

print(“Sensor ID”,sensor.get_id() )
print(“Sensor actual gain = %f db” % sensor.get_gain_db())
print(“Sensor actual exposure = %d us” % sensor.get_exposure_us() )
print(" ")

Reset Images

img_num = 0
time_start = pyb.millis()
time_last_image_ms = pyb.millis()


#*****************

Main loop

#*****************

while(True):

img = sensor.snapshot()

img_num +=1
print(“\nImage #”, img_num)
print(“Elapsed Time:”, pyb.elapsed_millis(time_start) )
print(“Interval time:”, pyb.elapsed_millis(time_last_image_ms) )
time_last_image_ms = pyb.millis()

Just something like 100 to 200 ms. If it’s not enough you will know.

You want to add the delay after setting everything but exposure.

See above. Added 2000ms delay in three places. Issue still exists.

Also tried 1000ms delay after each setting. Images are still different when app starts in dark or bright light.

Setup Image Sensor

sensor.reset()
sensor.set_framesize(sensor.QVGA)
sensor.set_pixformat(sensor.GRAYSCALE)
sensor.skip_frames(time = 1000) # Wait for settings to take effect

Setup Image Sensor manual gain, exposure, and white balance

sensor.set_auto_gain(False, gain_db=3) # gain in db
sensor.skip_frames(time = 1000) # Wait for settings to take effect
sensor.set_auto_whitebal(False)
sensor.skip_frames(time = 1000) # Wait for settings to take effect
sensor.set_auto_exposure(False, exposure_us=10000) # exposure in us
sensor.skip_frames(time = 1000) # Wait for settings to take effect

The sensor is still doing some type of auto exposure even with the manual settings for gain and exposure, because the interval time between images is much longer when the camera is in the dark (lens cap on), compared to when the lens cap is off.

With the exposure manually set to 10000us:
Lens Cap On - Image Interval time is 76-77 ms
Lens Cap Off- Image Interval time: 36-37 ms

Mmm, it might be night mode.

Um, I don’t really have time to look into this more right now. But, you can disable this stuff forcablity via register settings:

Use sensor.__write_reg(addr, val) and sensor.__read_reg(addr) to read/write register addresses on the OV7725.

Here’s our driver:

https://github.com/openmv/openmv/blob/master/src/omv/ov7725.c

Seems like this is a substantial issue with the foundational sensor settings on the H7. The manual gain and exposure settings not being correct probably affects many users, who are not aware that their H7 camera is not actually functioning according to the sensor settings in OpenMV.

When do you think you will have time to look into this issue further?

I have disabled all of the automatic image control functions in the datasheet:

Automatic Exposure Control (AEC)
Automatic Gain Control (AGC)
Automatic White Balance (AWB)
Automatic Band Filter (ABF)
Automatic Black-Level Calibration (ABLC)
Auto frame rate control (night mode)

The issue still remains. Manual setting of exposure/gain is not constant and changes depending on the initial images of the sensor. Could it be something in the OpenMV IDE?

Used the following code to set and confirm each of these registers set all control bits to zero.

Common Control 5 (COM5)

i=0x0E
sensor.__write_reg(i, 0)
read_reg = sensor.__read_reg(i)
print(“Register #”,i,“value:”, read_reg)

Common Control 8 (COM8)

i=0x13
sensor.__write_reg(i, 0)
read_reg = sensor.__read_reg(i)
print(“Register #”,i,“value:”, read_reg)

Common Control 13 (COM13)

i=0x3e
sensor.__write_reg(i, 0)
read_reg = sensor.__read_reg(i)
print(“Register #”,i,“value:”, read_reg)

AWB Control Byte 0 (AWB_Ctrl0)

i=0x63
sensor.__write_reg(i, 0)
read_reg = sensor.__read_reg(i)
print(“Register #”,i,“value:”, read_reg)

Special Digital Effect (SDE)

i=0xA6
sensor.__write_reg(i, 0)
read_reg = sensor.__read_reg(i)
print(“Register #”,i,“value:”, read_reg)

The IDE just displays JPEGs.

Question, what are you expecting to happen? Can you print what the contrast and gain is set to after setting it? It should be about the same value.

If so, then some other sensor auto control method is triggering. Please note that the sensor supports night mode where it will exposure the image for multiple frames to handle darkness. I enabled this feature after finishing this auto exposure code to improve image quality. You can tell if this is happening by the frame rate being really different between initial scenes.

With sensor.set_auto_exposure(False, exposure_us=10000) and sensor.set_auto_gain(False, gain_db=3)

The values read are:
Sensor gain = 3.152235 db
Sensor exposure = 9992 us

I’m looking for a full manual mode control of the sensor. No auto anything, including no night mode. As shown in the first post, the image of the PCBA under constant lighting is very different if the application starts up with the lights on or the lights off. Since I do not have control of the lighting at the time the application starts, I need to setup the sensor completely manually and independent of the Illumination at startup.

These PCBA images are just an example that recreate the issue. In my use case, the system starts running elsewhere and is then moved into position where Illumination is controlled. The problem is if the system starts up in low lighting, when it is subsequently moved into position, the objects are overexposed. In contrast, if the system is started in bright light, and then moved into position, the objects are under exposed. The use case requires full manual control of the camera settings, that is independent of lighting conditions at startup.

Thanks.

Hi, I have some time to today to mess with this. I’ll see what’s going on.

Cool. Thanks.

This works as expected on the H7:

# Sensor Exposure Control
#
# This example shows off how to cotnrol the camera sensor's
# exposure manually versus letting auto exposure control run.

# What's the difference between gain and exposure control?
#
# Well, by increasing the exposure time for the image you're getting more
# light on the camera. This gives you the best signal to noise ratio. You
# in general always want to increase the expsoure time... except, when you
# increase the exposure time you decrease the maximum possible frame rate
# and if anything moves in the image it will start to blur more with a
# higher exposure time. Gain control allows you to increase the output per
# pixel using analog and digital multipliers... however, it also amplifies
# noise. So, it's best to let the exposure increase as much as possible
# and then use gain control to make up any remaining ground.

import sensor, image, time

# Change this value to adjust the exposure. Try 10.0/0.1/etc.
EXPOSURE_TIME_SCALE = 1.0

sensor.reset()                      # Reset and initialize the sensor.
sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE)
sensor.set_framesize(sensor.QVGA)   # Set frame size to QVGA (320x240)

# Print out the initial exposure time for comparison.
print("Initial exposure == %d" % sensor.get_exposure_us())

sensor.skip_frames(time = 2000)     # Wait for settings take effect.
clock = time.clock()                # Create a clock object to track the FPS.

# You have to turn automatic gain control and automatic white blance off
# otherwise they will change the image gains to undo any exposure settings
# that you put in place...
sensor.set_auto_gain(False)
sensor.set_auto_whitebal(False)
# Need to let the above settings get in...
sensor.skip_frames(time = 500)

current_exposure_time_in_microseconds = sensor.get_exposure_us()
print("Current Exposure == %d" % current_exposure_time_in_microseconds)

# Auto exposure control (AEC) is enabled by default. Calling the below function
# disables sensor auto exposure control. The additionally "exposure_us"
# argument then overrides the auto exposure value after AEC is disabled.
sensor.set_auto_exposure(False, \
    exposure_us = 100000)

print("New exposure == %d" % sensor.get_exposure_us())
# sensor.get_exposure_us() returns the exact camera sensor exposure time
# in microseconds. However, this may be a different number than what was
# commanded because the sensor code converts the exposure time in microseconds
# to a row/pixel/clock time which doesn't perfectly match with microseconds...

# If you want to turn auto exposure back on do: sensor.set_auto_exposure(True)
# Note that the camera sensor will then change the exposure time as it likes.

# Doing: sensor.set_auto_exposure(False)
# Just disables the exposure value update but does not change the exposure
# value the camera sensor determined was good.

while(True):
    clock.tick()                    # Update the FPS clock.
    img = sensor.snapshot()         # Take a picture and return the image.
    #print(clock.fps())              # Note: OpenMV Cam runs about half as fast when connected
                                    # to the IDE. The FPS should increase once disconnected.



Traceback (most recent call last):
  File "<stdin>", line 65, in <module>
Exception: IDE interrupt
MicroPython v1.12-omv OpenMV v3.6.7 2020-07-20; OPENMV4-STM32H743
Type "help()" for more information.
>>> Initial exposure == 360
Current Exposure == 360
New exposure == 99984

Traceback (most recent call last):
  File "<stdin>", line 65, in <module>
Exception: IDE interrupt
MicroPython v1.12-omv OpenMV v3.6.7 2020-07-20; OPENMV4-STM32H743
Type "help()" for more information.
>>> Initial exposure == 3048
Current Exposure == 3048
New exposure == 99984

This works as expected:

import sensor

# Setup Image Sensor
sensor.reset()
sensor.set_framesize(sensor.QVGA)
sensor.set_pixformat(sensor.GRAYSCALE)
print("Start exposure == %d" % sensor.get_exposure_us())
sensor.skip_frames(time = 1000) # Wait for settings to take effect

# Setup Image Sensor manual gain, exposure, and white balance
sensor.set_auto_gain(False, gain_db=3) # gain in db
sensor.skip_frames(time = 1000) # Wait for settings to take effect
sensor.set_auto_whitebal(False)
sensor.skip_frames(time = 1000) # Wait for settings to take effect
sensor.set_auto_exposure(False, exposure_us=10000) # exposure in us
sensor.skip_frames(time = 1000) # Wait for settings to take effect

print("New exposure == %d" % sensor.get_exposure_us())



Traceback (most recent call last):
  File "<stdin>", line 7, in <module>
Exception: IDE interrupt
MicroPython v1.12-omv OpenMV v3.6.7 2020-07-20; OPENMV4-STM32H743
Type "help()" for more information.
>>> Start exposure == 3048
New exposure == 9984
MicroPython v1.12-omv OpenMV v3.6.7 2020-07-20; OPENMV4-STM32H743
Type "help()" for more information.
>>> Start exposure == 432
New exposure == 9984
MicroPython v1.12-omv OpenMV v3.6.7 2020-07-20; OPENMV4-STM32H743
Type "help()" for more information.
>>>

I’m using firmware v3.6.7.

I’ll give it a try.

The code above does not fix the underlying problem where the sensor is not in a manual mode. It only sets the exposure and reads back the set exposure value, but the sensor is still not in fully manual mode.

You can reproduce this issue with your code by starting the application under two conditions, (1) with the lens cover on, and (2) with the camera pointing at a bright light. Once the application is running, look at the images in the IDE frame buffer and you will see that the exposure is very different between startup conditions #1 and #2. (Note: the the illumination of the Amazon card below is the same in both conditions)

This shows that the sensor is not in manual mode, but is still doing some type of auto setup based on the illumination at startup.

Image after startup condition #1 (Lens Cap On)


Image after startup condition #2 (bright light)