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 \ stats.c \
template.c \ template.c \
xyz_tab.c \ xyz_tab.c \
yuv.c \
zbar.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_GBRG (SUBFORMAT_ID_GBRG)
#define SENSOR_HW_FLAGS_BAYER_GRBG (SUBFORMAT_ID_GRBG) #define SENSOR_HW_FLAGS_BAYER_GRBG (SUBFORMAT_ID_GRBG)
#define SENSOR_HW_FLAGS_BAYER_RGGB (SUBFORMAT_ID_RGGB) #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 (*vsync_cb_t)(uint32_t vsync);
typedef void (*frame_cb_t)(); 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 rgb_swap:1; // Byte-swap 2BPP RGB formats after capture.
uint32_t yuv_swap:1; // Byte-swap 2BPP YUV formats after capture. uint32_t yuv_swap:1; // Byte-swap 2BPP YUV formats after capture.
uint32_t bayer:3; // Bayer/CFA pattern. uint32_t bayer:3; // Bayer/CFA pattern.
uint32_t yuv_order:1; // YUV/YVU order.
} hw_flags; } hw_flags;
const uint16_t *color_palette; // Color palette used for color lookup. 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. // 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. // 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(); uint32_t size = framebuffer_get_buffer_size();
if ((sensor.pixformat == PIXFORMAT_BAYER) 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 * 2 > size)
&& (MAIN_FB()->u * MAIN_FB()->v * 1 <= size)) { && (MAIN_FB()->u * MAIN_FB()->v * 1 <= size)) {
return 0; return 0;
@ -1124,7 +1124,7 @@ __weak int sensor_auto_crop_framebuffer()
return 0; return 0;
} }
if (sensor.pixformat == PIXFORMAT_RGB565) { if ((sensor.pixformat == PIXFORMAT_RGB565) || (sensor.pixformat == PIXFORMAT_YUV422)) {
// Switch to bayer for the quick 2x savings. // Switch to bayer for the quick 2x savings.
sensor_set_pixformat(PIXFORMAT_BAYER); sensor_set_pixformat(PIXFORMAT_BAYER);
bpp = 1; 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: { case PIXFORMAT_BAYER_ANY: {
uint8_t *dst8 = (data->dst_row_override uint8_t *dst8 = (data->dst_row_override
? ((uint8_t *) 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; uint8_t *src8 = ((uint8_t *) data->row_buffer[!data->toggle]) + x_start;
unaligned_memcpy(dst8, src8, (x_end - x_start) * sizeof(uint8_t)); unaligned_memcpy(dst8, src8, (x_end - x_start) * sizeof(uint8_t));
break; 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: { default: {
break; 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 // rgb_channel extracted / color_palette applied image
image_t new_src_img; 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)) { || ((hint & IMAGE_HINT_APPLY_COLOR_PALETTE_FIRST) && color_palette)) {
new_src_img.w = src_img_w; // same width as source image new_src_img.w = src_img_w; // same width as source image
new_src_img.h = src_img_h; // same height as source image new_src_img.h = src_img_h; // same height as source image
@ -2687,9 +2696,8 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
// Special destination? // Special destination?
bool is_jpeg = (src_img->pixfmt == PIXFORMAT_JPEG); bool is_jpeg = (src_img->pixfmt == PIXFORMAT_JPEG);
bool is_bayer_or_jpeg = src_img->is_bayer || is_jpeg; // Best format to convert yuv/bayer/jpeg image to.
// Best format to convert bayer/jpeg image to. int new_not_mutable_pixfmt = (rgb_channel != -1) ? PIXFORMAT_RGB565 :
int is_bayer_or_jpeg_pixfmt = (rgb_channel != -1) ? PIXFORMAT_RGB565 :
(color_palette ? PIXFORMAT_GRAYSCALE : (color_palette ? PIXFORMAT_GRAYSCALE :
dst_img->pixfmt); dst_img->pixfmt);
@ -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? // Do we need to convert the image?
bool is_bayer_color_conversion = src_img->is_bayer && !dst_img->is_bayer; 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. // Force a deep copy if we cannot use the image in-place.
bool need_deep_copy = (dst_img->data == src_img->data) 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. // 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. // 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.w = src_img->w; // same width as source image
new_src_img.h = src_img->h; // same height as source image new_src_img.h = src_img->h; // same height as source image
if (is_bayer_or_jpeg) { if (!src_img->is_mutable) {
new_src_img.pixfmt = is_bayer_or_jpeg_pixfmt; new_src_img.pixfmt = new_not_mutable_pixfmt;
size_t size = image_size(&new_src_img); size_t size = image_size(&new_src_img);
new_src_img.data = fb_alloc(size, FB_ALLOC_NO_HINT); 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: { case PIXFORMAT_BINARY: {
if (src_img->is_bayer) { if (src_img->is_bayer) {
imlib_debayer_image(&new_src_img, src_img); 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); jpeg_decompress_image_to_binary(&new_src_img, src_img);
} }
break; 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: { case PIXFORMAT_GRAYSCALE: {
if (src_img->is_bayer) { if (src_img->is_bayer) {
imlib_debayer_image(&new_src_img, src_img); 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); jpeg_decompress_image_to_grayscale(&new_src_img, src_img);
} }
break; 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: { case PIXFORMAT_RGB565: {
if (src_img->is_bayer) { if (src_img->is_bayer) {
imlib_debayer_image(&new_src_img, src_img); 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); jpeg_decompress_image_to_rgb565(&new_src_img, src_img);
} }
break; break;
} }
case PIXFORMAT_BAYER_ANY: { case PIXFORMAT_BAYER_ANY:
case PIXFORMAT_YUV_ANY: {
memcpy(new_src_img.data, src_img->data, size); memcpy(new_src_img.data, src_img->data, size);
break; 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_t imlib_draw_row_data;
imlib_draw_row_data.dst_img = dst_img; 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.rgb_channel = rgb_channel;
imlib_draw_row_data.alpha = alpha; imlib_draw_row_data.alpha = alpha;
imlib_draw_row_data.color_palette = color_palette; 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 } // while y
break; break;
} }
case PIXFORMAT_RGB565: { case PIXFORMAT_RGB565:
// Re-use RGB565 for yuv.
case PIXFORMAT_YUV_ANY: {
while (y_not_done) { while (y_not_done) {
uint16_t *src_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(src_img, next_src_y_index); 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 // 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: { case PIXFORMAT_BAYER_ANY: {
while (y_not_done) { while (y_not_done) {
switch (is_bayer_or_jpeg_pixfmt) { switch (new_not_mutable_pixfmt) {
case PIXFORMAT_BINARY: case PIXFORMAT_MUTABLE_ANY: {
case PIXFORMAT_GRAYSCALE:
case PIXFORMAT_RGB565: {
imlib_debayer_line(dst_x_start, dst_x_end, next_src_y_index, 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; break;
} }
case PIXFORMAT_BAYER_ANY: { // Bayer images have the same shape as grayscale. 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); 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); imlib_draw_row_put_row_buffer(&imlib_draw_row_data, src_row_ptr);
break; 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 } // while y
break; break;
} }
case PIXFORMAT_RGB565: { case PIXFORMAT_RGB565:
// Re-use RGB565 for yuv.
case PIXFORMAT_YUV_ANY: {
while (y_not_done) { while (y_not_done) {
int src_y_index = next_src_y_index; int src_y_index = next_src_y_index;
uint16_t *src_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(src_img, 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); 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++) { for (int y=0; y<blocks; y++) {
int block_size = IM_MIN(BLOCK_SIZE, bytes - (y*BLOCK_SIZE)); int block_size = IM_MIN(BLOCK_SIZE, bytes - (y*BLOCK_SIZE));
write_byte(fp, 1 + block_size); write_byte(fp, 1 + block_size);
write_byte(fp, 0x80); // clear code write_byte(fp, 0x80); // clear code
uint16_t pixels[block_size]; uint16_t pixels[block_size];
if (img->is_bayer) {
imlib_debayer_line(0, block_size, y, pixels, PIXFORMAT_RGB565, img); 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++) { for (int x=0; x<block_size; x++) {
int r = COLOR_RGB565_TO_R8(pixels[x]); int r = COLOR_RGB565_TO_R8(pixels[x]);
int g = COLOR_RGB565_TO_G8(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 write_data(fp, (uint8_t []) {0x01, 0x81, 0x00}, 3); // end code
file_buffer_off(fp); file_buffer_off(fp);

View File

@ -260,15 +260,14 @@ size_t image_size(image_t *ptr)
case PIXFORMAT_BINARY: { case PIXFORMAT_BINARY: {
return IMAGE_BINARY_LINE_LEN_BYTES(ptr) * ptr->h; 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; 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; return IMAGE_RGB565_LINE_LEN_BYTES(ptr) * ptr->h;
} }
case PIXFORMAT_BAYER_ANY: {
return ptr->w * ptr->h;
}
case PIXFORMAT_JPEG: { case PIXFORMAT_JPEG: {
return ptr->size; return ptr->size;
} }

View File

@ -341,20 +341,22 @@ typedef enum {
PIXFORMAT_ID_BINARY = 1, PIXFORMAT_ID_BINARY = 1,
PIXFORMAT_ID_GRAY = 2, PIXFORMAT_ID_GRAY = 2,
PIXFORMAT_ID_RGB565 = 3, PIXFORMAT_ID_RGB565 = 3,
PIXFORMAT_ID_YUV422 = 4, PIXFORMAT_ID_BAYER = 4,
PIXFORMAT_ID_BAYER = 5, PIXFORMAT_ID_YUV422 = 5,
PIXFORMAT_ID_JPEG = 6, PIXFORMAT_ID_JPEG = 6,
/* Note: Update PIXFORMAT_IS_VALID when adding new formats */ /* Note: Update PIXFORMAT_IS_VALID when adding new formats */
} pixformat_id_t; } pixformat_id_t;
// Pixel sub-format IDs. // Pixel sub-format IDs.
typedef enum { typedef enum {
SUBFORMAT_ID_GRAY8 = 0,
SUBFORMAT_ID_GRAY16 = 1,
SUBFORMAT_ID_BGGR = 0, // !!! Note: Make sure bayer sub-formats don't !!! 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_GBRG = 1, // !!! overflow the sensor.hw_flags.bayer field !!!
SUBFORMAT_ID_GRBG = 2, SUBFORMAT_ID_GRBG = 2,
SUBFORMAT_ID_RGGB = 3, SUBFORMAT_ID_RGGB = 3,
SUBFORMAT_ID_GRAY8 = 0, SUBFORMAT_ID_YUV422 = 0,
SUBFORMAT_ID_GRAY16 = 1, SUBFORMAT_ID_YVU422 = 1,
/* Note: Update PIXFORMAT_IS_VALID when adding new formats */ /* Note: Update PIXFORMAT_IS_VALID when adding new formats */
} subformat_id_t; } subformat_id_t;
@ -364,45 +366,58 @@ typedef enum {
PIXFORMAT_BPP_GRAY8 = 1, PIXFORMAT_BPP_GRAY8 = 1,
PIXFORMAT_BPP_GRAY16 = 2, PIXFORMAT_BPP_GRAY16 = 2,
PIXFORMAT_BPP_RGB565 = 2, PIXFORMAT_BPP_RGB565 = 2,
PIXFORMAT_BPP_YUV422 = 2,
PIXFORMAT_BPP_BAYER = 1, PIXFORMAT_BPP_BAYER = 1,
PIXFORMAT_BPP_YUV422 = 2,
/* Note: Update PIXFORMAT_IS_VALID when adding new formats */ /* Note: Update PIXFORMAT_IS_VALID when adding new formats */
} pixformat_bpp_t; } pixformat_bpp_t;
// Pixel format flags. // Pixel format flags.
#define PIXFORMAT_FLAGS_Y (1 << 28) // YUV format.
#define PIXFORMAT_FLAGS_M (1 << 27) // Mutable format. #define PIXFORMAT_FLAGS_M (1 << 27) // Mutable format.
#define PIXFORMAT_FLAGS_C (1 << 26) // Colored format. #define PIXFORMAT_FLAGS_C (1 << 26) // Colored format.
#define PIXFORMAT_FLAGS_J (1 << 25) // Compressed format (JPEG/PNG). #define PIXFORMAT_FLAGS_J (1 << 25) // Compressed format (JPEG/PNG).
#define PIXFORMAT_FLAGS_R (1 << 24) // RAW/Bayer format. #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_CM (PIXFORMAT_FLAGS_C | PIXFORMAT_FLAGS_M)
#define PIXFORMAT_FLAGS_CR (PIXFORMAT_FLAGS_C | PIXFORMAT_FLAGS_R) #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) #define IMLIB_IMAGE_MAX_SIZE(x) ((x) & 0xFFFFFFFF)
// Each pixel format encodes flags, pixel format id and bpp as follows: // Each pixel format encodes flags, pixel format id and bpp as follows:
// 31......28 27 26 25 24 23..........16 15...........8 7.............0 // 31......29 28 27 26 25 24 23..........16 15...........8 7.............0
// <RESERVED> MF CF JF RF <PIXFORMAT_ID> <SUBFORMAT_ID> <BYTES_PER_PIX> // <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. // NOTE: Bit 31-30 must Not be used for pixformat_t to be used as mp_int_t.
typedef enum { typedef enum {
PIXFORMAT_INVALID = (0), PIXFORMAT_INVALID = (0),
PIXFORMAT_BINARY = (PIXFORMAT_FLAGS_M | (PIXFORMAT_ID_BINARY << 16) | (0 << 8) | PIXFORMAT_BPP_BINARY ), 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_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_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 = (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_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_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_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_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_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_LAST = 0xFFFFFFFFU,
} pixformat_t; } pixformat_t;
#define PIXFORMAT_MUTABLE_ANY \
PIXFORMAT_BINARY: \
case PIXFORMAT_GRAYSCALE: \
case PIXFORMAT_RGB565 \
#define PIXFORMAT_BAYER_ANY \ #define PIXFORMAT_BAYER_ANY \
PIXFORMAT_BAYER_BGGR: \ PIXFORMAT_BAYER_BGGR: \
case PIXFORMAT_BAYER_GBRG: \ case PIXFORMAT_BAYER_GBRG: \
case PIXFORMAT_BAYER_GRBG: \ case PIXFORMAT_BAYER_GRBG: \
case PIXFORMAT_BAYER_RGGB \ case PIXFORMAT_BAYER_RGGB \
#define PIXFORMAT_YUV_ANY \
PIXFORMAT_YUV422: \
case PIXFORMAT_YVU422 \
#define IMLIB_PIXFORMAT_IS_VALID(x) \ #define IMLIB_PIXFORMAT_IS_VALID(x) \
((x == PIXFORMAT_BINARY) \ ((x == PIXFORMAT_BINARY) \
|| (x == PIXFORMAT_GRAYSCALE) \ || (x == PIXFORMAT_GRAYSCALE) \
@ -411,6 +426,8 @@ typedef enum {
|| (x == PIXFORMAT_BAYER_GBRG) \ || (x == PIXFORMAT_BAYER_GBRG) \
|| (x == PIXFORMAT_BAYER_GRBG) \ || (x == PIXFORMAT_BAYER_GRBG) \
|| (x == PIXFORMAT_BAYER_RGGB) \ || (x == PIXFORMAT_BAYER_RGGB) \
|| (x == PIXFORMAT_YUV422) \
|| (x == PIXFORMAT_YVU422) \
|| (x == PIXFORMAT_JPEG)) \ || (x == PIXFORMAT_JPEG)) \
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) #if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
@ -425,7 +442,8 @@ struct { \
uint32_t is_compressed :1; \ uint32_t is_compressed :1; \
uint32_t is_color :1; \ uint32_t is_color :1; \
uint32_t is_mutable :1; \ uint32_t is_mutable :1; \
uint32_t /*reserved*/ :4; \ uint32_t is_yuv :1; \
uint32_t /*reserved*/ :3; \
}; \ }; \
uint32_t pixfmt; \ uint32_t pixfmt; \
}; \ }; \
@ -436,7 +454,8 @@ struct { \
struct { \ struct { \
union { \ union { \
struct { \ struct { \
uint32_t /*reserved*/ :4; \ uint32_t /*reserved*/ :3; \
uint32_t is_yuv :1; \
uint32_t is_mutable :1; \ uint32_t is_mutable :1; \
uint32_t is_color :1; \ uint32_t is_color :1; \
uint32_t is_compressed :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); size_t image_size(image_t *ptr);
bool image_get_mask_pixel(image_t *ptr, int x, int y); 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(image) (((image)->w + UINT32_T_MASK) >> UINT32_T_SHIFT)
#define IMAGE_BINARY_LINE_LEN_BYTES(image) (IMAGE_BINARY_LINE_LEN(image) * sizeof(uint32_t)) #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; \ ((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 // // Fast Stuff //
#define IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(image, y) \ #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; \ _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. // Old Image Macros - Will be refactor and removed. But, only after making sure through testing new macros work.
// Image kernels // 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_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); 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 */ /* Color space functions */
int8_t imlib_rgb565_to_l(uint16_t pixel); int8_t imlib_rgb565_to_l(uint16_t pixel);
int8_t imlib_rgb565_to_a(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: { case PIXFORMAT_RGB565: {
if ((dx != MCU_W) || (dy != MCU_H)) { // partial MCU, fill with 0's to start 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++) { 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; 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: { case PIXFORMAT_BAYER_ANY: {
if ((dx != MCU_W) || (dy != MCU_H)) { // partial MCU, fill with 0's to start 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; 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; break;
case PIXFORMAT_RGB565: case PIXFORMAT_RGB565:
case PIXFORMAT_BAYER_ANY: case PIXFORMAT_BAYER_ANY:
case PIXFORMAT_YUV_ANY:
mcu_size = JPEG_444_YCBCR_MCU_SIZE; mcu_size = JPEG_444_YCBCR_MCU_SIZE;
JPEG_Info.ColorSpace = JPEG_YCBCR_COLORSPACE; JPEG_Info.ColorSpace = JPEG_YCBCR_COLORSPACE;
JPEG_Info.ChromaSubsampling = JPEG_444_SUBSAMPLING; 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)) { if (mp_obj_is_integer(copy_to_fb_obj)) {
copy_to_fb = mp_obj_get_int(copy_to_fb_obj); copy_to_fb = mp_obj_get_int(copy_to_fb_obj);
} else { } 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 *py_helper_arg_to_image_mutable(const mp_obj_t arg)
{ {
image_t *arg_img = py_image_cobj(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; 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); image_t *arg_img = py_image_cobj(arg);
PY_ASSERT_TRUE_MSG(IMAGE_IS_MUTABLE_BAYER(arg_img), "Image is not mutable!"); PY_ASSERT_FALSE_MSG(arg_img->is_compressed, "Image is compressed!");
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!");
return arg_img; return arg_img;
} }
@ -52,13 +45,6 @@ image_t *py_helper_arg_to_image_grayscale(const mp_obj_t arg)
return arg_img; 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, 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) mp_map_t *kw_args, mp_obj_t kw, image_t *default_val)
{ {

View File

@ -13,10 +13,8 @@
#include "imlib.h" #include "imlib.h"
extern const mp_obj_fun_builtin_var_t py_func_unavailable_obj; 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(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_not_compressed(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_grayscale(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, 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); 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, 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; return row;
} }
} }
case PIXFORMAT_BAYER_ANY: case PIXFORMAT_GRAYSCALE:
case PIXFORMAT_GRAYSCALE: { case PIXFORMAT_BAYER_ANY: {
if (self->cur >= img->h) { if (self->cur >= img->h) {
return MP_OBJ_STOP_ITERATION; return MP_OBJ_STOP_ITERATION;
} else { } else {
@ -325,7 +325,8 @@ STATIC mp_obj_t py_image_it_iternext(mp_obj_t self_in)
return row; return row;
} }
} }
case PIXFORMAT_RGB565: { case PIXFORMAT_RGB565:
case PIXFORMAT_YUV_ANY: {
if (self->cur >= img->h) { if (self->cur >= img->h) {
return MP_OBJ_STOP_ITERATION; return MP_OBJ_STOP_ITERATION;
} else { } 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_BINARY) ? "binary" :
(image->pixfmt == PIXFORMAT_GRAYSCALE) ? "grayscale" : (image->pixfmt == PIXFORMAT_GRAYSCALE) ? "grayscale" :
(image->pixfmt == PIXFORMAT_RGB565) ? "rgb565" : (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_YUV422) ? "yuv422" :
(image->pixfmt == PIXFORMAT_JPEG) ? "jpeg" : "bayer", (image->pixfmt == PIXFORMAT_YVU422) ? "yvu422" :
(image->pixfmt == PIXFORMAT_JPEG) ? "jpeg" : "unknown",
image_size(image)); 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); 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)); 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)) { if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice; mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(image->w * image->h, index, &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); uint8_t p = IMAGE_GET_GRAYSCALE_PIXEL(image, i % image->w, i / image->w);
return mp_obj_new_int(p); 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)) { if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice; mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(image->w * image->h, index, &slice)) { if (!mp_seq_get_fast_slice_indexes(image->w * image->h, index, &slice)) {
@ -428,18 +435,28 @@ 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); mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL);
for (mp_uint_t i = 0; i < result->len; i++) { 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); uint16_t p = IMAGE_GET_RGB565_PIXEL(image, (slice.start + i) % image->w, (slice.start + i) / image->w);
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)), 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_G8(p)),
mp_obj_new_int(COLOR_RGB565_TO_B8(p))}); mp_obj_new_int(COLOR_RGB565_TO_B8(p))});
} }
}
return result; return result;
} }
mp_uint_t i = mp_get_index(self->base.type, image->w * image->h, index, false); 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); uint16_t p = IMAGE_GET_RGB565_PIXEL(image, i % image->w, i / image->w);
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)), 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_G8(p)),
mp_obj_new_int(COLOR_RGB565_TO_B8(p))}); mp_obj_new_int(COLOR_RGB565_TO_B8(p))});
} }
}
case PIXFORMAT_JPEG: { case PIXFORMAT_JPEG: {
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice; mp_bound_slice_t 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)); IMAGE_PUT_BINARY_PIXEL(image, i % image->w, i / image->w, mp_obj_get_int(value));
return mp_const_none; 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)) { if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice; mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(image->w * image->h, index, &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); IMAGE_PUT_GRAYSCALE_PIXEL(image, i % image->w, i / image->w, p);
return mp_const_none; return mp_const_none;
} }
case PIXFORMAT_RGB565: { case PIXFORMAT_RGB565:
case PIXFORMAT_YUV_ANY: {
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice; mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(image->w * image->h, index, &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"); 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++) { for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) {
mp_obj_t *value_2; mp_obj_t *value_2;
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); 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])); p = COLOR_R8_G8_B8_TO_RGB565(mp_obj_get_int(value_2[0]),
IMAGE_PUT_RGB565_PIXEL(image, (slice.start + i) % image->w, (slice.start + i) / image->w, p); 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 { } else {
mp_obj_t *value_2; mp_obj_t *value_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); 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])); 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++) { 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; 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); return mp_obj_new_int(PIXFORMAT_RGB565);
case PIXFORMAT_BAYER_ANY: case PIXFORMAT_BAYER_ANY:
return mp_obj_new_int(PIXFORMAT_BAYER); return mp_obj_new_int(PIXFORMAT_BAYER);
case PIXFORMAT_YUV_ANY:
return mp_obj_new_int(PIXFORMAT_YUV422);
default: default:
return mp_obj_new_int(PIXFORMAT_JPEG); 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) 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; const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 1, 2, &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)); pixel_tuple[2] = mp_obj_new_int(COLOR_RGB565_TO_B8(pixel));
return mp_obj_new_tuple(3, pixel_tuple); return mp_obj_new_tuple(3, pixel_tuple);
} else { } 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; 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) 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; const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 1, 2, &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); IMAGE_PUT_BINARY_PIXEL(arg_img, arg_x, arg_y, arg_c);
return args[0]; 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); IMAGE_PUT_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y, arg_c);
return args[0]; 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); IMAGE_PUT_RGB565_PIXEL(arg_img, arg_x, arg_y, arg_c);
return args[0]; 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]; 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, 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) 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; 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); 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)) { if (mp_obj_is_integer(copy_obj)) {
copy = mp_obj_get_int(copy_obj); copy = mp_obj_get_int(copy_obj);
} else { } 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_EXTRACT_RGB_CHANNEL_FIRST |
IMAGE_HINT_APPLY_COLOR_PALETTE_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) { } else if (dst_img.pixfmt == PIXFORMAT_JPEG) {
if ((arg_x_scale != 1) || if ((arg_x_scale != 1) ||
(arg_y_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]; 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); 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!"); 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]); 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); 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!"); 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); 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); 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!"); 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]); 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); 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!"); 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) 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 = image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 1, kw_args); 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) 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_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; const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 2, 2, &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) 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; rectangle_t roi;
py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &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_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_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_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_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_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_AREA), MP_ROM_INT(IMAGE_HINT_AREA)},
{MP_ROM_QSTR(MP_QSTR_BILINEAR), MP_ROM_INT(IMAGE_HINT_BILINEAR)}, {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_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_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_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_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_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_OV2640), MP_OBJ_NEW_SMALL_INT(OV2640_ID)},
{ MP_OBJ_NEW_QSTR(MP_QSTR_OV5640), MP_OBJ_NEW_SMALL_INT(OV5640_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 \ stats.o \
template.o \ template.o \
xyz_tab.o \ xyz_tab.o \
yuv.o \
zbar.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/stats.c
${TOP_DIR}/${OMV_DIR}/imlib/template.c ${TOP_DIR}/${OMV_DIR}/imlib/template.c
${TOP_DIR}/${OMV_DIR}/imlib/xyz_tab.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}/imlib/zbar.c
${TOP_DIR}/${OMV_DIR}/ports/${PORT}/main.c ${TOP_DIR}/${OMV_DIR}/ports/${PORT}/main.c

View File

@ -18,6 +18,7 @@
#include "py_lcd_cec.h" #include "py_lcd_cec.h"
#include "py_lcd_touch.h" #include "py_lcd_touch.h"
#include "py_helper.h" #include "py_helper.h"
#include "py_image.h"
#include "extmod/machine_i2c.h" #include "extmod/machine_i2c.h"
#include "omv_boardconfig.h" #include "omv_boardconfig.h"
#include STM32_HAL_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) 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_x_off = 0;
int arg_y_off = 0; int arg_y_off = 0;

View File

@ -15,6 +15,7 @@
#include "spi.h" #include "spi.h"
#include "py_helper.h" #include "py_helper.h"
#include "py_image.h"
#include "omv_boardconfig.h" #include "omv_boardconfig.h"
#include STM32_HAL_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, const uint16_t *color_palette, const uint8_t *alpha_palette,
image_hint_t hint) 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; imlib_draw_row_callback_t cb = rgb565 ? spi_tv_draw_image_cb_rgb565 : spi_tv_draw_image_cb_grayscale;
image_t dst_img; 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) 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_x_off = 0;
int arg_y_off = 0; int arg_y_off = 0;

