Add yuv image processing support

This commit is contained in:
Kwabena W. Agyeman 2021-09-17 09:27:26 -07:00
parent 291e8f0ada
commit bf447e5599
27 changed files with 530 additions and 134 deletions

View File

@ -91,6 +91,7 @@ SRCS += $(addprefix imlib/, \
stats.c \
template.c \
xyz_tab.c \
yuv.c \
zbar.c \
)

View File

@ -179,6 +179,8 @@ typedef enum {
#define SENSOR_HW_FLAGS_BAYER_GBRG (SUBFORMAT_ID_GBRG)
#define SENSOR_HW_FLAGS_BAYER_GRBG (SUBFORMAT_ID_GRBG)
#define SENSOR_HW_FLAGS_BAYER_RGGB (SUBFORMAT_ID_RGGB)
#define SENSOR_HW_FLAGS_YUV422 (SUBFORMAT_ID_YUV422)
#define SENSOR_HW_FLAGS_YVU422 (SUBFORMAT_ID_YVU422)
typedef void (*vsync_cb_t)(uint32_t vsync);
typedef void (*frame_cb_t)();
@ -203,6 +205,7 @@ typedef struct _sensor {
uint32_t rgb_swap:1; // Byte-swap 2BPP RGB formats after capture.
uint32_t yuv_swap:1; // Byte-swap 2BPP YUV formats after capture.
uint32_t bayer:3; // Bayer/CFA pattern.
uint32_t yuv_order:1; // YUV/YVU order.
} hw_flags;
const uint16_t *color_palette; // Color palette used for color lookup.

View File

@ -520,11 +520,11 @@ __weak int sensor_set_pixformat(pixformat_t pixformat)
}
// Some sensor drivers automatically switch to BAYER to reduce the frame size if it does not fit in RAM.
// If the current format is BAYER (1BPP), and the target format is RGB-565 (2BPP) and the frame does not
// If the current format is BAYER (1BPP), and the target format is color and (2BPP), and the frame does not
// fit in RAM it will just be switched back again to BAYER, so we keep the current format unchanged.
uint32_t size = framebuffer_get_buffer_size();
if ((sensor.pixformat == PIXFORMAT_BAYER)
&& (pixformat == PIXFORMAT_RGB565)
&& ((pixformat == PIXFORMAT_RGB565) || (pixformat == PIXFORMAT_YUV422))
&& (MAIN_FB()->u * MAIN_FB()->v * 2 > size)
&& (MAIN_FB()->u * MAIN_FB()->v * 1 <= size)) {
return 0;
@ -1033,7 +1033,7 @@ __weak int sensor_set_special_effect(sde_t sde)
if (sensor.set_special_effect == NULL) {
return SENSOR_ERROR_CTL_UNSUPPORTED;
}
// Call the sensor specific function.
if (sensor.set_special_effect(&sensor, sde) != 0) {
return SENSOR_ERROR_CTL_FAILED;
@ -1124,7 +1124,7 @@ __weak int sensor_auto_crop_framebuffer()
return 0;
}
if (sensor.pixformat == PIXFORMAT_RGB565) {
if ((sensor.pixformat == PIXFORMAT_RGB565) || (sensor.pixformat == PIXFORMAT_YUV422)) {
// Switch to bayer for the quick 2x savings.
sensor_set_pixformat(PIXFORMAT_BAYER);
bpp = 1;

View File

@ -2444,11 +2444,20 @@ void imlib_draw_row(int x_start, int x_end, int y_row, imlib_draw_row_data_t *da
case PIXFORMAT_BAYER_ANY: {
uint8_t *dst8 = (data->dst_row_override
? ((uint8_t *) data->dst_row_override)
: IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(data->dst_img, y_row)) + x_start;
: IMAGE_COMPUTE_BAYER_PIXEL_ROW_PTR(data->dst_img, y_row)) + x_start;
uint8_t *src8 = ((uint8_t *) data->row_buffer[!data->toggle]) + x_start;
unaligned_memcpy(dst8, src8, (x_end - x_start) * sizeof(uint8_t));
break;
}
// Only yuv422 copying/cropping is supported.
case PIXFORMAT_YUV_ANY: {
uint16_t *dst16 = (data->dst_row_override
? ((uint16_t *) data->dst_row_override)
: IMAGE_COMPUTE_YUV_PIXEL_ROW_PTR(data->dst_img, y_row)) + x_start;
uint16_t *src16 = ((uint16_t *) data->row_buffer[!data->toggle]) + x_start;
unaligned_memcpy(dst16, src16, (x_end - x_start) * sizeof(uint16_t));
break;
}
default: {
break;
}
@ -2673,7 +2682,7 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
// rgb_channel extracted / color_palette applied image
image_t new_src_img;
if (((hint & IMAGE_HINT_EXTRACT_RGB_CHANNEL_FIRST) && (rgb_channel != -1) && IMAGE_IS_COLOR(src_img))
if (((hint & IMAGE_HINT_EXTRACT_RGB_CHANNEL_FIRST) && (rgb_channel != -1) && src_img->is_color)
|| ((hint & IMAGE_HINT_APPLY_COLOR_PALETTE_FIRST) && color_palette)) {
new_src_img.w = src_img_w; // same width as source image
new_src_img.h = src_img_h; // same height as source image
@ -2687,11 +2696,10 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
// Special destination?
bool is_jpeg = (src_img->pixfmt == PIXFORMAT_JPEG);
bool is_bayer_or_jpeg = src_img->is_bayer || is_jpeg;
// Best format to convert bayer/jpeg image to.
int is_bayer_or_jpeg_pixfmt = (rgb_channel != -1) ? PIXFORMAT_RGB565 :
(color_palette ? PIXFORMAT_GRAYSCALE :
dst_img->pixfmt);
// Best format to convert yuv/bayer/jpeg image to.
int new_not_mutable_pixfmt = (rgb_channel != -1) ? PIXFORMAT_RGB565 :
(color_palette ? PIXFORMAT_GRAYSCALE :
dst_img->pixfmt);
bool no_scaling_nearest_neighbor = (dst_delta_x == 1)
&& (dst_x_start == 0) && (src_x_start == 0)
@ -2707,21 +2715,23 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
// Do we need to convert the image?
bool is_bayer_color_conversion = src_img->is_bayer && !dst_img->is_bayer;
bool is_yuv_color_conversion = src_img->is_yuv && !dst_img->is_yuv;
bool is_color_conversion = is_bayer_color_conversion || is_yuv_color_conversion;
// Force a deep copy if we cannot use the image in-place.
bool need_deep_copy = (dst_img->data == src_img->data)
&& (is_scaling || (src_img_row_bytes < dst_img_row_bytes) || is_bayer_color_conversion);
&& (is_scaling || (src_img_row_bytes < dst_img_row_bytes) || is_color_conversion);
// Force a deep copy if we are scaling.
bool is_bayer_scaling = is_bayer_color_conversion && is_scaling;
bool is_color_conversion_scaling = is_color_conversion && is_scaling;
// Make a deep copy of the source image.
if (need_deep_copy || is_bayer_scaling || is_jpeg) {
if (need_deep_copy || is_color_conversion_scaling || is_jpeg) {
new_src_img.w = src_img->w; // same width as source image
new_src_img.h = src_img->h; // same height as source image
if (is_bayer_or_jpeg) {
new_src_img.pixfmt = is_bayer_or_jpeg_pixfmt;
if (!src_img->is_mutable) {
new_src_img.pixfmt = new_not_mutable_pixfmt;
size_t size = image_size(&new_src_img);
new_src_img.data = fb_alloc(size, FB_ALLOC_NO_HINT);
@ -2729,7 +2739,9 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
case PIXFORMAT_BINARY: {
if (src_img->is_bayer) {
imlib_debayer_image(&new_src_img, src_img);
} else if (src_img->pixfmt == PIXFORMAT_JPEG) {
} else if (src_img->is_yuv) {
imlib_deyuv_image(&new_src_img, src_img);
} else if (is_jpeg) {
jpeg_decompress_image_to_binary(&new_src_img, src_img);
}
break;
@ -2737,7 +2749,9 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
case PIXFORMAT_GRAYSCALE: {
if (src_img->is_bayer) {
imlib_debayer_image(&new_src_img, src_img);
} else if (src_img->pixfmt == PIXFORMAT_JPEG) {
} else if (src_img->is_yuv) {
imlib_deyuv_image(&new_src_img, src_img);
} else if (is_jpeg) {
jpeg_decompress_image_to_grayscale(&new_src_img, src_img);
}
break;
@ -2745,12 +2759,15 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
case PIXFORMAT_RGB565: {
if (src_img->is_bayer) {
imlib_debayer_image(&new_src_img, src_img);
} else if (src_img->pixfmt == PIXFORMAT_JPEG) {
} else if (src_img->is_yuv) {
imlib_deyuv_image(&new_src_img, src_img);
} else if (is_jpeg) {
jpeg_decompress_image_to_rgb565(&new_src_img, src_img);
}
break;
}
case PIXFORMAT_BAYER_ANY: {
case PIXFORMAT_BAYER_ANY:
case PIXFORMAT_YUV_ANY: {
memcpy(new_src_img.data, src_img->data, size);
break;
}
@ -2770,7 +2787,7 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
imlib_draw_row_data_t imlib_draw_row_data;
imlib_draw_row_data.dst_img = dst_img;
imlib_draw_row_data.src_img_pixfmt = is_bayer_or_jpeg ? is_bayer_or_jpeg_pixfmt : src_img->pixfmt;
imlib_draw_row_data.src_img_pixfmt = (!src_img->is_mutable) ? new_not_mutable_pixfmt : src_img->pixfmt;
imlib_draw_row_data.rgb_channel = rgb_channel;
imlib_draw_row_data.alpha = alpha;
imlib_draw_row_data.color_palette = color_palette;
@ -4538,7 +4555,9 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
} // while y
break;
}
case PIXFORMAT_RGB565: {
case PIXFORMAT_RGB565:
// Re-use RGB565 for yuv.
case PIXFORMAT_YUV_ANY: {
while (y_not_done) {
uint16_t *src_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(src_img, next_src_y_index);
// Must be called per loop to get the address of the temp buffer to blend with
@ -4622,16 +4641,44 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
}
case PIXFORMAT_BAYER_ANY: {
while (y_not_done) {
switch (is_bayer_or_jpeg_pixfmt) {
case PIXFORMAT_BINARY:
case PIXFORMAT_GRAYSCALE:
case PIXFORMAT_RGB565: {
switch (new_not_mutable_pixfmt) {
case PIXFORMAT_MUTABLE_ANY: {
imlib_debayer_line(dst_x_start, dst_x_end, next_src_y_index,
imlib_draw_row_get_row_buffer(&imlib_draw_row_data), is_bayer_or_jpeg_pixfmt, src_img);
imlib_draw_row_get_row_buffer(&imlib_draw_row_data),
new_not_mutable_pixfmt, src_img);
break;
}
case PIXFORMAT_BAYER_ANY: { // Bayer images have the same shape as grayscale.
uint8_t *src_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(src_img, next_src_y_index);
case PIXFORMAT_BAYER_ANY: { // Bayer images have the same shape as GRAYSCALE.
uint8_t *src_row_ptr = IMAGE_COMPUTE_BAYER_PIXEL_ROW_PTR(src_img, next_src_y_index);
imlib_draw_row_put_row_buffer(&imlib_draw_row_data, src_row_ptr);
break;
}
default : {
break;
}
}
imlib_draw_row(dst_x_start, dst_x_end, dst_y, &imlib_draw_row_data);
// Increment offsets
dst_y += dst_delta_y;
src_y_accum += src_y_frac;
next_src_y_index = src_y_accum >> 16;
y_not_done = ++y < dst_y_end;
} // while y
break;
}
case PIXFORMAT_YUV_ANY: {
while (y_not_done) {
switch (new_not_mutable_pixfmt) {
case PIXFORMAT_MUTABLE_ANY: {
imlib_deyuv_line(dst_x_start, dst_x_end, next_src_y_index,
imlib_draw_row_get_row_buffer(&imlib_draw_row_data),
new_not_mutable_pixfmt, src_img);
break;
}
case PIXFORMAT_YUV_ANY: { // YUV images have the same shape as RGB565.
uint16_t *src_row_ptr = IMAGE_COMPUTE_YUV_PIXEL_ROW_PTR(src_img, next_src_y_index);
imlib_draw_row_put_row_buffer(&imlib_draw_row_data, src_row_ptr);
break;
}
@ -4743,7 +4790,9 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
} // while y
break;
}
case PIXFORMAT_RGB565: {
case PIXFORMAT_RGB565:
// Re-use RGB565 for yuv.
case PIXFORMAT_YUV_ANY: {
while (y_not_done) {
int src_y_index = next_src_y_index;
uint16_t *src_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(src_img, src_y_index);

View File

@ -88,13 +88,17 @@ void gif_add_frame(FIL *fp, image_t *img, uint16_t delay)
write_byte(fp, (red<<5) | (green<<2) | blue);
}
}
} else if (IM_IS_BAYER(img)) {
} else if (img->is_bayer || img->is_yuv) {
for (int y=0; y<blocks; y++) {
int block_size = IM_MIN(BLOCK_SIZE, bytes - (y*BLOCK_SIZE));
write_byte(fp, 1 + block_size);
write_byte(fp, 0x80); // clear code
uint16_t pixels[block_size];
imlib_debayer_line(0, block_size, y, pixels, PIXFORMAT_RGB565, img);
if (img->is_bayer) {
imlib_debayer_line(0, block_size, y, pixels, PIXFORMAT_RGB565, img);
} else {
imlib_deyuv_line(0, block_size, y, pixels, PIXFORMAT_RGB565, img);
}
for (int x=0; x<block_size; x++) {
int r = COLOR_RGB565_TO_R8(pixels[x]);
int g = COLOR_RGB565_TO_G8(pixels[x]);
@ -105,7 +109,6 @@ void gif_add_frame(FIL *fp, image_t *img, uint16_t delay)
}
}
write_data(fp, (uint8_t []) {0x01, 0x81, 0x00}, 3); // end code
file_buffer_off(fp);

View File

@ -260,15 +260,14 @@ size_t image_size(image_t *ptr)
case PIXFORMAT_BINARY: {
return IMAGE_BINARY_LINE_LEN_BYTES(ptr) * ptr->h;
}
case PIXFORMAT_GRAYSCALE: {
case PIXFORMAT_GRAYSCALE:
case PIXFORMAT_BAYER_ANY: { // re-use
return IMAGE_GRAYSCALE_LINE_LEN_BYTES(ptr) * ptr->h;
}
case PIXFORMAT_RGB565: {
case PIXFORMAT_RGB565:
case PIXFORMAT_YUV_ANY: { // re-use
return IMAGE_RGB565_LINE_LEN_BYTES(ptr) * ptr->h;
}
case PIXFORMAT_BAYER_ANY: {
return ptr->w * ptr->h;
}
case PIXFORMAT_JPEG: {
return ptr->size;
}

View File

@ -341,20 +341,22 @@ typedef enum {
PIXFORMAT_ID_BINARY = 1,
PIXFORMAT_ID_GRAY = 2,
PIXFORMAT_ID_RGB565 = 3,
PIXFORMAT_ID_YUV422 = 4,
PIXFORMAT_ID_BAYER = 5,
PIXFORMAT_ID_BAYER = 4,
PIXFORMAT_ID_YUV422 = 5,
PIXFORMAT_ID_JPEG = 6,
/* Note: Update PIXFORMAT_IS_VALID when adding new formats */
} pixformat_id_t;
// Pixel sub-format IDs.
typedef enum {
SUBFORMAT_ID_GRAY8 = 0,
SUBFORMAT_ID_GRAY16 = 1,
SUBFORMAT_ID_BGGR = 0, // !!! Note: Make sure bayer sub-formats don't !!!
SUBFORMAT_ID_GBRG = 1, // !!! overflow the sensor.hw_flags.bayer field !!!
SUBFORMAT_ID_GRBG = 2,
SUBFORMAT_ID_RGGB = 3,
SUBFORMAT_ID_GRAY8 = 0,
SUBFORMAT_ID_GRAY16 = 1,
SUBFORMAT_ID_YUV422 = 0,
SUBFORMAT_ID_YVU422 = 1,
/* Note: Update PIXFORMAT_IS_VALID when adding new formats */
} subformat_id_t;
@ -364,45 +366,58 @@ typedef enum {
PIXFORMAT_BPP_GRAY8 = 1,
PIXFORMAT_BPP_GRAY16 = 2,
PIXFORMAT_BPP_RGB565 = 2,
PIXFORMAT_BPP_YUV422 = 2,
PIXFORMAT_BPP_BAYER = 1,
PIXFORMAT_BPP_YUV422 = 2,
/* Note: Update PIXFORMAT_IS_VALID when adding new formats */
} pixformat_bpp_t;
// Pixel format flags.
#define PIXFORMAT_FLAGS_Y (1 << 28) // YUV format.
#define PIXFORMAT_FLAGS_M (1 << 27) // Mutable format.
#define PIXFORMAT_FLAGS_C (1 << 26) // Colored format.
#define PIXFORMAT_FLAGS_J (1 << 25) // Compressed format (JPEG/PNG).
#define PIXFORMAT_FLAGS_R (1 << 24) // RAW/Bayer format.
#define PIXFORMAT_FLAGS_CY (PIXFORMAT_FLAGS_C | PIXFORMAT_FLAGS_Y)
#define PIXFORMAT_FLAGS_CM (PIXFORMAT_FLAGS_C | PIXFORMAT_FLAGS_M)
#define PIXFORMAT_FLAGS_CR (PIXFORMAT_FLAGS_C | PIXFORMAT_FLAGS_R)
#define PIXFORMAT_FLAGS_CJ (PIXFORMAT_FLAGS_C | PIXFORMAT_FLAGS_J)
#define IMLIB_IMAGE_MAX_SIZE(x) ((x) & 0xFFFFFFFF)
// Each pixel format encodes flags, pixel format id and bpp as follows:
// 31......28 27 26 25 24 23..........16 15...........8 7.............0
// <RESERVED> MF CF JF RF <PIXFORMAT_ID> <SUBFORMAT_ID> <BYTES_PER_PIX>
// 31......29 28 27 26 25 24 23..........16 15...........8 7.............0
// <RESERVED> YF MF CF JF RF <PIXFORMAT_ID> <SUBFORMAT_ID> <BYTES_PER_PIX>
// NOTE: Bit 31-30 must Not be used for pixformat_t to be used as mp_int_t.
typedef enum {
PIXFORMAT_INVALID = (0),
PIXFORMAT_BINARY = (PIXFORMAT_FLAGS_M | (PIXFORMAT_ID_BINARY << 16) | (0 << 8) | PIXFORMAT_BPP_BINARY ),
PIXFORMAT_GRAYSCALE = (PIXFORMAT_FLAGS_M | (PIXFORMAT_ID_GRAY << 16) | (SUBFORMAT_ID_GRAY8 << 8) | PIXFORMAT_BPP_GRAY8 ),
PIXFORMAT_RGB565 = (PIXFORMAT_FLAGS_CM | (PIXFORMAT_ID_RGB565 << 16) | (0 << 8) | PIXFORMAT_BPP_RGB565 ),
PIXFORMAT_YUV422 = (PIXFORMAT_FLAGS_CM | (PIXFORMAT_ID_YUV422 << 16) | (0 << 8) | PIXFORMAT_BPP_YUV422 ),
PIXFORMAT_BAYER = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER << 16) | (SUBFORMAT_ID_BGGR << 8) | PIXFORMAT_BPP_BAYER ),
PIXFORMAT_BAYER_BGGR = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER << 16) | (SUBFORMAT_ID_BGGR << 8) | PIXFORMAT_BPP_BAYER ),
PIXFORMAT_BAYER_GBRG = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER << 16) | (SUBFORMAT_ID_GBRG << 8) | PIXFORMAT_BPP_BAYER ),
PIXFORMAT_BAYER_GRBG = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER << 16) | (SUBFORMAT_ID_GRBG << 8) | PIXFORMAT_BPP_BAYER ),
PIXFORMAT_BAYER_RGGB = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER << 16) | (SUBFORMAT_ID_RGGB << 8) | PIXFORMAT_BPP_BAYER ),
PIXFORMAT_JPEG = (PIXFORMAT_FLAGS_J | (PIXFORMAT_ID_JPEG << 16) | (0 << 8) | 0 ),
PIXFORMAT_BINARY = (PIXFORMAT_FLAGS_M | (PIXFORMAT_ID_BINARY << 16) | (0 << 8) | PIXFORMAT_BPP_BINARY ),
PIXFORMAT_GRAYSCALE = (PIXFORMAT_FLAGS_M | (PIXFORMAT_ID_GRAY << 16) | (SUBFORMAT_ID_GRAY8 << 8) | PIXFORMAT_BPP_GRAY8 ),
PIXFORMAT_RGB565 = (PIXFORMAT_FLAGS_CM | (PIXFORMAT_ID_RGB565 << 16) | (0 << 8) | PIXFORMAT_BPP_RGB565 ),
PIXFORMAT_BAYER = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER << 16) | (SUBFORMAT_ID_BGGR << 8) | PIXFORMAT_BPP_BAYER ),
PIXFORMAT_BAYER_BGGR = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER << 16) | (SUBFORMAT_ID_BGGR << 8) | PIXFORMAT_BPP_BAYER ),
PIXFORMAT_BAYER_GBRG = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER << 16) | (SUBFORMAT_ID_GBRG << 8) | PIXFORMAT_BPP_BAYER ),
PIXFORMAT_BAYER_GRBG = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER << 16) | (SUBFORMAT_ID_GRBG << 8) | PIXFORMAT_BPP_BAYER ),
PIXFORMAT_BAYER_RGGB = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER << 16) | (SUBFORMAT_ID_RGGB << 8) | PIXFORMAT_BPP_BAYER ),
PIXFORMAT_YUV422 = (PIXFORMAT_FLAGS_CY | (PIXFORMAT_ID_YUV422 << 16) | (SUBFORMAT_ID_YUV422 << 8) | PIXFORMAT_BPP_YUV422 ),
PIXFORMAT_YVU422 = (PIXFORMAT_FLAGS_CY | (PIXFORMAT_ID_YUV422 << 16) | (SUBFORMAT_ID_YVU422 << 8) | PIXFORMAT_BPP_YUV422 ),
PIXFORMAT_JPEG = (PIXFORMAT_FLAGS_CJ | (PIXFORMAT_ID_JPEG << 16) | (0 << 8) | 0 ),
PIXFORMAT_LAST = 0xFFFFFFFFU,
} pixformat_t;
#define PIXFORMAT_MUTABLE_ANY \
PIXFORMAT_BINARY: \
case PIXFORMAT_GRAYSCALE: \
case PIXFORMAT_RGB565 \
#define PIXFORMAT_BAYER_ANY \
PIXFORMAT_BAYER_BGGR: \
case PIXFORMAT_BAYER_GBRG: \
case PIXFORMAT_BAYER_GRBG: \
case PIXFORMAT_BAYER_RGGB \
#define PIXFORMAT_YUV_ANY \
PIXFORMAT_YUV422: \
case PIXFORMAT_YVU422 \
#define IMLIB_PIXFORMAT_IS_VALID(x) \
((x == PIXFORMAT_BINARY) \
|| (x == PIXFORMAT_GRAYSCALE) \
@ -411,6 +426,8 @@ typedef enum {
|| (x == PIXFORMAT_BAYER_GBRG) \
|| (x == PIXFORMAT_BAYER_GRBG) \
|| (x == PIXFORMAT_BAYER_RGGB) \
|| (x == PIXFORMAT_YUV422) \
|| (x == PIXFORMAT_YVU422) \
|| (x == PIXFORMAT_JPEG)) \
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
@ -425,7 +442,8 @@ struct { \
uint32_t is_compressed :1; \
uint32_t is_color :1; \
uint32_t is_mutable :1; \
uint32_t /*reserved*/ :4; \
uint32_t is_yuv :1; \
uint32_t /*reserved*/ :3; \
}; \
uint32_t pixfmt; \
}; \
@ -436,7 +454,8 @@ struct { \
struct { \
union { \
struct { \
uint32_t /*reserved*/ :4; \
uint32_t /*reserved*/ :3; \
uint32_t is_yuv :1; \
uint32_t is_mutable :1; \
uint32_t is_color :1; \
uint32_t is_compressed :1; \
@ -468,10 +487,6 @@ void image_copy(image_t *dst, image_t *src);
size_t image_size(image_t *ptr);
bool image_get_mask_pixel(image_t *ptr, int x, int y);
#define IMAGE_IS_MUTABLE(image) (image->is_mutable)
#define IMAGE_IS_COLOR(image) (image->is_color)
#define IMAGE_IS_MUTABLE_BAYER(image) (image->is_mutable || image->is_bayer)
#define IMAGE_BINARY_LINE_LEN(image) (((image)->w + UINT32_T_MASK) >> UINT32_T_SHIFT)
#define IMAGE_BINARY_LINE_LEN_BYTES(image) (IMAGE_BINARY_LINE_LEN(image) * sizeof(uint32_t))
@ -550,6 +565,40 @@ bool image_get_mask_pixel(image_t *ptr, int x, int y);
((uint16_t *) _image->data)[(_image->w * _y) + _x] = _v; \
})
#define IMAGE_GET_YUV_PIXEL(image, x, y) \
({ \
__typeof__ (image) _image = (image); \
__typeof__ (x) _x = (x); \
__typeof__ (y) _y = (y); \
((uint16_t *) _image->data)[(_image->w * _y) + _x]; \
})
#define IMAGE_PUT_YUV_PIXEL(image, x, y, v) \
({ \
__typeof__ (image) _image = (image); \
__typeof__ (x) _x = (x); \
__typeof__ (y) _y = (y); \
__typeof__ (v) _v = (v); \
((uint16_t *) _image->data)[(_image->w * _y) + _x] = _v; \
})
#define IMAGE_GET_BAYER_PIXEL(image, x, y) \
({ \
__typeof__ (image) _image = (image); \
__typeof__ (x) _x = (x); \
__typeof__ (y) _y = (y); \
((uint8_t *) _image->data)[(_image->w * _y) + _x]; \
})
#define IMAGE_PUT_BAYER_PIXEL(image, x, y, v) \
({ \
__typeof__ (image) _image = (image); \
__typeof__ (x) _x = (x); \
__typeof__ (y) _y = (y); \
__typeof__ (v) _v = (v); \
((uint8_t *) _image->data)[(_image->w * _y) + _x] = _v; \
})
// Fast Stuff //
#define IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(image, y) \
@ -634,6 +683,20 @@ bool image_get_mask_pixel(image_t *ptr, int x, int y);
_row_ptr[_x] = _v; \
})
#define IMAGE_COMPUTE_BAYER_PIXEL_ROW_PTR(image, y) \
({ \
__typeof__ (image) _image = (image); \
__typeof__ (y) _y = (y); \
((uint8_t *) _image->data) + (_image->w * _y); \
})
#define IMAGE_COMPUTE_YUV_PIXEL_ROW_PTR(image, y) \
({ \
__typeof__ (image) _image = (image); \
__typeof__ (y) _y = (y); \
((uint16_t *) _image->data) + (_image->w * _y); \
})
// Old Image Macros - Will be refactor and removed. But, only after making sure through testing new macros work.
// Image kernels
@ -1016,6 +1079,10 @@ void imlib_fill_image_from_float(image_t *img, int w, int h, float *data, float
void imlib_debayer_line(int x_start, int x_end, int y_row, void *dst_row_ptr, pixformat_t pixfmt, image_t *src);
void imlib_debayer_image(image_t *dst, image_t *src);
// YUV Image Processing
void imlib_deyuv_line(int x_start, int x_end, int y_row, void *dst_row_ptr, pixformat_t pixfmt, image_t *src);
void imlib_deyuv_image(image_t *dst, image_t *src);
/* Color space functions */
int8_t imlib_rgb565_to_l(uint16_t pixel);
int8_t imlib_rgb565_to_a(uint16_t pixel);

View File

@ -148,7 +148,9 @@ static void jpeg_get_mcu(image_t *src, int x_offset, int y_offset, int dx, int d
}
case PIXFORMAT_RGB565: {
if ((dx != MCU_W) || (dy != MCU_H)) { // partial MCU, fill with 0's to start
memset(Y0, 0, JPEG_444_YCBCR_MCU_SIZE);
memset(Y0, 0, JPEG_444_GS_MCU_SIZE);
memset(CB, 0, JPEG_444_GS_MCU_SIZE);
memset(CR, 0, JPEG_444_GS_MCU_SIZE);
}
for (int y = y_offset, yy = y + dy, index = 0; y < yy; y++) {
@ -220,9 +222,79 @@ static void jpeg_get_mcu(image_t *src, int x_offset, int y_offset, int dx, int d
}
break;
}
case PIXFORMAT_YUV_ANY: {
if ((dx != MCU_W) || (dy != MCU_H)) { // partial MCU, fill with 0's to start
memset(Y0, 0, JPEG_444_GS_MCU_SIZE);
memset(CB, 0, JPEG_444_GS_MCU_SIZE);
memset(CR, 0, JPEG_444_GS_MCU_SIZE);
}
int shift = (src->pixfmt == PIXFORMAT_YUV422) ? 24 : 8;
for (int y = y_offset, yy = y + dy, index = 0; y < yy; y++) {
uint32_t *rp = (uint32_t *) (IMAGE_COMPUTE_YUV_PIXEL_ROW_PTR(src, y) + x_offset);
for (int x = 0, xx = dx - 1; x < xx; x += 2, index += 2) {
int pixels = *rp++;
#if (OMV_HARDWARE_JPEG == 0)
pixels ^= 0x80808080;
#endif
Y0[index] = pixels, Y0[index + 1] = pixels >> 16;
int cb = pixels >> shift;
CB[index] = cb, CB[index + 1] = cb;
int cr = pixels >> (32 - shift);
CR[index] = cr, CR[index + 1] = cr;
}
if (dx & 1) {
int pixel = *((uint16_t *) rp);
#if (OMV_HARDWARE_JPEG == 0)
pixel ^= 0x8080;
#endif
Y0[index] = pixel;
if (index % MCU_W) {
if (shift == 8) {
CR[index] = CR[index - 1];
CB[index++] = pixel >> 8;
} else {
CB[index] = CB[index - 1];
CR[index++] = pixel >> 8;
}
} else {
if (shift == 8) {
CB[index] = pixel >> 8;
#if (OMV_HARDWARE_JPEG == 0)
CR[index++] = 0;
#else
CR[index++] = 0x80;
#endif
} else {
#if (OMV_HARDWARE_JPEG == 0)
CB[index] = 0;
#else
CB[index] = 0x80;
#endif
CR[index++] = pixel >> 8;
}
}
}
index += MCU_W - dx;
}
break;
}
case PIXFORMAT_BAYER_ANY: {
if ((dx != MCU_W) || (dy != MCU_H)) { // partial MCU, fill with 0's to start
memset(Y0, 0, JPEG_444_YCBCR_MCU_SIZE);
memset(Y0, 0, JPEG_444_GS_MCU_SIZE);
memset(CB, 0, JPEG_444_GS_MCU_SIZE);
memset(CR, 0, JPEG_444_GS_MCU_SIZE);
}
int src_w = src->w, w_limit = src_w - 1, w_limit_m_1 = w_limit - 1;
@ -987,6 +1059,7 @@ bool jpeg_compress(image_t *src, image_t *dst, int quality, bool realloc)
break;
case PIXFORMAT_RGB565:
case PIXFORMAT_BAYER_ANY:
case PIXFORMAT_YUV_ANY:
mcu_size = JPEG_444_YCBCR_MCU_SIZE;
JPEG_Info.ColorSpace = JPEG_YCBCR_COLORSPACE;
JPEG_Info.ChromaSubsampling = JPEG_444_SUBSAMPLING;

127
src/omv/imlib/yuv.c Normal file
View File

@ -0,0 +1,127 @@
/*
* This file is part of the OpenMV project.
*
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
* Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
*
* This work is licensed under the MIT license, see the file LICENSE for details.
*
* Deyuv Functions
*/
#include "imlib.h"
void imlib_deyuv_line(int x_start, int x_end, int y_row, void *dst_row_ptr, pixformat_t pixfmt, image_t *src)
{
int shift = (src->pixfmt == PIXFORMAT_YUV422) ? 16 : 0;
int src_w = src->w, w_limit = src_w - 1;
uint16_t *rowptr_yuv = ((uint16_t *) src->data) + (y_row * src_w);
// If the image is an odd width this will go for the last loop and we drop the last column.
for (int x = x_start; x < x_end; x += 2) {
int32_t row_yuv; // signed
// keep pixels in bounds
if (x >= w_limit) {
if (src_w >= 2) {
uint32_t temp = *((uint32_t *) (rowptr_yuv + x - 1));
row_yuv = ((temp & 0xff00) << 16) | (temp & 0xff0000) | (temp >> 16);
} else {
row_yuv = *((uint16_t *) (rowptr_yuv + x));
row_yuv = ((row_yuv & 0xff) << 16) | 0x80000000;
}
} else {
row_yuv = *((uint32_t *) (rowptr_yuv + x));
}
int y0 = row_yuv & 0xff, y1 = (row_yuv >> 16) & 0xff;
switch (pixfmt) {
case PIXFORMAT_BINARY: {
uint32_t *row_ptr_32 = (uint32_t *) dst_row_ptr;
IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr_32, x, (y0 >> 7));
if (x != w_limit) {
IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr_32, x + 1, (y1 >> 7));
}
break;
}
case PIXFORMAT_GRAYSCALE: {
uint8_t *row_ptr_8 = (uint8_t *) dst_row_ptr;
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr_8, x, y0);
if (x != w_limit) {
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr_8, x + 1, y1);
}
break;
}
case PIXFORMAT_RGB565: {
uint16_t *row_ptr_16 = (uint16_t *) dst_row_ptr;
// R = Y + (1.40200 * U)
// G = Y - (0.34414 * V) - (0.71414 * U)
// B = Y + (1.77200 * V)
// R = Y + ((179 * U) >> 7)
// G = Y - (((44 * V) - (91 * U)) >> 7)
// B = Y + ((227 * V) >> 7)
row_yuv ^= 0x80008000;
int u = (row_yuv << shift) >> 24; // signed bit extraction
int v = (row_yuv << (16 - shift)) >> 24; // signed bit extraction
int ry = (179 * u) >> 7;
int gy = ((44 * v) + (91 * u)) >> 7;
int by = (227 * v) >> 7;
int r0 = y0 + ry, g0 = y0 - gy, b0 = y0 + by;
r0 = IM_MIN(IM_MAX(r0, COLOR_R8_MIN), COLOR_R8_MAX);
g0 = IM_MIN(IM_MAX(g0, COLOR_G8_MIN), COLOR_G8_MAX);
b0 = IM_MIN(IM_MAX(b0, COLOR_B8_MIN), COLOR_B8_MAX);
int rgb565_0 = COLOR_R8_G8_B8_TO_RGB565(r0, g0, b0);
IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr_16, x, rgb565_0);
if (x != w_limit) {
int r1 = y1 + ry, g1 = y1 - gy, b1 = y1 + by;
r1 = IM_MIN(IM_MAX(r1, COLOR_R8_MIN), COLOR_R8_MAX);
g1 = IM_MIN(IM_MAX(g1, COLOR_G8_MIN), COLOR_G8_MAX);
b1 = IM_MIN(IM_MAX(b1, COLOR_B8_MIN), COLOR_B8_MAX);
int rgb565_1 = COLOR_R8_G8_B8_TO_RGB565(r1, g1, b1);
IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr_16, x + 1, rgb565_1);
}
break;
}
default: {
break;
}
}
}
}
void imlib_deyuv_image(image_t *dst, image_t *src)
{
for (int y = 0, src_w = src->w, src_h = src->h; y < src_h; y++) {
void *row_ptr = NULL;
switch (dst->pixfmt) {
case PIXFORMAT_BINARY: {
row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(dst, y);
break;
}
case PIXFORMAT_GRAYSCALE: {
row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(dst, y);
break;
}
case PIXFORMAT_RGB565: {
row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(dst, y);
break;
}
}
imlib_deyuv_line(0, src_w, y, row_ptr, dst->pixfmt, src);
}
}

