Skip to content

Auto exposure and white balance loop: scale per-channel rgb gains so none exceed new parameter rgb_gain_limit #298

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
114 changes: 89 additions & 25 deletions source/application/lua_libraries/camera.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ static struct camera_auto_last_values
double green_gain;
double blue_gain;
} last = {
.shutter = 500.0f,
.shutter = 4096.0f,
.analog_gain = 1.0f,
.red_gain = 1.9f,
.green_gain = 1.0f,
.blue_gain = 2.2f,
.red_gain = 121.6f,
.green_gain = 64.0f,
.blue_gain = 140.8f,
};

static struct camera_capture_settings
Expand Down Expand Up @@ -561,11 +561,12 @@ static int lua_camera_auto(lua_State *L)
}

// Default auto exposure settings
camera_metering_mode_t metering = AVERAGE;
double target_exposure = 0.18;
double exposure_speed = 0.50;
double shutter_limit = 1600.0;
double analog_gain_limit = 60.0;
camera_metering_mode_t metering = CENTER_WEIGHTED;
double target_exposure = 0.1;
double exposure_speed = 0.45;
double shutter_limit = 16383.0;
double analog_gain_limit = 16.0;
double rgb_gain_limit = 287.0;

// Default white balance settings
double white_balance_speed = 0.5;
Expand Down Expand Up @@ -655,6 +656,17 @@ static int lua_camera_auto(lua_State *L)

lua_pop(L, 1);
}

if (lua_getfield(L, 1, "rgb_gain_limit") != LUA_TNIL)
{
rgb_gain_limit = luaL_checknumber(L, -1);
if (rgb_gain_limit < 0.0 || rgb_gain_limit > 1023.0)
{
luaL_error(L, "rgb_gain_limit must be between 0 and 1023");
}

lua_pop(L, 1);
}
}

// Get current brightness from FPGA
Expand All @@ -668,6 +680,25 @@ static int lua_camera_auto(lua_State *L)
double matrix_g = metering_data[4] / 255.0f;
double matrix_b = metering_data[5] / 255.0f;

if (spot_r == 0.0) {
spot_r = 0.0001;
}
if (spot_g == 0.0) {
spot_g = 0.0001;
}
if (spot_b == 0.0) {
spot_b = 0.0001;
}
if (matrix_r == 0.0) {
matrix_r = 0.0001;
}
if (matrix_g == 0.0) {
matrix_g = 0.0001;
}
if (matrix_b == 0.0) {
matrix_b = 0.0001;
}

double spot_average = (spot_r + spot_g + spot_b) / 3.0;
double matrix_average = (matrix_r + matrix_g + matrix_b) / 3.0;
double center_weighted_average = (spot_average +
Expand Down Expand Up @@ -769,6 +800,10 @@ static int lua_camera_auto(lua_State *L)
? matrix_g / last.green_gain
: matrix_b / last.blue_gain);

// scale normalized RGB values to the gain scale
max_rgb *= 256.0;

// target per-channel gains that we blend towards
double red_gain = max_rgb / matrix_r * last.red_gain;
double green_gain = max_rgb / matrix_g * last.green_gain;
double blue_gain = max_rgb / matrix_b * last.blue_gain;
Expand All @@ -777,19 +812,6 @@ static int lua_camera_auto(lua_State *L)
double blending_factor = (scene_brightness - white_balance_min_activation) /
(white_balance_max_activation -
white_balance_min_activation);

if (red_gain > 1023.0)
{
red_gain = 1023.0;
}
if (green_gain > 1023.0)
{
green_gain = 1023.0;
}
if (blue_gain > 1023.0)
{
blue_gain = 1023.0;
}
if (blending_factor > 1.0)
{
blending_factor = 1.0;
Expand All @@ -811,9 +833,51 @@ static int lua_camera_auto(lua_State *L)
(blue_gain - last.blue_gain) +
last.blue_gain;

uint16_t red_gain_uint16 = (uint16_t)(last.red_gain * 256.0);
uint16_t green_gain_uint16 = (uint16_t)(last.green_gain * 256.0);
uint16_t blue_gain_uint16 = (uint16_t)(last.blue_gain * 256.0);
double max_rgb_gain = last.red_gain > last.green_gain
? (last.red_gain > last.blue_gain
? last.red_gain
: last.blue_gain)
: (last.green_gain > last.blue_gain
? last.green_gain
: last.blue_gain);

// Scale per-channel gains so the largest channel is at most rgb_gain_limit
if (max_rgb_gain > rgb_gain_limit)
{
double scale_factor = rgb_gain_limit / max_rgb_gain;
last.red_gain *= scale_factor;
last.green_gain *= scale_factor;
last.blue_gain *= scale_factor;
}

if (last.red_gain > 1023.0)
{
last.red_gain = 1023.0;
}
if (last.red_gain <= 0.0)
{
last.red_gain = 0.0001;
}
if (last.green_gain > 1023.0)
{
last.green_gain = 1023.0;
}
if (last.green_gain <= 0.0)
{
last.green_gain = 0.0001;
}
if (last.blue_gain > 1023.0)
{
last.blue_gain = 1023.0;
}
if (last.blue_gain <= 0.0)
{
last.blue_gain = 0.0001;
}

uint16_t red_gain_uint16 = (uint16_t)(last.red_gain);
uint16_t green_gain_uint16 = (uint16_t)(last.green_gain);
uint16_t blue_gain_uint16 = (uint16_t)(last.blue_gain);

check_error(i2c_write(CAMERA, 0x5180, 0x03, red_gain_uint16 >> 8).fail);
check_error(i2c_write(CAMERA, 0x5181, 0xFF, red_gain_uint16).fail);
Expand Down