Improve sensor module with transpose and get operations

This commit is contained in:
Kwabena W. Agyeman 2020-02-11 10:25:36 -08:00
parent a47ff0748b
commit f314ac4e72
4 changed files with 274 additions and 54 deletions

View File

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

View File

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

View File

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

View File

@ -10,7 +10,6 @@
*/
#ifndef __SENSOR_H__
#define __SENSOR_H__
#include <stdint.h>
#include <stdarg.h>
#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);