Add jpeg decoding support (#1371)

* Add jpeg decoding support
This commit is contained in:
Kwabena W. Agyeman 2021-06-28 16:49:53 -07:00 committed by GitHub
parent 6b99527ead
commit 642c503744
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 3316 additions and 31 deletions

View File

@ -1381,6 +1381,42 @@ __STATIC_FORCEINLINE int32_t __SSAT_ASR(int32_t val, uint32_t sat, uint32_t shif
return val;
}
/**
\brief Signed Saturate
\details Saturates two signed values.
\param [in] value Values to be saturated
\param [in] sat Bit position to saturate to (1..16)
\return Saturated value
*/
__STATIC_FORCEINLINE int32_t __SSAT16(int32_t val, uint32_t sat)
{
if ((sat >= 1U) && (sat <= 32U))
{
const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U);
const int32_t min = -1 - max ;
int32_t valHi = val >> 16;
if (valHi > max)
{
valHi = max;
}
else if (valHi < min)
{
valHi = min;
}
int32_t valLo = (val << 16) >> 16;
if (valLo > max)
{
valLo = max;
}
else if (valLo < min)
{
valLo = min;
}
return (valHi << 16) | (valLo & 0xFFFF);
}
return val;
}
/**
\brief Unsigned Saturate
\details Saturates an unsigned value.
@ -1432,6 +1468,41 @@ __STATIC_FORCEINLINE uint32_t __USAT_ASR(int32_t val, uint32_t sat, uint32_t shi
return (uint32_t)val;
}
/**
\brief Unsigned Saturate
\details Saturates two unsigned values.
\param [in] value Values to be saturated
\param [in] sat Bit position to saturate to (0..15)
\return Saturated value
*/
__STATIC_FORCEINLINE uint32_t __USAT16(int32_t val, uint32_t sat)
{
if (sat <= 15U)
{
const uint32_t max = ((1U << sat) - 1U);
int32_t valHi = val >> 16;
if (valHi > (int32_t)max)
{
valHi = max;
}
else if (valHi < 0)
{
valHi = 0U;
}
int32_t valLo = (val << 16) >> 16;
if (valLo > (int32_t)max)
{
valLo = max;
}
else if (valLo < 0)
{
valLo = 0U;
}
return (valHi << 16) | valLo;
}
return (uint32_t)val;
}
#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \
(defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \
(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */

View File

@ -80,6 +80,7 @@ SRCS += $(addprefix imlib/, \
imlib.c \
integral.c \
integral_mw.c \
jpegd.c \
jpeg.c \
kmeans.c \
lab_tab.c \

View File

@ -2664,13 +2664,10 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
src_y_accum_reset -= 0x8000;
}
bool is_bayer = src_img->bpp == IMAGE_BPP_BAYER;
bool is_color = is_bayer || (src_img->bpp == IMAGE_BPP_RGB565);
// rgb_channel extracted / color_palette applied image
image_t new_src_img;
if (((hint & IMAGE_HINT_EXTRACT_RGB_CHANNEL_FIRST) && is_color && (rgb_channel != -1))
if (((hint & IMAGE_HINT_EXTRACT_RGB_CHANNEL_FIRST) && (rgb_channel != -1) && IMAGE_IS_COLOR(src_img))
|| ((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
@ -2682,8 +2679,14 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
color_palette = NULL;
}
// Best bpp to convert bayer image to.
int is_bayer_bpp = (rgb_channel != -1) ? IMAGE_BPP_RGB565 : (color_palette ? IMAGE_BPP_GRAYSCALE : dst_img->bpp);
// Special destination?
bool is_bayer = src_img->bpp == IMAGE_BPP_BAYER;
bool is_jpeg = src_img->bpp >= IMAGE_BPP_JPEG;
bool is_bayer_or_jpeg = is_bayer || is_jpeg;
// Best bpp to convert bayer/jpeg image to.
int is_bayer_or_jpeg_bpp = (rgb_channel != -1) ? IMAGE_BPP_RGB565 :
(color_palette ? IMAGE_BPP_GRAYSCALE :
dst_img->bpp);
bool no_scaling_nearest_neighbor = (dst_delta_x == 1)
&& (dst_x_start == 0) && (src_x_start == 0)
@ -2707,27 +2710,39 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
// Force a deep copy if we are scaling.
bool is_bayer_scaling = is_bayer_color_conversion && is_scaling;
// Make a deep copy of the source iamge.
if (need_deep_copy || is_bayer_scaling) {
// Make a deep copy of the source image.
if (need_deep_copy || is_bayer_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) {
new_src_img.bpp = is_bayer_bpp;
if (is_bayer_or_jpeg) {
new_src_img.bpp = is_bayer_or_jpeg_bpp;
size_t size = image_size(&new_src_img);
new_src_img.data = fb_alloc(image_size(&new_src_img), FB_ALLOC_NO_HINT);
new_src_img.data = fb_alloc(size, FB_ALLOC_NO_HINT);
switch (new_src_img.bpp) {
case IMAGE_BPP_BINARY: {
imlib_debayer_image_to_binary(&new_src_img, src_img);
if (src_img->bpp == IMAGE_BPP_BAYER) {
imlib_debayer_image_to_binary(&new_src_img, src_img);
} else if (src_img->bpp >= IMAGE_BPP_JPEG) {
jpeg_decompress_image_to_binary(&new_src_img, src_img);
}
break;
}
case IMAGE_BPP_GRAYSCALE: {
imlib_debayer_image_to_grayscale(&new_src_img, src_img);
if (src_img->bpp == IMAGE_BPP_BAYER) {
imlib_debayer_image_to_grayscale(&new_src_img, src_img);
} else if (src_img->bpp >= IMAGE_BPP_JPEG) {
jpeg_decompress_image_to_grayscale(&new_src_img, src_img);
}
break;
}
case IMAGE_BPP_RGB565: {
imlib_debayer_image_to_rgb565(&new_src_img, src_img);
if (src_img->bpp == IMAGE_BPP_BAYER) {
imlib_debayer_image_to_rgb565(&new_src_img, src_img);
} else if (src_img->bpp >= IMAGE_BPP_JPEG) {
jpeg_decompress_image_to_rgb565(&new_src_img, src_img);
}
break;
}
case IMAGE_BPP_BAYER: {
@ -2750,7 +2765,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_bpp = is_bayer ? is_bayer_bpp : src_img->bpp;
imlib_draw_row_data.src_img_bpp = is_bayer_or_jpeg ? is_bayer_or_jpeg_bpp : src_img->bpp;
imlib_draw_row_data.rgb_channel = rgb_channel;
imlib_draw_row_data.alpha = alpha;
imlib_draw_row_data.color_palette = color_palette;
@ -4602,7 +4617,7 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
}
case IMAGE_BPP_BAYER: {
while (y_not_done) {
switch (is_bayer_bpp) {
switch (is_bayer_or_jpeg_bpp) {
case IMAGE_BPP_BINARY: {
uint32_t *dst_row_ptr = imlib_draw_row_get_row_buffer(&imlib_draw_row_data);
imlib_debayer_line_to_binary(dst_x_start, dst_x_end, next_src_y_index,

View File

@ -983,6 +983,9 @@ void imlib_jpeg_compress_init();
void imlib_jpeg_compress_deinit();
void jpeg_mdma_irq_handler();
#endif
void jpeg_decompress_image_to_binary(image_t *dst, image_t *src);
void jpeg_decompress_image_to_grayscale(image_t *dst, image_t *src);
void jpeg_decompress_image_to_rgb565(image_t *dst, image_t *src);
bool jpeg_compress(image_t *src, image_t *dst, int quality, bool realloc);
int jpeg_clean_trailing_bytes(int bpp, uint8_t *data);
void jpeg_read_geometry(FIL *fp, image_t *img, const char *path, jpg_read_settings_t *rs);

3194
src/omv/imlib/jpegd.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -5183,7 +5183,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(args[0]);
image_t *arg_img = py_helper_arg_to_image_mutable_bayer_jpeg(args[0]);
rectangle_t roi;
py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi);

View File

@ -161,6 +161,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/imlib/, \
imlib.o \
integral.o \
integral_mw.o \
jpegd.o \
jpeg.o \
kmeans.o \
lab_tab.o \

View File

@ -89,7 +89,7 @@ target_sources(${MICROPY_TARGET} PRIVATE
${TOP_DIR}/${OMV_DIR}/alloc/umm_malloc.c
${TOP_DIR}/${OMV_DIR}/alloc/dma_alloc.c
${TOP_DIR}/${OMV_DIR}/alloc/unaligned_memcpy.c
${TOP_DIR}/${OMV_DIR}/common/array.c
${TOP_DIR}/${OMV_DIR}/common/ff_wrapper.c
${TOP_DIR}/${OMV_DIR}/common/ini.c
@ -97,7 +97,7 @@ target_sources(${MICROPY_TARGET} PRIVATE
${TOP_DIR}/${OMV_DIR}/common/trace.c
${TOP_DIR}/${OMV_DIR}/common/mutex.c
${TOP_DIR}/${OMV_DIR}/common/usbdbg.c
${TOP_DIR}/${OMV_DIR}/sensors/ov2640.c
${TOP_DIR}/${OMV_DIR}/sensors/ov5640.c
${TOP_DIR}/${OMV_DIR}/sensors/ov7670.c
@ -109,7 +109,7 @@ target_sources(${MICROPY_TARGET} PRIVATE
${TOP_DIR}/${OMV_DIR}/sensors/lepton.c
${TOP_DIR}/${OMV_DIR}/sensors/hm01b0.c
${TOP_DIR}/${OMV_DIR}/sensors/gc2145.c
${TOP_DIR}/${OMV_DIR}/modules/py_clock.c
${TOP_DIR}/${OMV_DIR}/modules/py_gif.c
${TOP_DIR}/${OMV_DIR}/modules/py_helper.c
@ -120,7 +120,7 @@ target_sources(${MICROPY_TARGET} PRIVATE
${TOP_DIR}/${OMV_DIR}/modules/py_sensor.c
${TOP_DIR}/${OMV_DIR}/modules/py_tf.c
${TOP_DIR}/${OMV_DIR}/modules/py_fir.c
${TOP_DIR}/${OMV_DIR}/imlib/agast.c
${TOP_DIR}/${OMV_DIR}/imlib/apriltag.c
${TOP_DIR}/${OMV_DIR}/imlib/bayer.c
@ -147,6 +147,7 @@ target_sources(${MICROPY_TARGET} PRIVATE
${TOP_DIR}/${OMV_DIR}/imlib/imlib.c
${TOP_DIR}/${OMV_DIR}/imlib/integral.c
${TOP_DIR}/${OMV_DIR}/imlib/integral_mw.c
${TOP_DIR}/${OMV_DIR}/imlib/jpegd.c
${TOP_DIR}/${OMV_DIR}/imlib/jpeg.c
${TOP_DIR}/${OMV_DIR}/imlib/kmeans.c
${TOP_DIR}/${OMV_DIR}/imlib/lab_tab.c
@ -220,12 +221,12 @@ if(MICROPY_PY_ULAB)
${MICROPY_ULAB_DIR}/code/scipy/optimize/optimize.c
${MICROPY_ULAB_DIR}/code/scipy/signal/signal.c
${MICROPY_ULAB_DIR}/code/scipy/special/special.c
${MICROPY_ULAB_DIR}/code/ndarray_operators.c
${MICROPY_ULAB_DIR}/code/ulab_tools.c
${MICROPY_ULAB_DIR}/code/ndarray.c
${MICROPY_ULAB_DIR}/code/ndarray_operators.c
${MICROPY_ULAB_DIR}/code/ulab_tools.c
${MICROPY_ULAB_DIR}/code/ndarray.c
${MICROPY_ULAB_DIR}/code/numpy/approx/approx.c
${MICROPY_ULAB_DIR}/code/numpy/compare/compare.c
${MICROPY_ULAB_DIR}/code/ulab_create.c
${MICROPY_ULAB_DIR}/code/ulab_create.c
${MICROPY_ULAB_DIR}/code/numpy/fft/fft.c
${MICROPY_ULAB_DIR}/code/numpy/fft/fft_tools.c
${MICROPY_ULAB_DIR}/code/numpy/filter/filter.c
@ -237,7 +238,7 @@ if(MICROPY_PY_ULAB)
${MICROPY_ULAB_DIR}/code/user/user.c
${MICROPY_ULAB_DIR}/code/numpy/numpy.c
${MICROPY_ULAB_DIR}/code/scipy/scipy.c
${MICROPY_ULAB_DIR}/code/ulab.c
${MICROPY_ULAB_DIR}/code/ulab.c
)
target_sources(${MICROPY_TARGET} PRIVATE ${ULAB_SOURCES})

View File

@ -1606,7 +1606,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(args[0]);
image_t *arg_img = py_helper_arg_to_image_mutable_bayer_jpeg(args[0]);
int arg_x_off = 0;
int arg_y_off = 0;

View File

@ -679,9 +679,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) &&
((src_img->bpp == IMAGE_BPP_RGB565) || src_img->bpp == IMAGE_BPP_BAYER))
|| color_palette;
bool rgb565 = ((rgb_channel == -1) && IMAGE_IS_COLOR(src_img)) || 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;
@ -959,7 +957,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(args[0]);
image_t *arg_img = py_helper_arg_to_image_mutable_bayer_jpeg(args[0]);
int arg_x_off = 0;
int arg_y_off = 0;

View File

@ -195,6 +195,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/imlib/, \
imlib.o \
integral.o \
integral_mw.o \
jpegd.o \
jpeg.o \
kmeans.o \
lab_tab.o \