Parcourir la source

Change control loop for AAA

Martijn Braam il y a 4 mois
Parent
commit
7e3d9e9063
4 fichiers modifiés avec 199 ajouts et 48 suppressions
  1. 61 6
      src/io_pipeline.c
  2. 1 0
      src/io_pipeline.h
  3. 126 42
      src/process_pipeline.c
  4. 11 0
      src/state.h

+ 61 - 6
src/io_pipeline.c

@@ -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;
         }
 }
 

+ 1 - 0
src/io_pipeline.h

@@ -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);
 

+ 126 - 42
src/process_pipeline.c

@@ -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 - 0
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;