Change control loop for AAA
This commit is contained in:
@@ -24,6 +24,12 @@ static MPPipeline *pipeline;
|
||||
static GSource *capture_source;
|
||||
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
|
||||
setup(MPPipeline *pipeline, const void *data)
|
||||
{
|
||||
@@ -124,6 +130,23 @@ mp_io_pipeline_focus()
|
||||
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
|
||||
capture(MPPipeline *pipeline, const void *data)
|
||||
{
|
||||
@@ -256,13 +279,45 @@ update_controls()
|
||||
static void
|
||||
do_aaa()
|
||||
{
|
||||
if (!state_io.exposure.manual && state_io.exposure.auto_control == 0) {
|
||||
int step = state_io.gain.value / 16;
|
||||
if (step < 1) {
|
||||
step = 1;
|
||||
bool auto_exposure =
|
||||
!state_io.exposure.manual && state_io.exposure.auto_control == 0;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -10,6 +10,7 @@ void mp_io_pipeline_stop();
|
||||
|
||||
void mp_io_pipeline_focus();
|
||||
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);
|
||||
|
||||
|
@@ -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,
|
||||
|
||||
|
11
src/state.h
11
src/state.h
@@ -69,6 +69,13 @@ typedef struct state_io {
|
||||
int device_rotation;
|
||||
} 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 {
|
||||
libmegapixels_devconfig *configuration;
|
||||
libmegapixels_camera *camera;
|
||||
@@ -98,4 +105,8 @@ typedef struct state_proc {
|
||||
float red;
|
||||
float blue;
|
||||
float blacklevel;
|
||||
|
||||
int mode_balance;
|
||||
int mode_exposure;
|
||||
int mode_focus;
|
||||
} mp_state_proc;
|
Reference in New Issue
Block a user