From f314ac4e72a4ad3af89e57c9aa1c0da90f65a5fb Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Tue, 11 Feb 2020 10:25:36 -0800 Subject: [PATCH] Improve sensor module with transpose and get operations --- src/omv/py/py_sensor.c | 113 ++++++++++++++++++++---- src/omv/py/qstrdefsomv.h | 8 ++ src/omv/sensor.c | 184 +++++++++++++++++++++++++++++++-------- src/omv/sensor.h | 23 ++++- 4 files changed, 274 insertions(+), 54 deletions(-) diff --git a/src/omv/py/py_sensor.c b/src/omv/py/py_sensor.c index 9af42d0e9..25c65e206 100644 --- a/src/omv/py/py_sensor.c +++ b/src/omv/py/py_sensor.c @@ -17,6 +17,7 @@ #include "py_assert.h" #include "py_image.h" #include "py_sensor.h" +#include "py_imu.h" #include "omv_boardconfig.h" #include "py_helper.h" #include "framebuffer.h" @@ -44,13 +45,37 @@ static mp_obj_t py_sensor_flush() { return mp_const_none; } -static mp_obj_t py_sensor_snapshot(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - // Snapshot image +static mp_obj_t py_sensor_snapshot(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ +#if MICROPY_PY_IMU + // To prevent oscillation there is a 20 degree dead-zone between each state. + // This means there is a 70 degree active-zone. + if (sensor_get_auto_rotation()) { + float roll = py_imu_roll_rotation(); + if ((325 < roll) || (roll < 35) ) { // center is 0/360, upright + sensor_set_hmirror(false); + sensor_set_vflip(false); + sensor_set_transpose(false); + } else if ((235 < roll) && (roll < 305)) { // center is 270, rotated right + sensor_set_hmirror(true); + sensor_set_vflip(false); + sensor_set_transpose(true); + } else if ((145 < roll) && (roll < 215)) { // center is 180, upside down + sensor_set_hmirror(true); + sensor_set_vflip(true); + sensor_set_transpose(false); + } else if ((55 < roll) && (roll < 125)) { // center is 90, rotated left + sensor_set_hmirror(false); + sensor_set_vflip(true); + sensor_set_transpose(true); + } + } +#endif //MICROPY_PY_IMU + mp_obj_t image = py_image(0, 0, 0, 0); - if (sensor.snapshot(&sensor, (image_t*) py_image_cobj(image), NULL)==-1) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "Sensor Timeout!!")); - return mp_const_false; + if (sensor.snapshot(&sensor, (image_t *) py_image_cobj(image), NULL) == -1) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "Sensor Timeout")); } return image; @@ -69,9 +94,7 @@ static mp_obj_t py_sensor_skip_frames(uint n_args, const mp_obj_t *args, mp_map_ if (!n_args) { while ((systick_current_millis() - millis) < time) { // 32-bit math handles wrap arrounds... - if (sensor.snapshot(&sensor, NULL, NULL) == -1) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "Sensor Timeout!!")); - } + py_sensor_snapshot(0, NULL, NULL); } } else { for (int i = 0, j = mp_obj_get_int(args[0]); i < j; i++) { @@ -79,9 +102,7 @@ static mp_obj_t py_sensor_skip_frames(uint n_args, const mp_obj_t *args, mp_map_ break; } - if (sensor.snapshot(&sensor, NULL, NULL) == -1) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "Sensor Timeout!!")); - } + py_sensor_snapshot(0, NULL, NULL); } } @@ -164,9 +185,16 @@ static mp_obj_t py_sensor_dealloc_extra_fb() static mp_obj_t py_sensor_set_pixformat(mp_obj_t pixformat) { if (sensor_set_pixformat(mp_obj_get_int(pixformat)) != 0) { - PY_ASSERT_TRUE_MSG(0, "Pixel format is not supported!"); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Pixel format is not supported!")); } - return mp_const_true; + return mp_const_none; +} + +static mp_obj_t py_sensor_get_pixformat() { + if (sensor.pixformat == PIXFORMAT_INVALID) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Pixel format not set yet!")); + } + return mp_obj_new_int(sensor.pixformat); } static mp_obj_t py_sensor_set_framerate(mp_obj_t framerate) { @@ -202,7 +230,14 @@ static mp_obj_t py_sensor_set_framesize(mp_obj_t framesize) { if (sensor_set_framesize(mp_obj_get_int(framesize)) != 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Failed to set framesize!")); } - return mp_const_true; + return mp_const_none; +} + +static mp_obj_t py_sensor_get_framesize() { + if (sensor.framesize == FRAMESIZE_INVALID) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Frame size not set yet!")); + } + return mp_obj_new_int(sensor.framesize); } static mp_obj_t py_sensor_set_windowing(mp_obj_t roi_obj) { @@ -380,6 +415,10 @@ static mp_obj_t py_sensor_set_hmirror(mp_obj_t enable) { return mp_const_none; } +static mp_obj_t py_sensor_get_hmirror() { + return mp_obj_new_bool(sensor_get_hmirror()); +} + static mp_obj_t py_sensor_set_vflip(mp_obj_t enable) { if (sensor_set_vflip(mp_obj_is_true(enable)) != 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sensor control failed!")); @@ -387,6 +426,32 @@ static mp_obj_t py_sensor_set_vflip(mp_obj_t enable) { return mp_const_none; } +static mp_obj_t py_sensor_get_vflip() { + return mp_obj_new_bool(sensor_get_vflip()); +} + +static mp_obj_t py_sensor_set_transpose(mp_obj_t enable) { + if (sensor_set_transpose(mp_obj_is_true(enable)) != 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Cannot transpose in JPEG mode!")); + } + return mp_const_none; +} + +static mp_obj_t py_sensor_get_transpose() { + return mp_obj_new_bool(sensor_get_transpose()); +} + +static mp_obj_t py_sensor_set_auto_rotation(mp_obj_t enable) { + if (sensor_set_auto_rotation(mp_obj_is_true(enable)) != 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Cannot auto rotate in JPEG mode!")); + } + return mp_const_none; +} + +static mp_obj_t py_sensor_get_auto_rotation() { + return mp_obj_new_bool(sensor_get_auto_rotation()); +} + static mp_obj_t py_sensor_set_special_effect(mp_obj_t sde) { if (sensor_set_special_effect(mp_obj_get_int(sde)) != 0) { return mp_const_false; @@ -611,9 +676,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_id_obj, py_sensor_ge STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_sensor_alloc_extra_fb_obj, py_sensor_alloc_extra_fb); STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_dealloc_extra_fb_obj, py_sensor_dealloc_extra_fb); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_pixformat_obj, py_sensor_set_pixformat); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_pixformat_obj, py_sensor_get_pixformat); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_framerate_obj, py_sensor_set_framerate); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_framesize_obj, py_sensor_set_framesize); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_windowing_obj, py_sensor_set_windowing); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_framesize_obj, py_sensor_get_framesize); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_windowing_obj, py_sensor_set_windowing); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_gainceiling_obj, py_sensor_set_gainceiling); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_contrast_obj, py_sensor_set_contrast); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_brightness_obj, py_sensor_set_brightness); @@ -627,7 +694,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_exposure_us_obj, py_sensor_ge STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_sensor_set_auto_whitebal_obj,1,py_sensor_set_auto_whitebal); STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_rgb_gain_db_obj, py_sensor_get_rgb_gain_db); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_hmirror_obj, py_sensor_set_hmirror); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_hmirror_obj, py_sensor_get_hmirror); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_vflip_obj, py_sensor_set_vflip); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_vflip_obj, py_sensor_get_vflip); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_transpose_obj, py_sensor_set_transpose); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_transpose_obj, py_sensor_get_transpose); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_auto_rotation_obj, py_sensor_set_auto_rotation); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_auto_rotation_obj, py_sensor_get_auto_rotation); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_special_effect_obj, py_sensor_set_special_effect); STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_sensor_set_lens_correction_obj, py_sensor_set_lens_correction); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_vsync_output_obj, py_sensor_set_vsync_output); @@ -638,7 +711,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_sensor_write_reg_obj, py_sensor_wr STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_read_reg_obj, py_sensor_read_reg); STATIC const mp_map_elem_t globals_dict_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_sensor) }, + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_sensor)}, { MP_OBJ_NEW_QSTR(MP_QSTR_BINARY), MP_OBJ_NEW_SMALL_INT(PIXFORMAT_BINARY)}, /* 1BPP/BINARY*/ { MP_OBJ_NEW_QSTR(MP_QSTR_GRAYSCALE), MP_OBJ_NEW_SMALL_INT(PIXFORMAT_GRAYSCALE)},/* 1BPP/GRAYSCALE*/ { MP_OBJ_NEW_QSTR(MP_QSTR_RGB565), MP_OBJ_NEW_SMALL_INT(PIXFORMAT_RGB565)}, /* 2BPP/RGB565*/ @@ -728,8 +801,10 @@ STATIC const mp_map_elem_t globals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_alloc_extra_fb), (mp_obj_t)&py_sensor_alloc_extra_fb_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_dealloc_extra_fb), (mp_obj_t)&py_sensor_dealloc_extra_fb_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_pixformat), (mp_obj_t)&py_sensor_set_pixformat_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_get_pixformat), (mp_obj_t)&py_sensor_get_pixformat_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_framerate), (mp_obj_t)&py_sensor_set_framerate_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_framesize), (mp_obj_t)&py_sensor_set_framesize_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_get_framesize), (mp_obj_t)&py_sensor_get_framesize_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_windowing), (mp_obj_t)&py_sensor_set_windowing_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_gainceiling), (mp_obj_t)&py_sensor_set_gainceiling_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_contrast), (mp_obj_t)&py_sensor_set_contrast_obj }, @@ -744,7 +819,13 @@ STATIC const mp_map_elem_t globals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_set_auto_whitebal), (mp_obj_t)&py_sensor_set_auto_whitebal_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_rgb_gain_db), (mp_obj_t)&py_sensor_get_rgb_gain_db_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_hmirror), (mp_obj_t)&py_sensor_set_hmirror_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_get_hmirror), (mp_obj_t)&py_sensor_get_hmirror_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_vflip), (mp_obj_t)&py_sensor_set_vflip_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_get_vflip), (mp_obj_t)&py_sensor_get_vflip_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_transpose), (mp_obj_t)&py_sensor_set_transpose_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_get_transpose), (mp_obj_t)&py_sensor_get_transpose_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_auto_rotation), (mp_obj_t)&py_sensor_set_auto_rotation_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_get_auto_rotation), (mp_obj_t)&py_sensor_get_auto_rotation_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_special_effect), (mp_obj_t)&py_sensor_set_special_effect_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_lens_correction), (mp_obj_t)&py_sensor_set_lens_correction_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_vsync_output), (mp_obj_t)&py_sensor_set_vsync_output_obj }, diff --git a/src/omv/py/qstrdefsomv.h b/src/omv/py/qstrdefsomv.h index e8634bd38..0e9023050 100644 --- a/src/omv/py/qstrdefsomv.h +++ b/src/omv/py/qstrdefsomv.h @@ -242,8 +242,10 @@ Q(get_id) Q(alloc_extra_fb) Q(dealloc_extra_fb) Q(set_pixformat) +Q(get_pixformat) Q(set_framerate) Q(set_framesize) +Q(get_framesize) Q(set_vsync_output) Q(set_binning) Q(set_windowing) @@ -264,7 +266,13 @@ Q(set_auto_whitebal) Q(rgb_gain_db) Q(get_rgb_gain_db) Q(set_hmirror) +Q(get_hmirror) Q(set_vflip) +Q(get_vflip) +Q(set_transpose) +Q(get_transpose) +Q(set_auto_rotation) +Q(get_auto_rotation) Q(set_special_effect) Q(set_lens_correction) Q(ioctl) diff --git a/src/omv/sensor.c b/src/omv/sensor.c index 41576a75d..ebcb3b2fd 100644 --- a/src/omv/sensor.c +++ b/src/omv/sensor.c @@ -417,12 +417,16 @@ int sensor_init() int sensor_reset() { // Reset the sesnor state - sensor.sde = 0; - sensor.pixformat = 0; - sensor.framesize = 0; - sensor.framerate = 0; - sensor.gainceiling = 0; - sensor.vsync_gpio = NULL; + sensor.sde = 0; + sensor.pixformat = 0; + sensor.framesize = 0; + sensor.framerate = 0; + sensor.gainceiling = 0; + sensor.hmirror = false; + sensor.vflip = false; + sensor.transpose = false; + sensor.auto_rotation = false; + sensor.vsync_gpio = NULL; // Reset default color palette. sensor.color_palette = rainbow_table; @@ -497,6 +501,10 @@ int sensor_set_pixformat(pixformat_t pixformat) return 0; } + if ((sensor.transpose || sensor.auto_rotation) && (pixformat == PIXFORMAT_JPEG)) { + return -1; + } + if (sensor.set_pixformat == NULL || sensor.set_pixformat(&sensor, pixformat) != 0) { // Operation not supported @@ -712,26 +720,80 @@ int sensor_get_rgb_gain_db(float *r_gain_db, float *g_gain_db, float *b_gain_db) int sensor_set_hmirror(int enable) { + if (sensor.hmirror == ((bool) enable)) { + /* no change */ + return 0; + } + /* call the sensor specific function */ if (sensor.set_hmirror == NULL || sensor.set_hmirror(&sensor, enable) != 0) { /* operation not supported */ return -1; } + sensor.hmirror = enable; + systick_sleep(100); // wait for the camera to settle return 0; } +bool sensor_get_hmirror() +{ + return sensor.hmirror; +} + int sensor_set_vflip(int enable) { + if (sensor.vflip == ((bool) enable)) { + /* no change */ + return 0; + } + /* call the sensor specific function */ if (sensor.set_vflip == NULL || sensor.set_vflip(&sensor, enable) != 0) { /* operation not supported */ return -1; } + sensor.vflip = enable; + systick_sleep(100); // wait for the camera to settle return 0; } +bool sensor_get_vflip() +{ + return sensor.vflip; +} + +int sensor_set_transpose(bool enable) +{ + if (sensor.pixformat == PIXFORMAT_JPEG) { + return -1; + } + + sensor.transpose = enable; + return 0; +} + +bool sensor_get_transpose() +{ + return sensor.transpose; +} + +int sensor_set_auto_rotation(bool enable) +{ + if (sensor.pixformat == PIXFORMAT_JPEG) { + return -1; + } + + sensor.auto_rotation = enable; + return 0; +} + +bool sensor_get_auto_rotation() +{ + return sensor.auto_rotation; +} + int sensor_set_special_effect(sde_t sde) { if (sensor.sde == sde) { @@ -846,42 +908,84 @@ void DCMI_DMAConvCpltUser(uint32_t addr) // Skip lines outside the window. if (line >= MAIN_FB()->y && line <= (MAIN_FB()->y + MAIN_FB()->h)) { - switch (sensor.pixformat) { - case PIXFORMAT_BAYER: - dst += (line - MAIN_FB()->y) * MAIN_FB()->w; - src += MAIN_FB()->x; - for (int i = MAIN_FB()->w; i; i--) { - *dst++ = *src++; - } - break; - case PIXFORMAT_GRAYSCALE: - dst += (line - MAIN_FB()->y) * MAIN_FB()->w; - if (sensor.gs_bpp == 1) { + if (!sensor.transpose) { + switch (sensor.pixformat) { + case PIXFORMAT_BAYER: + dst += (line - MAIN_FB()->y) * MAIN_FB()->w; src += MAIN_FB()->x; - // 1BPP GRAYSCALE. for (int i = MAIN_FB()->w; i; i--) { *dst++ = *src++; } - } else { - src16 += MAIN_FB()->x; - // Extract Y channel from YUV. - for (int i = MAIN_FB()->w; i; i--) { - *dst++ = *src16++; + break; + case PIXFORMAT_GRAYSCALE: + dst += (line - MAIN_FB()->y) * MAIN_FB()->w; + if (sensor.gs_bpp == 1) { + src += MAIN_FB()->x; + // 1BPP GRAYSCALE. + for (int i = MAIN_FB()->w; i; i--) { + *dst++ = *src++; + } + } else { + src16 += MAIN_FB()->x; + // Extract Y channel from YUV. + for (int i = MAIN_FB()->w; i; i--) { + *dst++ = *src16++; + } } - } - break; - case PIXFORMAT_YUV422: - case PIXFORMAT_RGB565: - dst16 += (line - MAIN_FB()->y) * MAIN_FB()->w; - src16 += MAIN_FB()->x; - for (int i = MAIN_FB()->w; i; i--) { - *dst16++ = *src16++; - } - break; - case PIXFORMAT_JPEG: - break; - default: - break; + break; + case PIXFORMAT_YUV422: + case PIXFORMAT_RGB565: + dst16 += (line - MAIN_FB()->y) * MAIN_FB()->w; + src16 += MAIN_FB()->x; + for (int i = MAIN_FB()->w; i; i--) { + *dst16++ = *src16++; + } + break; + case PIXFORMAT_JPEG: + default: + break; + } + } else { + switch (sensor.pixformat) { + case PIXFORMAT_BAYER: + dst += line - MAIN_FB()->y; + src += MAIN_FB()->x; + for (int i = MAIN_FB()->w, h = MAIN_FB()->h; i; i--) { + *dst = *src++; + dst += h; + } + break; + case PIXFORMAT_GRAYSCALE: + dst += line - MAIN_FB()->y; + if (sensor.gs_bpp == 1) { + src += MAIN_FB()->x; + // 1BPP GRAYSCALE. + for (int i = MAIN_FB()->w, h = MAIN_FB()->h; i; i--) { + *dst = *src++; + dst += h; + } + } else { + src16 += MAIN_FB()->x; + // Extract Y channel from YUV. + for (int i = MAIN_FB()->w, h = MAIN_FB()->h; i; i--) { + *dst = *src16++; + dst += h; + } + } + break; + case PIXFORMAT_YUV422: + case PIXFORMAT_RGB565: + dst16 += line - MAIN_FB()->y; + src16 += MAIN_FB()->x; + for (int i = MAIN_FB()->w, h = MAIN_FB()->h; i; i--) { + *dst16 = *src16++; + dst16 += h; + } + break; + case PIXFORMAT_JPEG: + default: + break; + } } } @@ -1041,6 +1145,12 @@ int sensor_snapshot(sensor_t *sensor, image_t *image, streaming_cb_t streaming_c break; } + // Fix resolution if transposed. + if (sensor->transpose) { + MAIN_FB()->w = MAIN_FB()->v; // v==h -> w + MAIN_FB()->h = MAIN_FB()->u; // u==w -> h + } + // Set the user image. if (image != NULL) { image->w = MAIN_FB()->w; diff --git a/src/omv/sensor.h b/src/omv/sensor.h index 98ef3aade..26ba40d19 100644 --- a/src/omv/sensor.h +++ b/src/omv/sensor.h @@ -10,7 +10,6 @@ */ #ifndef __SENSOR_H__ #define __SENSOR_H__ -#include #include #include "imlib.h" @@ -170,6 +169,10 @@ typedef struct _sensor { framesize_t framesize; // Frame size framerate_t framerate; // Frame rate gainceiling_t gainceiling; // AGC gainceiling + bool hmirror; // Horizontal Mirror + bool vflip; // Vertical Flip + bool transpose; // Transpose Image + bool auto_rotation; // Rotate Image Automatically // Sensor function pointers int (*reset) (sensor_t *sensor); @@ -278,9 +281,27 @@ int sensor_get_rgb_gain_db(float *r_gain_db, float *g_gain_db, float *b_gain_db) // Enable/disable the hmirror mode. int sensor_set_hmirror(int enable); +// Get hmirror status. +bool sensor_get_hmirror(); + // Enable/disable the vflip mode. int sensor_set_vflip(int enable); +// Get vflip status. +bool sensor_get_vflip(); + +// Enable/disable the transpose mode. +int sensor_set_transpose(bool enable); + +// Get transpose mode state. +bool sensor_get_transpose(); + +// Enable/disable the auto rotation mode. +int sensor_set_auto_rotation(bool enable); + +// Get transpose mode state. +bool sensor_get_auto_rotation(); + // Set special digital effects (SDE). int sensor_set_special_effect(sde_t sde);