View File

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

View File

@ -627,7 +627,8 @@ void DCMI_DMAConvCpltUser(uint32_t addr)
#if (OMV_ENABLE_SENSOR_MDMA == 1) #if (OMV_ENABLE_SENSOR_MDMA == 1)
mdma_memcpy(buffer, dst16, src16, sizeof(uint16_t), sensor.transpose); mdma_memcpy(buffer, dst16, src16, sizeof(uint16_t), sensor.transpose);
#else #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) { if (!sensor.transpose) {
unaligned_memcpy_rev16(dst16, src16, MAIN_FB()->u); unaligned_memcpy_rev16(dst16, src16, MAIN_FB()->u);
} else { } else {
@ -668,7 +669,8 @@ static void mdma_config(MDMA_InitTypeDef *init, sensor_t *sensor, uint32_t bytes
init->SourceBlockAddressOffset = 0; init->SourceBlockAddressOffset = 0;
init->DestBlockAddressOffset = 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; init->Endianness = MDMA_LITTLE_BYTE_ENDIANNESS_EXCHANGE;
} else { } else {
init->Endianness = MDMA_LITTLE_ENDIANNESS_PRESERVE; init->Endianness = MDMA_LITTLE_ENDIANNESS_PRESERVE;
@ -963,7 +965,6 @@ int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags)
#endif #endif
break; break;
case PIXFORMAT_RGB565: case PIXFORMAT_RGB565:
case PIXFORMAT_YUV422:
MAIN_FB()->pixfmt = PIXFORMAT_RGB565; MAIN_FB()->pixfmt = PIXFORMAT_RGB565;
#if (OMV_ENABLE_SENSOR_MDMA == 1) #if (OMV_ENABLE_SENSOR_MDMA == 1)
// Flush data for MDMA // 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); SCB_InvalidateDCache_by_Addr(buffer->data, w * h);
#endif #endif
break; 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: { case PIXFORMAT_JPEG: {
int32_t size = 0; int32_t size = 0;
if (sensor->chip_id == OV5640_ID) { 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); SCB_InvalidateDCache_by_Addr(buffer->data, size);
#endif #endif
} }
// Clean trailing data after 0xFFD9 at the end of the jpeg byte stream. // Clean trailing data after 0xFFD9 at the end of the jpeg byte stream.
MAIN_FB()->pixfmt = PIXFORMAT_JPEG; MAIN_FB()->pixfmt = PIXFORMAT_JPEG;
MAIN_FB()->size = jpeg_clean_trailing_bytes(size, buffer->data); MAIN_FB()->size = jpeg_clean_trailing_bytes(size, buffer->data);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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