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

@@ -24,6 +24,12 @@ static MPPipeline *pipeline;
static GSource *capture_source; static GSource *capture_source;
static bool pipeline_changed = true; static bool pipeline_changed = true;
typedef struct invoke_set_control {
uint32_t control;
int32_t int_value;
bool bool_value;
} invoke_set_control;
static void static void
setup(MPPipeline *pipeline, const void *data) setup(MPPipeline *pipeline, const void *data)
{ {
@@ -124,6 +130,23 @@ mp_io_pipeline_focus()
mp_pipeline_invoke(pipeline, focus, NULL, 0); mp_pipeline_invoke(pipeline, focus, NULL, 0);
} }
static void
set_control_int32(MPPipeline *pipeline, const invoke_set_control *data)
{
mp_camera_control_set_int32(state_io.camera, data->control, data->int_value);
}
void
mp_io_pipeline_set_control_int32(uint32_t control, uint32_t value)
{
invoke_set_control data = { 0 };
data.control = control;
data.int_value = value;
mp_pipeline_invoke(
pipeline, set_control_int32, &data, sizeof(invoke_set_control));
}
static void static void
capture(MPPipeline *pipeline, const void *data) capture(MPPipeline *pipeline, const void *data)
{ {
@@ -256,13 +279,45 @@ update_controls()
static void static void
do_aaa() do_aaa()
{ {
if (!state_io.exposure.manual && state_io.exposure.auto_control == 0) { bool auto_exposure =
int step = state_io.gain.value / 16; !state_io.exposure.manual && state_io.exposure.auto_control == 0;
if (step < 1) {
step = 1; if (auto_exposure) {
int direction = state_io.stats.exposure;
int step = 0;
if (direction > 0) {
// Preview is too dark
// Try raising the exposure time first
if (state_io.exposure.value < state_io.exposure.max) {
step = state_io.exposure.value / 16;
state_io.exposure.value_req =
state_io.exposure.value + (step * direction);
printf("Expose + %d\n", state_io.exposure.value_req);
} else {
// Raise sensor gain if exposure limit is hit
step = state_io.gain.value / 16;
state_io.gain.value_req =
state_io.gain.value + (step * direction);
printf("Gain + %d\n", state_io.gain.value_req);
}
} else if (direction < 0) {
// Preview is too bright
// Lower the sensor gain first to have less noise
if (state_io.gain.value > 0) {
step = state_io.gain.value / 16;
state_io.gain.value_req =
state_io.gain.value + (step * direction);
printf("Gain - %d\n", state_io.gain.value_req);
} else {
// Shorten the exposure time to go even darker
step = state_io.exposure.value / 16;
state_io.exposure.value_req =
state_io.exposure.value + (step * direction);
printf("Expose - %d\n", state_io.exposure.value_req);
}
} }
state_io.gain.value_req = state_io.gain.value;
state_io.gain.value_req += step * state_io.stats.exposure;
} }
} }

View File

@@ -10,6 +10,7 @@ void mp_io_pipeline_stop();
void mp_io_pipeline_focus(); void mp_io_pipeline_focus();
void mp_io_pipeline_capture(); void mp_io_pipeline_capture();
void mp_io_pipeline_set_control_int32(uint32_t control, uint32_t value);
void mp_io_pipeline_release_buffer(uint32_t buffer_index); void mp_io_pipeline_release_buffer(uint32_t buffer_index);

View File

@@ -39,6 +39,7 @@ static int output_buffer_width = -1;
static int output_buffer_height = -1; static int output_buffer_height = -1;
static bool flash_enabled; static bool flash_enabled;
static int framecounter = 0;
static char capture_fname[255]; static char capture_fname[255];
@@ -154,6 +155,10 @@ setup(MPPipeline *pipeline, const void *data)
libdng_init(); libdng_init();
settings = g_settings_new(APP_ID); settings = g_settings_new(APP_ID);
prctl(PR_SET_NAME, "megapixels-pr", NULL, NULL, NULL); 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 void
@@ -340,6 +345,122 @@ clamp_float(float value, float min, float max)
return value; 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 * static GdkTexture *
process_image_for_preview(const uint8_t *image) 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_process_pipeline_buffer_ref(output_buffer);
mp_main_set_preview(output_buffer); mp_main_set_preview(output_buffer);
if (!state_proc.exposure.manual && state_proc.exposure.auto_control == 0) { if (framecounter++ == 2) {
int width = output_buffer_width; framecounter = 0;
int height = output_buffer_height / 3; process_aaa();
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);
} }
// Create a thumbnail from the preview for the last capture // 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.control = state_proc.gain.control,
.gain.auto_control = state_proc.gain.auto_control, .gain.auto_control = state_proc.gain.auto_control,
.gain.value = state_proc.gain.value, .gain.value = state_proc.gain.value,
.gain.value_req = state_proc.gain.value_req,
.gain.max = state_proc.gain.max, .gain.max = state_proc.gain.max,
.gain.manual = state_proc.gain.manual, .gain.manual = state_proc.gain.manual,
.exposure.control = state_proc.exposure.control, .exposure.control = state_proc.exposure.control,
.exposure.auto_control = state_proc.exposure.auto_control, .exposure.auto_control = state_proc.exposure.auto_control,
.exposure.value = state_proc.exposure.value, .exposure.value = state_proc.exposure.value,
.exposure.value_req = state_proc.exposure.value_req,
.exposure.max = state_proc.exposure.max, .exposure.max = state_proc.exposure.max,
.exposure.manual = state_proc.exposure.manual, .exposure.manual = state_proc.exposure.manual,

View File

@@ -69,6 +69,13 @@ typedef struct state_io {
int device_rotation; int device_rotation;
} mp_state_io; } mp_state_io;
typedef enum aaa_mode {
AAA_DISABLED,
AAA_BY_SENSOR,
AAA_BY_V4L2_CONTROLS,
AAA_BY_POST,
} aaa_mode;
typedef struct state_proc { typedef struct state_proc {
libmegapixels_devconfig *configuration; libmegapixels_devconfig *configuration;
libmegapixels_camera *camera; libmegapixels_camera *camera;
@@ -98,4 +105,8 @@ typedef struct state_proc {
float red; float red;
float blue; float blue;
float blacklevel; float blacklevel;
int mode_balance;
int mode_exposure;
int mode_focus;
} mp_state_proc; } mp_state_proc;