View File

@ -1082,7 +1082,7 @@ mp_obj_t py_fir_snapshot(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
if (mp_obj_is_integer(copy_to_fb_obj)) {
copy_to_fb = mp_obj_get_int(copy_to_fb_obj);
} else {
arg_other = py_helper_arg_to_image_mutable_bayer(copy_to_fb_obj);
arg_other = py_helper_arg_to_image_not_compressed(copy_to_fb_obj);
}
}

View File

@ -27,21 +27,14 @@ MP_DEFINE_CONST_FUN_OBJ_KW(py_func_unavailable_obj, 0, py_func_unavailable);
image_t *py_helper_arg_to_image_mutable(const mp_obj_t arg)
{
image_t *arg_img = py_image_cobj(arg);
PY_ASSERT_TRUE_MSG(IMAGE_IS_MUTABLE(arg_img), "Image is not mutable!");
PY_ASSERT_TRUE_MSG(arg_img->is_mutable, "Image is not mutable!");
return arg_img;
}
image_t *py_helper_arg_to_image_mutable_bayer(const mp_obj_t arg)
image_t *py_helper_arg_to_image_not_compressed(const mp_obj_t arg)
{
image_t *arg_img = py_image_cobj(arg);
PY_ASSERT_TRUE_MSG(IMAGE_IS_MUTABLE_BAYER(arg_img), "Image is not mutable!");
return arg_img;
}
image_t *py_helper_arg_to_image_mutable_bayer_jpeg(const mp_obj_t arg)
{
image_t *arg_img = py_image_cobj(arg);
PY_ASSERT_TRUE_MSG(IMLIB_PIXFORMAT_IS_VALID(arg_img->pixfmt), "Image is not mutable!");
PY_ASSERT_FALSE_MSG(arg_img->is_compressed, "Image is compressed!");
return arg_img;
}
@ -52,13 +45,6 @@ image_t *py_helper_arg_to_image_grayscale(const mp_obj_t arg)
return arg_img;
}
image_t *py_helper_arg_to_image_color(const mp_obj_t arg)
{
image_t *arg_img = py_image_cobj(arg);
PY_ASSERT_TRUE_MSG(arg_img->pixfmt == PIXFORMAT_RGB565, "Image is not RGB565!");
return arg_img;
}
image_t *py_helper_keyword_to_image_mutable(uint n_args, const mp_obj_t *args, uint arg_index,
mp_map_t *kw_args, mp_obj_t kw, image_t *default_val)
{

View File

@ -13,10 +13,8 @@
#include "imlib.h"
extern const mp_obj_fun_builtin_var_t py_func_unavailable_obj;
image_t *py_helper_arg_to_image_mutable(const mp_obj_t arg);
image_t *py_helper_arg_to_image_mutable_bayer(const mp_obj_t arg);
image_t *py_helper_arg_to_image_mutable_bayer_jpeg(const mp_obj_t arg);
image_t *py_helper_arg_to_image_not_compressed(const mp_obj_t arg);
image_t *py_helper_arg_to_image_grayscale(const mp_obj_t arg);
image_t *py_helper_arg_to_image_color(const mp_obj_t arg);
image_t *py_helper_keyword_to_image_mutable(uint n_args, const mp_obj_t *args, uint arg_index,
mp_map_t *kw_args, mp_obj_t kw, image_t *default_val);
image_t *py_helper_keyword_to_image_mutable_mask(uint n_args, const mp_obj_t *args, uint arg_index,

View File

@ -312,8 +312,8 @@ STATIC mp_obj_t py_image_it_iternext(mp_obj_t self_in)
return row;
}
}
case PIXFORMAT_BAYER_ANY:
case PIXFORMAT_GRAYSCALE: {
case PIXFORMAT_GRAYSCALE:
case PIXFORMAT_BAYER_ANY: {
if (self->cur >= img->h) {
return MP_OBJ_STOP_ITERATION;
} else {
@ -325,7 +325,8 @@ STATIC mp_obj_t py_image_it_iternext(mp_obj_t self_in)
return row;
}
}
case PIXFORMAT_RGB565: {
case PIXFORMAT_RGB565:
case PIXFORMAT_YUV_ANY: {
if (self->cur >= img->h) {
return MP_OBJ_STOP_ITERATION;
} else {
@ -373,8 +374,13 @@ static void py_image_print(const mp_print_t *print, mp_obj_t self, mp_print_kind
(image->pixfmt == PIXFORMAT_BINARY) ? "binary" :
(image->pixfmt == PIXFORMAT_GRAYSCALE) ? "grayscale" :
(image->pixfmt == PIXFORMAT_RGB565) ? "rgb565" :
(image->pixfmt == PIXFORMAT_BAYER_BGGR) ? "bayer_bggr" :
(image->pixfmt == PIXFORMAT_BAYER_GBRG) ? "bayer_gbrg" :
(image->pixfmt == PIXFORMAT_BAYER_GRBG) ? "bayer_grbg" :
(image->pixfmt == PIXFORMAT_BAYER_RGGB) ? "bayer_rggb" :
(image->pixfmt == PIXFORMAT_YUV422) ? "yuv422" :
(image->pixfmt == PIXFORMAT_JPEG) ? "jpeg" : "bayer",
(image->pixfmt == PIXFORMAT_YVU422) ? "yvu422" :
(image->pixfmt == PIXFORMAT_JPEG) ? "jpeg" : "unknown",
image_size(image));
}
}
@ -401,8 +407,8 @@ static mp_obj_t py_image_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value
mp_uint_t i = mp_get_index(self->base.type, image->w * image->h, index, false);
return mp_obj_new_int(IMAGE_GET_BINARY_PIXEL(image, i % image->w, i / image->w));
}
case PIXFORMAT_BAYER_ANY:
case PIXFORMAT_GRAYSCALE: {
case PIXFORMAT_GRAYSCALE:
case PIXFORMAT_BAYER_ANY: {
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(image->w * image->h, index, &slice)) {
@ -419,7 +425,8 @@ static mp_obj_t py_image_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value
uint8_t p = IMAGE_GET_GRAYSCALE_PIXEL(image, i % image->w, i / image->w);
return mp_obj_new_int(p);
}
case PIXFORMAT_RGB565: {
case PIXFORMAT_RGB565:
case PIXFORMAT_YUV_ANY: {
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(image->w * image->h, index, &slice)) {
@ -428,17 +435,27 @@ static mp_obj_t py_image_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value
mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL);
for (mp_uint_t i = 0; i < result->len; i++) {
uint16_t p = IMAGE_GET_RGB565_PIXEL(image, (slice.start + i) % image->w, (slice.start + i) / image->w);
result->items[i] = mp_obj_new_tuple(3, (mp_obj_t []) {mp_obj_new_int(COLOR_RGB565_TO_R8(p)),
mp_obj_new_int(COLOR_RGB565_TO_G8(p)),
mp_obj_new_int(COLOR_RGB565_TO_B8(p))});
if (image->is_yuv) {
result->items[i] = mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(p & 0xff),
mp_obj_new_int((p >> 8) & 0xff)});
} else {
result->items[i] = mp_obj_new_tuple(3, (mp_obj_t []) {mp_obj_new_int(COLOR_RGB565_TO_R8(p)),
mp_obj_new_int(COLOR_RGB565_TO_G8(p)),
mp_obj_new_int(COLOR_RGB565_TO_B8(p))});
}
}
return result;
}
mp_uint_t i = mp_get_index(self->base.type, image->w * image->h, index, false);
uint16_t p = IMAGE_GET_RGB565_PIXEL(image, i % image->w, i / image->w);
return mp_obj_new_tuple(3, (mp_obj_t []) {mp_obj_new_int(COLOR_RGB565_TO_R8(p)),
mp_obj_new_int(COLOR_RGB565_TO_G8(p)),
mp_obj_new_int(COLOR_RGB565_TO_B8(p))});
if (image->is_yuv) {
return mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(p & 0xff),
mp_obj_new_int((p >> 8) & 0xff)});
} else {
return mp_obj_new_tuple(3, (mp_obj_t []) {mp_obj_new_int(COLOR_RGB565_TO_R8(p)),
mp_obj_new_int(COLOR_RGB565_TO_G8(p)),
mp_obj_new_int(COLOR_RGB565_TO_B8(p))});
}
}
case PIXFORMAT_JPEG: {
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
@ -486,8 +503,8 @@ static mp_obj_t py_image_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value
IMAGE_PUT_BINARY_PIXEL(image, i % image->w, i / image->w, mp_obj_get_int(value));
return mp_const_none;
}
case PIXFORMAT_BAYER_ANY:
case PIXFORMAT_GRAYSCALE: {
case PIXFORMAT_GRAYSCALE:
case PIXFORMAT_BAYER_ANY: {
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(image->w * image->h, index, &slice)) {
@ -515,7 +532,8 @@ static mp_obj_t py_image_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value
IMAGE_PUT_GRAYSCALE_PIXEL(image, i % image->w, i / image->w, p);
return mp_const_none;
}
case PIXFORMAT_RGB565: {
case PIXFORMAT_RGB565:
case PIXFORMAT_YUV_ANY: {
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(image->w * image->h, index, &slice)) {
@ -528,16 +546,36 @@ static mp_obj_t py_image_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value
PY_ASSERT_TRUE_MSG(value_l_len == (slice.stop - slice.start), "cannot grow or shrink image");
for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) {
mp_obj_t *value_2;
mp_obj_get_array_fixed_n(value_l[i], 3, &value_2);
uint16_t p = COLOR_R8_G8_B8_TO_RGB565(mp_obj_get_int(value_2[0]), mp_obj_get_int(value_2[1]), mp_obj_get_int(value_2[2]));
IMAGE_PUT_RGB565_PIXEL(image, (slice.start + i) % image->w, (slice.start + i) / image->w, p);
uint16_t p;
if (image->is_yuv) {
mp_obj_get_array_fixed_n(value_l[i], 2, &value_2);
p = (mp_obj_get_int(value_2[0]) & 0xff) |
(mp_obj_get_int(value_2[1]) & 0xff) << 8;
} else {
mp_obj_get_array_fixed_n(value_l[i], 3, &value_2);
p = COLOR_R8_G8_B8_TO_RGB565(mp_obj_get_int(value_2[0]),
mp_obj_get_int(value_2[1]),
mp_obj_get_int(value_2[2]));
}
IMAGE_PUT_RGB565_PIXEL(image, (slice.start + i) % image->w,
(slice.start + i) / image->w, p);
}
} else {
mp_obj_t *value_2;
mp_obj_get_array_fixed_n(value, 3, &value_2);
uint16_t p = COLOR_R8_G8_B8_TO_RGB565(mp_obj_get_int(value_2[0]), mp_obj_get_int(value_2[1]), mp_obj_get_int(value_2[2]));
uint16_t p;
if (image->is_yuv) {
mp_obj_get_array_fixed_n(value, 2, &value_2);
p = (mp_obj_get_int(value_2[0]) & 0xff) |
(mp_obj_get_int(value_2[1]) & 0xff) << 8;
} else {
mp_obj_get_array_fixed_n(value, 3, &value_2);
p = COLOR_R8_G8_B8_TO_RGB565(mp_obj_get_int(value_2[0]),
mp_obj_get_int(value_2[1]),
mp_obj_get_int(value_2[2]));
}
for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) {
IMAGE_PUT_RGB565_PIXEL(image, (slice.start + i) % image->w, (slice.start + i) / image->w, p);
IMAGE_PUT_RGB565_PIXEL(image, (slice.start + i) % image->w,
(slice.start + i) / image->w, p);
}
}
return mp_const_none;
@ -626,6 +664,8 @@ static mp_obj_t py_image_format(mp_obj_t img_obj)
return mp_obj_new_int(PIXFORMAT_RGB565);
case PIXFORMAT_BAYER_ANY:
return mp_obj_new_int(PIXFORMAT_BAYER);
case PIXFORMAT_YUV_ANY:
return mp_obj_new_int(PIXFORMAT_YUV422);
default:
return mp_obj_new_int(PIXFORMAT_JPEG);
}
@ -647,7 +687,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_bytearray_obj, py_image_bytearray);
STATIC mp_obj_t py_image_get_pixel(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]);
image_t *arg_img = py_helper_arg_to_image_not_compressed(args[0]);
const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 1, 2, &arg_vec);
@ -707,7 +747,18 @@ STATIC mp_obj_t py_image_get_pixel(uint n_args, const mp_obj_t *args, mp_map_t *
pixel_tuple[2] = mp_obj_new_int(COLOR_RGB565_TO_B8(pixel));
return mp_obj_new_tuple(3, pixel_tuple);
} else {
return mp_obj_new_int(IMAGE_GET_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y)); // Correct!
return mp_obj_new_int(IMAGE_GET_BAYER_PIXEL(arg_img, arg_x, arg_y));
}
case PIXFORMAT_YUV_ANY:
if (arg_rgbtuple) {
uint16_t pixel; imlib_deyuv_line(arg_x, arg_x + 1, arg_y, &pixel, PIXFORMAT_RGB565, arg_img);
mp_obj_t pixel_tuple[3];
pixel_tuple[0] = mp_obj_new_int(COLOR_RGB565_TO_R8(pixel));
pixel_tuple[1] = mp_obj_new_int(COLOR_RGB565_TO_G8(pixel));
pixel_tuple[2] = mp_obj_new_int(COLOR_RGB565_TO_B8(pixel));
return mp_obj_new_tuple(3, pixel_tuple);
} else {
return mp_obj_new_int(IMAGE_GET_YUV_PIXEL(arg_img, arg_x, arg_y));
}
default: return mp_const_none;
}
@ -716,7 +767,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_get_pixel_obj, 2, py_image_get_pixel)
STATIC mp_obj_t py_image_set_pixel(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]);
image_t *arg_img = py_helper_arg_to_image_not_compressed(args[0]);
const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 1, 2, &arg_vec);
@ -735,18 +786,16 @@ STATIC mp_obj_t py_image_set_pixel(uint n_args, const mp_obj_t *args, mp_map_t *
IMAGE_PUT_BINARY_PIXEL(arg_img, arg_x, arg_y, arg_c);
return args[0];
}
case PIXFORMAT_GRAYSCALE: {
case PIXFORMAT_GRAYSCALE:
case PIXFORMAT_BAYER_ANY: { // re-use
IMAGE_PUT_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y, arg_c);
return args[0];
}
case PIXFORMAT_RGB565: {
case PIXFORMAT_RGB565:
case PIXFORMAT_YUV_ANY: { // re-use
IMAGE_PUT_RGB565_PIXEL(arg_img, arg_x, arg_y, arg_c);
return args[0];
}
case PIXFORMAT_BAYER_ANY: {
IMAGE_PUT_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y, arg_c); // Correct!
return args[0];
}
default: return args[0];
}
}
@ -861,7 +910,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_pooled_obj, 3, py_image_midp
static mp_obj_t py_image_to(pixformat_t pixfmt, const uint16_t *default_color_palette, bool copy_to_fb,
uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *src_img = py_helper_arg_to_image_mutable_bayer_jpeg(args[0]);
image_t *src_img = py_image_cobj(args[0]);
float arg_x_scale = 1.f;
bool got_x_scale = py_helper_keyword_float_maybe(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_scale), &arg_x_scale);
@ -926,7 +975,7 @@ static mp_obj_t py_image_to(pixformat_t pixfmt, const uint16_t *default_color_pa
if (mp_obj_is_integer(copy_obj)) {
copy = mp_obj_get_int(copy_obj);
} else {
arg_other = py_helper_arg_to_image_mutable_bayer(copy_obj);
arg_other = py_helper_arg_to_image_not_compressed(copy_obj);
}
}
@ -1004,6 +1053,24 @@ static mp_obj_t py_image_to(pixformat_t pixfmt, const uint16_t *default_color_pa
IMAGE_HINT_EXTRACT_RGB_CHANNEL_FIRST |
IMAGE_HINT_APPLY_COLOR_PALETTE_FIRST);
}
} else if (dst_img.is_yuv) {
if (((arg_x_scale != 1) && (arg_x_scale != -1)) ||
((arg_y_scale != 1) && (arg_y_scale != -1)) ||
(arg_rgb_channel != -1) ||
(arg_alpha != 256) ||
(color_palette != NULL) ||
(alpha_palette != NULL)) {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Only YUV422 copying/cropping is supported!"));
} else {
if (arg_roi.x % 2) {
dst_img.pixfmt = (dst_img.pixfmt == PIXFORMAT_YUV422) ? PIXFORMAT_YVU422 : PIXFORMAT_YUV422;
}
hint &= ~(IMAGE_HINT_AREA |
IMAGE_HINT_BICUBIC |
IMAGE_HINT_BILINEAR |
IMAGE_HINT_EXTRACT_RGB_CHANNEL_FIRST |
IMAGE_HINT_APPLY_COLOR_PALETTE_FIRST);
}
} else if (dst_img.pixfmt == PIXFORMAT_JPEG) {
if ((arg_x_scale != 1) ||
(arg_y_scale != 1) ||
@ -1138,7 +1205,7 @@ static mp_obj_t py_image_compress(uint n_args, const mp_obj_t *args, mp_map_t *k
{
if (IM_IS_JPEG((image_t *) py_image_cobj(args[0]))) return args[0];
image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]);
image_t *arg_img = py_helper_arg_to_image_not_compressed(args[0]);
int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50);
PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!");
@ -1158,7 +1225,7 @@ static mp_obj_t py_image_compress_for_ide(uint n_args, const mp_obj_t *args, mp_
{
if (IM_IS_JPEG((image_t *) py_image_cobj(args[0]))) return py_image_jpeg_encode_for_ide(args[0]);
image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]);
image_t *arg_img = py_helper_arg_to_image_not_compressed(args[0]);
int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50);
PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!");
@ -1186,7 +1253,7 @@ static mp_obj_t py_image_compressed(uint n_args, const mp_obj_t *args, mp_map_t
return py_image_from_struct(&out);
}
arg_img = py_helper_arg_to_image_mutable_bayer(args[0]);
arg_img = py_helper_arg_to_image_not_compressed(args[0]);
int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50);
PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!");
@ -1206,7 +1273,7 @@ static mp_obj_t py_image_compressed_for_ide(uint n_args, const mp_obj_t *args, m
{
if (IM_IS_JPEG((image_t *) py_image_cobj(args[0]))) return py_image_jpeg_encoded_for_ide(args[0]);
image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]);
image_t *arg_img = py_helper_arg_to_image_not_compressed(args[0]);
int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50);
PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!");
@ -1258,7 +1325,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_flush_obj, py_image_flush);
STATIC mp_obj_t py_image_clear(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]);
image_t *arg_img = py_helper_arg_to_image_not_compressed(args[0]);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 1, kw_args);
@ -1515,7 +1582,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_edges_obj, 2, py_image_draw_edge
STATIC mp_obj_t py_image_draw_image(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_mutable(args[0]);
image_t *arg_other = py_helper_arg_to_image_mutable_bayer(args[1]);
image_t *arg_other = py_helper_arg_to_image_not_compressed(args[1]);
const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 2, 2, &arg_vec);
@ -5226,7 +5293,7 @@ static const mp_obj_type_t py_apriltag_type = {
static mp_obj_t py_image_find_apriltags(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_mutable_bayer_jpeg(args[0]);
image_t *arg_img = py_image_cobj(args[0]);
rectangle_t roi;
py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi);
@ -6905,8 +6972,8 @@ static const mp_rom_map_elem_t globals_dict_table[] = {
{MP_ROM_QSTR(MP_QSTR_BINARY), MP_ROM_INT(PIXFORMAT_BINARY)}, /* 1BPP/BINARY*/
{MP_ROM_QSTR(MP_QSTR_GRAYSCALE), MP_ROM_INT(PIXFORMAT_GRAYSCALE)},/* 1BPP/GRAYSCALE*/
{MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_INT(PIXFORMAT_RGB565)}, /* 2BPP/RGB565*/
{MP_ROM_QSTR(MP_QSTR_YUV422), MP_ROM_INT(PIXFORMAT_YUV422)}, /* 2BPP/YUV422*/
{MP_ROM_QSTR(MP_QSTR_BAYER), MP_ROM_INT(PIXFORMAT_BAYER)}, /* 1BPP/RAW*/
{MP_ROM_QSTR(MP_QSTR_YUV422), MP_ROM_INT(PIXFORMAT_YUV422)}, /* 2BPP/YUV422*/
{MP_ROM_QSTR(MP_QSTR_JPEG), MP_ROM_INT(PIXFORMAT_JPEG)}, /* JPEG/COMPRESSED*/
{MP_ROM_QSTR(MP_QSTR_AREA), MP_ROM_INT(IMAGE_HINT_AREA)},
{MP_ROM_QSTR(MP_QSTR_BILINEAR), MP_ROM_INT(IMAGE_HINT_BILINEAR)},

View File

@ -991,8 +991,8 @@ STATIC const mp_map_elem_t globals_dict_table[] = {
{ 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*/
{ MP_OBJ_NEW_QSTR(MP_QSTR_YUV422), MP_OBJ_NEW_SMALL_INT(PIXFORMAT_YUV422)}, /* 2BPP/YUV422*/
{ MP_OBJ_NEW_QSTR(MP_QSTR_BAYER), MP_OBJ_NEW_SMALL_INT(PIXFORMAT_BAYER)}, /* 1BPP/RAW*/
{ MP_OBJ_NEW_QSTR(MP_QSTR_YUV422), MP_OBJ_NEW_SMALL_INT(PIXFORMAT_YUV422)}, /* 2BPP/YUV422*/
{ MP_OBJ_NEW_QSTR(MP_QSTR_JPEG), MP_OBJ_NEW_SMALL_INT(PIXFORMAT_JPEG)}, /* JPEG/COMPRESSED*/
{ MP_OBJ_NEW_QSTR(MP_QSTR_OV2640), MP_OBJ_NEW_SMALL_INT(OV2640_ID)},
{ MP_OBJ_NEW_QSTR(MP_QSTR_OV5640), MP_OBJ_NEW_SMALL_INT(OV5640_ID)},

View File

@ -172,6 +172,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/imlib/, \
stats.o \
template.o \
xyz_tab.o \
yuv.o \
zbar.o \
)

View File

@ -168,6 +168,7 @@ target_sources(${MICROPY_TARGET} PRIVATE
${TOP_DIR}/${OMV_DIR}/imlib/stats.c
${TOP_DIR}/${OMV_DIR}/imlib/template.c
${TOP_DIR}/${OMV_DIR}/imlib/xyz_tab.c
${TOP_DIR}/${OMV_DIR}/imlib/yuv.c
${TOP_DIR}/${OMV_DIR}/imlib/zbar.c
${TOP_DIR}/${OMV_DIR}/ports/${PORT}/main.c

View File

@ -18,6 +18,7 @@
#include "py_lcd_cec.h"
#include "py_lcd_touch.h"
#include "py_helper.h"
#include "py_image.h"
#include "extmod/machine_i2c.h"
#include "omv_boardconfig.h"
#include STM32_HAL_H
@ -1606,7 +1607,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_lcd_get_point_y_position_obj, py_lcd_get_poi
STATIC mp_obj_t py_lcd_display(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_mutable_bayer_jpeg(args[0]);
image_t *arg_img = py_image_cobj(args[0]);
int arg_x_off = 0;
int arg_y_off = 0;

View File

@ -15,6 +15,7 @@
#include "spi.h"
#include "py_helper.h"
#include "py_image.h"
#include "omv_boardconfig.h"
#include STM32_HAL_H
@ -679,7 +680,7 @@ static void spi_tv_display(image_t *src_img, int dst_x_start, int dst_y_start, f
const uint16_t *color_palette, const uint8_t *alpha_palette,
image_hint_t hint)
{
bool rgb565 = ((rgb_channel == -1) && IMAGE_IS_COLOR(src_img)) || color_palette;
bool rgb565 = ((rgb_channel == -1) && src_img->is_color) || color_palette;
imlib_draw_row_callback_t cb = rgb565 ? spi_tv_draw_image_cb_rgb565 : spi_tv_draw_image_cb_grayscale;
image_t dst_img;
@ -957,7 +958,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_tv_channel_obj, 0, 1, py_tv_channe
STATIC mp_obj_t py_tv_display(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_mutable_bayer_jpeg(args[0]);
image_t *arg_img = py_image_cobj(args[0]);
int arg_x_off = 0;
int arg_y_off = 0;

View File

@ -206,6 +206,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/imlib/, \
stats.o \
template.o \
xyz_tab.o \
yuv.o \
zbar.o \
)

View File

@ -627,7 +627,8 @@ void DCMI_DMAConvCpltUser(uint32_t addr)
#if (OMV_ENABLE_SENSOR_MDMA == 1)
mdma_memcpy(buffer, dst16, src16, sizeof(uint16_t), sensor.transpose);
#else
if (sensor.hw_flags.rgb_swap) {
if ((sensor.pixformat == PIXFORMAT_RGB565 && sensor.hw_flags.rgb_swap)
|| (sensor.pixformat == PIXFORMAT_YUV422 && sensor.hw_flags.yuv_swap)) {
if (!sensor.transpose) {
unaligned_memcpy_rev16(dst16, src16, MAIN_FB()->u);
} else {
@ -668,7 +669,8 @@ static void mdma_config(MDMA_InitTypeDef *init, sensor_t *sensor, uint32_t bytes
init->SourceBlockAddressOffset = 0;
init->DestBlockAddressOffset = 0;
if ((sensor->pixformat == PIXFORMAT_RGB565) && sensor->hw_flags.rgb_swap) {
if ((sensor->pixformat == PIXFORMAT_RGB565 && sensor->hw_flags.rgb_swap)
|| (sensor->pixformat == PIXFORMAT_YUV422 && sensor->hw_flags.yuv_swap)) {
init->Endianness = MDMA_LITTLE_BYTE_ENDIANNESS_EXCHANGE;
} else {
init->Endianness = MDMA_LITTLE_ENDIANNESS_PRESERVE;
@ -963,7 +965,6 @@ int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags)
#endif
break;
case PIXFORMAT_RGB565:
case PIXFORMAT_YUV422:
MAIN_FB()->pixfmt = PIXFORMAT_RGB565;
#if (OMV_ENABLE_SENSOR_MDMA == 1)
// Flush data for MDMA
@ -978,6 +979,17 @@ int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags)
SCB_InvalidateDCache_by_Addr(buffer->data, w * h);
#endif
break;
case PIXFORMAT_YUV422: {
bool yuv_order = sensor->hw_flags.yuv_order == SENSOR_HW_FLAGS_YUV422;
int even = yuv_order ? PIXFORMAT_YUV422 : PIXFORMAT_YVU422;
int odd = yuv_order ? PIXFORMAT_YVU422 : PIXFORMAT_YUV422;
MAIN_FB()->pixfmt = (MAIN_FB()->x % 2) ? odd : even;
#if (OMV_ENABLE_SENSOR_MDMA == 1)
// Flush data for MDMA
SCB_InvalidateDCache_by_Addr(buffer->data, w * h * sizeof(uint16_t));
#endif
break;
}
case PIXFORMAT_JPEG: {
int32_t size = 0;
if (sensor->chip_id == OV5640_ID) {
@ -998,7 +1010,6 @@ int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags)
SCB_InvalidateDCache_by_Addr(buffer->data, size);
#endif
}
// Clean trailing data after 0xFFD9 at the end of the jpeg byte stream.
MAIN_FB()->pixfmt = PIXFORMAT_JPEG;
MAIN_FB()->size = jpeg_clean_trailing_bytes(size, buffer->data);

View File

@ -748,7 +748,7 @@ static int set_pixformat(sensor_t *sensor, pixformat_t pixformat)
break;
case PIXFORMAT_BAYER:
// Make sure odd/even row are switched to work with our bayer conversion.
ret |= cambus_writeb(&sensor->bus, sensor->slv_addr,
ret |= cambus_writeb(&sensor->bus, sensor->slv_addr,
REG_SYNC_MODE, REG_SYNC_MODE_DEF | REG_SYNC_MODE_ROW_SWITCH);
ret |= cambus_writeb(&sensor->bus, sensor->slv_addr,
REG_OUTPUT_FMT, REG_OUTPUT_SET_FMT(reg, REG_OUTPUT_FMT_BAYER));
@ -881,6 +881,7 @@ int gc2145_init(sensor_t *sensor)
sensor->hw_flags.jpege = 0;
sensor->hw_flags.gs_bpp = 2;
sensor->hw_flags.rgb_swap = 1;
sensor->hw_flags.yuv_order = SENSOR_HW_FLAGS_YVU422;
return 0;
}

View File

@ -1013,6 +1013,7 @@ int mt9m114_init(sensor_t *sensor)
sensor->hw_flags.gs_bpp = 2;
sensor->hw_flags.rgb_swap = 0;
sensor->hw_flags.bayer = SENSOR_HW_FLAGS_BAYER_GBRG;
sensor->hw_flags.yuv_order = SENSOR_HW_FLAGS_YVU422;
return 0;
}

View File

@ -857,6 +857,7 @@ int ov2640_init(sensor_t *sensor)
sensor->hw_flags.jpeg_mode = 3;
sensor->hw_flags.gs_bpp = 2;
sensor->hw_flags.rgb_swap = 0;
sensor->hw_flags.yuv_order = SENSOR_HW_FLAGS_YVU422;
return 0;
}

View File

@ -1383,6 +1383,7 @@ int ov5640_init(sensor_t *sensor)
sensor->hw_flags.jpeg_mode = 4;
sensor->hw_flags.gs_bpp = 1;
sensor->hw_flags.rgb_swap = 0;
sensor->hw_flags.yuv_order = SENSOR_HW_FLAGS_YVU422;
return 0;
}

View File

@ -454,6 +454,7 @@ int ov7670_init(sensor_t *sensor)
sensor->hw_flags.jpege = 0;
sensor->hw_flags.gs_bpp = 2;
sensor->hw_flags.rgb_swap = 1;
sensor->hw_flags.yuv_order = SENSOR_HW_FLAGS_YVU422;
return 0;
}

View File

@ -624,6 +624,7 @@ int ov7725_init(sensor_t *sensor)
sensor->hw_flags.jpege = 0;
sensor->hw_flags.gs_bpp = 2;
sensor->hw_flags.rgb_swap = 1;
sensor->hw_flags.yuv_order = SENSOR_HW_FLAGS_YVU422;
return 0;
}

View File

@ -540,6 +540,7 @@ int ov9650_init(sensor_t *sensor)
sensor->hw_flags.jpege = 0;
sensor->hw_flags.gs_bpp = 2;
sensor->hw_flags.rgb_swap = 1;
sensor->hw_flags.yuv_order = SENSOR_HW_FLAGS_YVU422;
return 0;
}