Change control loop for AAA

This commit is contained in:
Martijn Braam
2024-01-23 16:53:47 +01:00
parent b140ebd9b7
commit 7e3d9e9063
4 changed files with 199 additions and 48 deletions

View File

@@ -39,6 +39,7 @@ static int output_buffer_width = -1;
static int output_buffer_height = -1;
static bool flash_enabled;
static int framecounter = 0;
static char capture_fname[255];
@@ -154,6 +155,10 @@ setup(MPPipeline *pipeline, const void *data)
libdng_init();
settings = g_settings_new(APP_ID);
prctl(PR_SET_NAME, "megapixels-pr", NULL, NULL, NULL);
state_proc.mode_balance = AAA_BY_POST;
state_proc.mode_exposure = AAA_BY_V4L2_CONTROLS;
state_proc.mode_focus = AAA_DISABLED;
}
void
@@ -340,6 +345,122 @@ clamp_float(float value, float min, float max)
return value;
}
static void
clamp_control(controlstate *control)
{
if (control->value_req > control->max) {
control->value_req = control->max;
}
}
static void
process_aaa()
{
bool auto_exposure =
!state_proc.exposure.manual && state_proc.exposure.auto_control == 0;
bool auto_focus =
!state_proc.focus.manual && state_proc.focus.auto_control == 0;
bool auto_balance = TRUE;
if (!auto_exposure && !auto_focus && !auto_balance) {
return;
}
int width = output_buffer_width;
int height = output_buffer_height / 3;
uint32_t *center = g_malloc_n(width * height * sizeof(uint32_t), 1);
glReadPixels(0, height, width, height, GL_RGBA, GL_UNSIGNED_BYTE, center);
libmegapixels_aaa_set_matrix(&state_proc.stats,
state_proc.calibration.color_matrix_1,
state_proc.calibration.color_matrix_2);
libmegapixels_aaa_software_statistics(
&state_proc.stats, center, width, height);
state_proc.blacklevel -= (float)state_proc.stats.blacklevel * 0.001f;
state_proc.blacklevel = clamp_float(state_proc.blacklevel, 0.0f, 0.07f);
if (auto_exposure) {
int direction = state_proc.stats.exposure;
int step = 0;
if (direction > 0) {
// Preview is too dark
// Try raising the exposure time first
if (state_proc.exposure.value < state_proc.exposure.max) {
step = state_proc.exposure.value / 4;
step = step < 4 ? 4 : step;
state_proc.exposure.value_req =
state_proc.exposure.value +
(step * direction);
printf("Expose + %d\n",
state_proc.exposure.value_req);
} else {
// Raise sensor gain if exposure limit is hit
step = state_proc.gain.value / 4;
step = step < 4 ? 4 : step;
state_proc.gain.value_req =
state_proc.gain.value + (step * direction);
printf("Gain + %d\n", state_proc.gain.value_req);
}
} else if (direction < 0) {
// Preview is too bright
// Lower the sensor gain first to have less noise
if (state_proc.gain.value > 0) {
step = state_proc.gain.value / 4;
state_proc.gain.value_req =
state_proc.gain.value + (step * direction);
printf("Gain - %d\n", state_proc.gain.value_req);
} else {
// Shorten the exposure time to go even darker
step = state_proc.exposure.value / 4;
state_proc.exposure.value_req =
state_proc.exposure.value +
(step * direction);
printf("Expose - %d\n",
state_proc.exposure.value_req);
}
}
clamp_control(&state_proc.gain);
clamp_control(&state_proc.exposure);
mp_io_pipeline_set_control_int32(state_proc.gain.control,
state_proc.gain.value_req);
mp_io_pipeline_set_control_int32(state_proc.exposure.control,
state_proc.exposure.value_req);
state_proc.gain.value = state_proc.gain.value_req;
state_proc.exposure.value = state_proc.exposure.value_req;
}
if (auto_balance) {
float r = state_proc.stats.avg_r;
float g = state_proc.stats.avg_g;
float b = state_proc.stats.avg_b;
// Revert the current gains set on the preview
b /= state_proc.red;
b /= state_proc.blue;
float t = 2.0f;
if (r < t && g < t && b < t) {
// Don't try to AWB on very dark frames
} else {
// Calculate the new R/B gains based on the average color of
// the frame
float new_r = g / clamp_float(r, 1.0f, 999.0f);
float new_b = g / clamp_float(b, 1.0f, 999.0f);
state_proc.red = clamp_float(new_r, 0.01f, 4.0f);
state_proc.blue = clamp_float(new_b, 0.01f, 4.0f);
}
}
gles2_debayer_set_shading(gles2_debayer,
state_proc.red,
state_proc.blue,
state_proc.blacklevel);
}
static GdkTexture *
process_image_for_preview(const uint8_t *image)
{
@@ -412,48 +533,9 @@ process_image_for_preview(const uint8_t *image)
mp_process_pipeline_buffer_ref(output_buffer);
mp_main_set_preview(output_buffer);
if (!state_proc.exposure.manual && state_proc.exposure.auto_control == 0) {
int width = output_buffer_width;
int height = output_buffer_height / 3;
uint32_t *center = g_malloc_n(width * height * sizeof(uint32_t), 1);
glReadPixels(
0, height, width, height, GL_RGBA, GL_UNSIGNED_BYTE, center);
libmegapixels_aaa_set_matrix(&state_proc.stats,
state_proc.calibration.color_matrix_1,
state_proc.calibration.color_matrix_2);
libmegapixels_aaa_software_statistics(
&state_proc.stats, center, width, height);
state_proc.blacklevel -= (float)state_proc.stats.blacklevel * 0.001f;
state_proc.blacklevel =
clamp_float(state_proc.blacklevel, 0.0f, 0.07f);
float r = state_proc.stats.avg_r;
float g = state_proc.stats.avg_g;
float b = state_proc.stats.avg_b;
// Revert the current gains set on the preview
b /= state_proc.red;
b /= state_proc.blue;
float t = 2.0f;
if (r < t && g < t && b < t) {
// Don't try to AWB on very dark frames
} else {
// Calculate the new R/B gains based on the average color of
// the frame
float new_r = g / clamp_float(r, 1.0f, 999.0f);
float new_b = g / clamp_float(b, 1.0f, 999.0f);
state_proc.red = clamp_float(new_r, 0.01f, 4.0f);
state_proc.blue = clamp_float(new_b, 0.01f, 4.0f);
}
gles2_debayer_set_shading(gles2_debayer,
state_proc.red,
state_proc.blue,
state_proc.blacklevel);
if (framecounter++ == 2) {
framecounter = 0;
process_aaa();
}
// Create a thumbnail from the preview for the last capture
@@ -1022,12 +1104,14 @@ update_state(MPPipeline *pipeline, const mp_state_proc *new_state)
.gain.control = state_proc.gain.control,
.gain.auto_control = state_proc.gain.auto_control,
.gain.value = state_proc.gain.value,
.gain.value_req = state_proc.gain.value_req,
.gain.max = state_proc.gain.max,
.gain.manual = state_proc.gain.manual,
.exposure.control = state_proc.exposure.control,
.exposure.auto_control = state_proc.exposure.auto_control,
.exposure.value = state_proc.exposure.value,
.exposure.value_req = state_proc.exposure.value_req,
.exposure.max = state_proc.exposure.max,
.exposure.manual = state_proc.exposure.manual,