diff --git a/src/omv/imlib/binary.c b/src/omv/imlib/binary.c index ca1852f83..1e53cced0 100644 --- a/src/omv/imlib/binary.c +++ b/src/omv/imlib/binary.c @@ -1,8 +1,8 @@ /* * This file is part of the OpenMV project. * - * Copyright (c) 2013-2021 Ibrahim Abdelkader - * Copyright (c) 2013-2021 Kwabena W. Agyeman + * Copyright (c) 2013-2024 Ibrahim Abdelkader + * Copyright (c) 2013-2024 Kwabena W. Agyeman * * This work is licensed under the MIT license, see the file LICENSE for details. * @@ -10,7 +10,6 @@ */ #include "imlib.h" -#ifdef IMLIB_ENABLE_BINARY_OPS void imlib_zero_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data) { image_t *mask = data->callback_arg; @@ -118,6 +117,7 @@ void imlib_mask_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data } } +#ifdef IMLIB_ENABLE_BINARY_OPS void imlib_binary(image_t *out, image_t *img, list_t *thresholds, bool invert, bool zero, image_t *mask) { image_t bmp; bmp.w = img->w; @@ -239,33 +239,40 @@ void imlib_invert(image_t *img) { } } -void imlib_b_and_line_op(image_t *img, int line, void *other, void *data, bool vflipped) { - image_t *mask = (image_t *) data; +void imlib_b_and_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data) { + image_t *mask = (image_t *) data->callback_arg; - switch (img->pixfmt) { + switch (data->dst_img->pixfmt) { case PIXFORMAT_BINARY: { - uint32_t *row0 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); - uint32_t *row1 = (uint32_t *) other; + uint32_t *row0 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(data->dst_img, y_row); + uint32_t *row1 = (uint32_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 32; x += 32) { + // Align to 32-bit boundary. + for (; (x % 32) && (x < x_end); x++) { + uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); + uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); + uint32_t p = p0 & p1; + IMAGE_PUT_BINARY_PIXEL_FAST(row0, x, p); + } + + for (; (x_end - x) >= 32; x += 32) { uint32_t p0 = row0[x / 32]; uint32_t p1 = ((uint32_t *) row1)[x / 32]; row0[x / 32] = p0 & p1; } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); uint32_t p = p0 & p1; IMAGE_PUT_BINARY_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); uint32_t p = p0 & p1; @@ -276,28 +283,27 @@ void imlib_b_and_line_op(image_t *img, int line, void *other, void *data, bool v break; } case PIXFORMAT_GRAYSCALE: { - uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); - uint8_t *row1 = (uint8_t *) other; + uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(data->dst_img, y_row); + uint8_t *row1 = (uint8_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 4; x += 4) { + for (; (x_end - x) >= 4; x += 4) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); *((uint32_t *) (row0 + x)) = p0 & p1; } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = p0 & p1; IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = p0 & p1; @@ -308,28 +314,27 @@ void imlib_b_and_line_op(image_t *img, int line, void *other, void *data, bool v break; } case PIXFORMAT_RGB565: { - uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); - uint16_t *row1 = (uint16_t *) other; + uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(data->dst_img, y_row); + uint16_t *row1 = (uint16_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 2; x += 2) { + for (; (x_end - x) >= 2; x += 2) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); *((uint32_t *) (row0 + x)) = p0 & p1; } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t p = p0 & p1; IMAGE_PUT_RGB565_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t p = p0 & p1; @@ -345,37 +350,40 @@ void imlib_b_and_line_op(image_t *img, int line, void *other, void *data, bool v } } -void imlib_b_and(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) { - imlib_image_operation(img, path, other, scalar, imlib_b_and_line_op, mask); -} +void imlib_b_nand_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data) { + image_t *mask = (image_t *) data->callback_arg; -static void imlib_b_nand_line_op(image_t *img, int line, void *other, void *data, bool vflipped) { - image_t *mask = (image_t *) data; - - switch (img->pixfmt) { + switch (data->dst_img->pixfmt) { case PIXFORMAT_BINARY: { - uint32_t *row0 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); - uint32_t *row1 = (uint32_t *) other; + uint32_t *row0 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(data->dst_img, y_row); + uint32_t *row1 = (uint32_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 32; x += 32) { + // Align to 32-bit boundary. + for (; (x % 32) && (x < x_end); x++) { + uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); + uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); + uint32_t p = ~(p0 & p1); + IMAGE_PUT_BINARY_PIXEL_FAST(row0, x, p); + } + + for (; (x_end - x) >= 32; x += 32) { uint32_t p0 = row0[x / 32]; uint32_t p1 = row1[x / 32]; row0[x / 32] = ~(p0 & p1); } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); uint32_t p = ~(p0 & p1); IMAGE_PUT_BINARY_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); uint32_t p = ~(p0 & p1); @@ -386,28 +394,27 @@ static void imlib_b_nand_line_op(image_t *img, int line, void *other, void *data break; } case PIXFORMAT_GRAYSCALE: { - uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); - uint8_t *row1 = (uint8_t *) other; + uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(data->dst_img, y_row); + uint8_t *row1 = (uint8_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 4; x += 4) { + for (; (x_end - x) >= 4; x += 4) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); *((uint32_t *) (row0 + x)) = ~(p0 & p1); } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = ~(p0 & p1); IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = ~(p0 & p1); @@ -418,28 +425,27 @@ static void imlib_b_nand_line_op(image_t *img, int line, void *other, void *data break; } case PIXFORMAT_RGB565: { - uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); - uint16_t *row1 = (uint16_t *) other; + uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(data->dst_img, y_row); + uint16_t *row1 = (uint16_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 2; x += 2) { + for (; (x_end - x) >= 2; x += 2) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); *((uint32_t *) (row0 + x)) = ~(p0 & p1); } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t p = ~(p0 & p1); IMAGE_PUT_RGB565_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t p = ~(p0 & p1); @@ -455,37 +461,40 @@ static void imlib_b_nand_line_op(image_t *img, int line, void *other, void *data } } -void imlib_b_nand(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) { - imlib_image_operation(img, path, other, scalar, imlib_b_nand_line_op, mask); -} +void imlib_b_or_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data) { + image_t *mask = (image_t *) data->callback_arg; -void imlib_b_or_line_op(image_t *img, int line, void *other, void *data, bool vflipped) { - image_t *mask = (image_t *) data; - - switch (img->pixfmt) { + switch (data->dst_img->pixfmt) { case PIXFORMAT_BINARY: { - uint32_t *row0 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); - uint32_t *row1 = (uint32_t *) other; + uint32_t *row0 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(data->dst_img, y_row); + uint32_t *row1 = (uint32_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 32; x += 32) { + // Align to 32-bit boundary. + for (; (x % 32) && (x < x_end); x++) { + uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); + uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); + uint32_t p = p0 | p1; + IMAGE_PUT_BINARY_PIXEL_FAST(row0, x, p); + } + + for (; (x_end - x) >= 32; x += 32) { uint32_t p0 = row0[x / 32]; uint32_t p1 = row1[x / 32]; row0[x / 32] = p0 | p1; } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); uint32_t p = p0 | p1; IMAGE_PUT_BINARY_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); uint32_t p = p0 | p1; @@ -496,28 +505,27 @@ void imlib_b_or_line_op(image_t *img, int line, void *other, void *data, bool vf break; } case PIXFORMAT_GRAYSCALE: { - uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); - uint8_t *row1 = (uint8_t *) other; + uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(data->dst_img, y_row); + uint8_t *row1 = (uint8_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 4; x += 4) { + for (; (x_end - x) >= 4; x += 4) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); *((uint32_t *) (row0 + x)) = p0 | p1; } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = p0 | p1; IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = p0 | p1; @@ -528,28 +536,27 @@ void imlib_b_or_line_op(image_t *img, int line, void *other, void *data, bool vf break; } case PIXFORMAT_RGB565: { - uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); - uint16_t *row1 = (uint16_t *) other; + uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(data->dst_img, y_row); + uint16_t *row1 = (uint16_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 2; x += 2) { + for (; (x_end - x) >= 2; x += 2) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); *((uint32_t *) (row0 + x)) = p0 | p1; } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t p = p0 | p1; IMAGE_PUT_RGB565_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t p = p0 | p1; @@ -565,37 +572,40 @@ void imlib_b_or_line_op(image_t *img, int line, void *other, void *data, bool vf } } -void imlib_b_or(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) { - imlib_image_operation(img, path, other, scalar, imlib_b_or_line_op, mask); -} +void imlib_b_nor_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data) { + image_t *mask = (image_t *) data->callback_arg; -static void imlib_b_nor_line_op(image_t *img, int line, void *other, void *data, bool vflipped) { - image_t *mask = (image_t *) data; - - switch (img->pixfmt) { + switch (data->dst_img->pixfmt) { case PIXFORMAT_BINARY: { - uint32_t *row0 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); - uint32_t *row1 = (uint32_t *) other; + uint32_t *row0 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(data->dst_img, y_row); + uint32_t *row1 = (uint32_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 32; x += 32) { + // Align to 32-bit boundary. + for (; (x % 32) && (x < x_end); x++) { + uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); + uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); + uint32_t p = ~(p0 | p1); + IMAGE_PUT_BINARY_PIXEL_FAST(row0, x, p); + } + + for (; (x_end - x) >= 32; x += 32) { uint32_t p0 = row0[x / 32]; uint32_t p1 = row1[x / 32]; row0[x / 32] = ~(p0 | p1); } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); uint32_t p = ~(p0 | p1); IMAGE_PUT_BINARY_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); uint32_t p = ~(p0 | p1); @@ -606,28 +616,27 @@ static void imlib_b_nor_line_op(image_t *img, int line, void *other, void *data, break; } case PIXFORMAT_GRAYSCALE: { - uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); - uint8_t *row1 = (uint8_t *) other; + uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(data->dst_img, y_row); + uint8_t *row1 = (uint8_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 4; x += 4) { + for (; (x_end - x) >= 4; x += 4) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); *((uint32_t *) (row0 + x)) = ~(p0 | p1); } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = ~(p0 | p1); IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = ~(p0 | p1); @@ -638,28 +647,27 @@ static void imlib_b_nor_line_op(image_t *img, int line, void *other, void *data, break; } case PIXFORMAT_RGB565: { - uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); - uint16_t *row1 = (uint16_t *) other; + uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(data->dst_img, y_row); + uint16_t *row1 = (uint16_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 2; x += 2) { + for (; (x_end - x) >= 2; x += 2) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); *((uint32_t *) (row0 + x)) = ~(p0 | p1); } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t p = ~(p0 | p1); IMAGE_PUT_RGB565_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t p = ~(p0 | p1); @@ -675,37 +683,40 @@ static void imlib_b_nor_line_op(image_t *img, int line, void *other, void *data, } } -void imlib_b_nor(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) { - imlib_image_operation(img, path, other, scalar, imlib_b_nor_line_op, mask); -} +void imlib_b_xor_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data) { + image_t *mask = (image_t *) data->callback_arg; -void imlib_b_xor_line_op(image_t *img, int line, void *other, void *data, bool vflipped) { - image_t *mask = (image_t *) data; - - switch (img->pixfmt) { + switch (data->dst_img->pixfmt) { case PIXFORMAT_BINARY: { - uint32_t *row0 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); - uint32_t *row1 = (uint32_t *) other; + uint32_t *row0 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(data->dst_img, y_row); + uint32_t *row1 = (uint32_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 32; x += 32) { + // Align to 32-bit boundary. + for (; (x % 32) && (x < x_end); x++) { + uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); + uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); + uint32_t p = p0 ^ p1; + IMAGE_PUT_BINARY_PIXEL_FAST(row0, x, p); + } + + for (; (x_end - x) >= 32; x += 32) { uint32_t p0 = row0[x / 32]; uint32_t p1 = row1[x / 32]; row0[x / 32] = p0 ^ p1; } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); uint32_t p = p0 ^ p1; IMAGE_PUT_BINARY_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); uint32_t p = p0 ^ p1; @@ -716,28 +727,27 @@ void imlib_b_xor_line_op(image_t *img, int line, void *other, void *data, bool v break; } case PIXFORMAT_GRAYSCALE: { - uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); - uint8_t *row1 = (uint8_t *) other; + uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(data->dst_img, y_row); + uint8_t *row1 = (uint8_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 4; x += 4) { + for (; (x_end - x) >= 4; x += 4) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); *((uint32_t *) (row0 + x)) = p0 ^ p1; } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = p0 ^ p1; IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = p0 ^ p1; @@ -748,28 +758,27 @@ void imlib_b_xor_line_op(image_t *img, int line, void *other, void *data, bool v break; } case PIXFORMAT_RGB565: { - uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); - uint16_t *row1 = (uint16_t *) other; + uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(data->dst_img, y_row); + uint16_t *row1 = (uint16_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 2; x += 2) { + for (; (x_end - x) >= 2; x += 2) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); *((uint32_t *) (row0 + x)) = p0 ^ p1; } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t p = p0 ^ p1; IMAGE_PUT_RGB565_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t p = p0 ^ p1; @@ -785,37 +794,40 @@ void imlib_b_xor_line_op(image_t *img, int line, void *other, void *data, bool v } } -void imlib_b_xor(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) { - imlib_image_operation(img, path, other, scalar, imlib_b_xor_line_op, mask); -} +void imlib_b_xnor_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data) { + image_t *mask = (image_t *) data->callback_arg; -static void imlib_b_xnor_line_op(image_t *img, int line, void *other, void *data, bool vflipped) { - image_t *mask = (image_t *) data; - - switch (img->pixfmt) { + switch (data->dst_img->pixfmt) { case PIXFORMAT_BINARY: { - uint32_t *row0 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); - uint32_t *row1 = (uint32_t *) other; + uint32_t *row0 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(data->dst_img, y_row); + uint32_t *row1 = (uint32_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 32; x += 32) { + // Align to 32-bit boundary. + for (; (x % 32) && (x < x_end); x++) { + uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); + uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); + uint32_t p = ~(p0 ^ p1); + IMAGE_PUT_BINARY_PIXEL_FAST(row0, x, p); + } + + for (; (x_end - x) >= 32; x += 32) { uint32_t p0 = row0[x / 32]; uint32_t p1 = row1[x / 32]; row0[x / 32] = ~(p0 ^ p1); } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); uint32_t p = ~(p0 ^ p1); IMAGE_PUT_BINARY_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); uint32_t p = ~(p0 ^ p1); @@ -826,28 +838,27 @@ static void imlib_b_xnor_line_op(image_t *img, int line, void *other, void *data break; } case PIXFORMAT_GRAYSCALE: { - uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); - uint8_t *row1 = (uint8_t *) other; + uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(data->dst_img, y_row); + uint8_t *row1 = (uint8_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 4; x += 4) { + for (; (x_end - x) >= 4; x += 4) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); *((uint32_t *) (row0 + x)) = ~(p0 ^ p1); } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = ~(p0 ^ p1); IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = ~(p0 ^ p1); @@ -858,28 +869,27 @@ static void imlib_b_xnor_line_op(image_t *img, int line, void *other, void *data break; } case PIXFORMAT_RGB565: { - uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); - uint16_t *row1 = (uint16_t *) other; + uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(data->dst_img, y_row); + uint16_t *row1 = (uint16_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 2; x += 2) { + for (; (x_end - x) >= 2; x += 2) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); *((uint32_t *) (row0 + x)) = ~(p0 ^ p1); } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t p = ~(p0 ^ p1); IMAGE_PUT_RGB565_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t p = ~(p0 ^ p1); @@ -895,10 +905,6 @@ static void imlib_b_xnor_line_op(image_t *img, int line, void *other, void *data } } -void imlib_b_xnor(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) { - imlib_image_operation(img, path, other, scalar, imlib_b_xnor_line_op, mask); -} - static void imlib_erode_dilate(image_t *img, int ksize, int threshold, int e_or_d, image_t *mask) { int brows = ksize + 1; image_t buf; @@ -1225,27 +1231,26 @@ void imlib_close(image_t *img, int ksize, int threshold, image_t *mask) { imlib_erode(img, ksize, threshold, mask); } -void imlib_top_hat(image_t *img, int ksize, int threshold, image_t *mask) { +static void imlib_hat(image_t *img, int ksize, int threshold, image_t *mask, binary_morph_op_t op) { image_t temp; temp.w = img->w; temp.h = img->h; temp.pixfmt = img->pixfmt; - temp.data = fb_alloc(image_size(img), FB_ALLOC_NO_HINT); + temp.data = fb_alloc(image_size(img), FB_ALLOC_CACHE_ALIGN); memcpy(temp.data, img->data, image_size(img)); - imlib_open(&temp, ksize, threshold, mask); - imlib_difference(img, NULL, &temp, 0, mask); - fb_free(); + op(&temp, ksize, threshold, mask); + void *dst_row_override = fb_alloc0(image_line_size(img), FB_ALLOC_CACHE_ALIGN); + imlib_draw_image(img, &temp, 0, 0, 1.0f, 1.0f, NULL, -1, 256, NULL, NULL, 0, + imlib_difference_line_op, mask, dst_row_override); + fb_free(); // dst_row_override + fb_free(); // temp.data +} + +void imlib_top_hat(image_t *img, int ksize, int threshold, image_t *mask) { + imlib_hat(img, ksize, threshold, mask, imlib_open); } void imlib_black_hat(image_t *img, int ksize, int threshold, image_t *mask) { - image_t temp; - temp.w = img->w; - temp.h = img->h; - temp.pixfmt = img->pixfmt; - temp.data = fb_alloc(image_size(img), FB_ALLOC_NO_HINT); - memcpy(temp.data, img->data, image_size(img)); - imlib_close(&temp, ksize, threshold, mask); - imlib_difference(img, NULL, &temp, 0, mask); - fb_free(); + imlib_hat(img, ksize, threshold, mask, imlib_close); } #endif diff --git a/src/omv/imlib/imlib.c b/src/omv/imlib/imlib.c index 1e74db57f..90a21e4e9 100644 --- a/src/omv/imlib/imlib.c +++ b/src/omv/imlib/imlib.c @@ -606,144 +606,8 @@ bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_setti imblib_parse_extension(img, path); // Enforce extension! return vflipped; } - -static void imlib_read_pixels(FIL *fp, image_t *img, int n_lines, img_read_settings_t *rs) { - switch (rs->format) { - case FORMAT_BMP: - bmp_read_pixels(fp, img, n_lines, &rs->bmp_rs); - break; - case FORMAT_PNM: - ppm_read_pixels(fp, img, n_lines, &rs->ppm_rs); - break; - default: // won't happen - break; - } -} #endif //IMLIB_ENABLE_IMAGE_FILE_IO -void imlib_image_operation(image_t *img, const char *path, image_t *other, int scalar, line_op_t op, void *data) { - if (path) { - #if defined(IMLIB_ENABLE_IMAGE_FILE_IO) - uint32_t size = fb_avail() / 2; - void *alloc = fb_alloc(size, FB_ALLOC_NO_HINT); // We have to do this before the read. - // This code reads a window of an image in at a time and then executes - // the line operation on each line in that window before moving to the - // next window. The vflipped part is here because BMP files can be saved - // vertically flipped resulting in us reading the image backwards. - FIL fp; - image_t temp; - img_read_settings_t rs; - bool vflipped = imlib_read_geometry(&fp, &temp, path, &rs); - if (!IM_EQUAL(img, &temp)) { - file_close(&fp); - mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Images not equal!")); - } - // When processing vertically flipped images the read function will fill - // the window up from the bottom. The read function assumes that the - // window is equal to an image in size. However, since this is not the - // case we shrink the window size to how many lines we're buffering. - temp.pixels = alloc; - // Set the max buffer height to image height. - temp.h = IM_MIN((uint32_t) img->h, (size / (temp.w * temp.bpp))); - // This should never happen unless someone forgot to free. - if ((!temp.pixels) || (!temp.h)) { - mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("Not enough memory available!")); - } - for (int i = 0; i < img->h; i += temp.h) { - // goes past end - int lines = IM_MIN(temp.h, img->h - i); - imlib_read_pixels(&fp, &temp, lines, &rs); - for (int j = 0; j < lines; j++) { - if (!vflipped) { - op(img, i + j, temp.pixels + (temp.w * temp.bpp * j), data, false); - } else { - op(img, (img->h - i - lines) + j, temp.pixels + (temp.w * temp.bpp * j), data, true); - } - } - } - file_close(&fp); - fb_free(); - #else - mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Image I/O is not supported")); - #endif - } else if (other) { - if (!IM_EQUAL(img, other)) { - mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Images not equal!")); - } - switch (img->pixfmt) { - case PIXFORMAT_BINARY: { - for (int i = 0, ii = img->h; i < ii; i++) { - op(img, i, IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(other, i), data, false); - } - break; - } - case PIXFORMAT_GRAYSCALE: { - for (int i = 0, ii = img->h; i < ii; i++) { - op(img, i, IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(other, i), data, false); - } - break; - } - case PIXFORMAT_RGB565: { - for (int i = 0, ii = img->h; i < ii; i++) { - op(img, i, IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(other, i), data, false); - } - break; - } - default: { - break; - } - } - } else { - switch (img->pixfmt) { - case PIXFORMAT_BINARY: { - uint32_t *row_ptr = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img), FB_ALLOC_NO_HINT); - - for (int i = 0, ii = img->w; i < ii; i++) { - IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr, i, scalar); - } - - for (int i = 0, ii = img->h; i < ii; i++) { - op(img, i, row_ptr, data, false); - } - - fb_free(); - break; - } - case PIXFORMAT_GRAYSCALE: { - uint8_t *row_ptr = fb_alloc(IMAGE_GRAYSCALE_LINE_LEN_BYTES(img), FB_ALLOC_NO_HINT); - - for (int i = 0, ii = img->w; i < ii; i++) { - IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr, i, scalar); - } - - for (int i = 0, ii = img->h; i < ii; i++) { - op(img, i, row_ptr, data, false); - } - - fb_free(); - break; - } - case PIXFORMAT_RGB565: { - uint16_t *row_ptr = fb_alloc(IMAGE_RGB565_LINE_LEN_BYTES(img), FB_ALLOC_NO_HINT); - - for (int i = 0, ii = img->w; i < ii; i++) { - IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, i, scalar); - } - - for (int i = 0, ii = img->h; i < ii; i++) { - op(img, i, row_ptr, data, false); - } - - fb_free(); - break; - } - default: { - break; - } - } - } -} - #if defined(IMLIB_ENABLE_IMAGE_FILE_IO) void imlib_load_image(image_t *img, const char *path) { FIL fp; diff --git a/src/omv/imlib/imlib.h b/src/omv/imlib/imlib.h index 69227432e..7330ab0ca 100644 --- a/src/omv/imlib/imlib.h +++ b/src/omv/imlib/imlib.h @@ -1373,15 +1373,12 @@ void imlib_zero_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data void imlib_mask_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data); void imlib_binary(image_t *out, image_t *img, list_t *thresholds, bool invert, bool zero, image_t *mask); void imlib_invert(image_t *img); -void imlib_b_and_line_op(image_t *img, int line, void *other, void *data, bool vflipped); -void imlib_b_and(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); -void imlib_b_nand(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); -void imlib_b_or_line_op(image_t *img, int line, void *other, void *data, bool vflipped); -void imlib_b_or(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); -void imlib_b_nor(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); -void imlib_b_xor_line_op(image_t *img, int line, void *other, void *data, bool vflipped); -void imlib_b_xor(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); -void imlib_b_xnor(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); +void imlib_b_and_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data); +void imlib_b_nand_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data); +void imlib_b_or_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data); +void imlib_b_nor_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data); +void imlib_b_xor_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data); +void imlib_b_xnor_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data); void imlib_erode(image_t *img, int ksize, int threshold, image_t *mask); void imlib_dilate(image_t *img, int ksize, int threshold, image_t *mask); void imlib_open(image_t *img, int ksize, int threshold, image_t *mask); @@ -1389,20 +1386,12 @@ void imlib_close(image_t *img, int ksize, int threshold, image_t *mask); void imlib_top_hat(image_t *img, int ksize, int threshold, image_t *mask); void imlib_black_hat(image_t *img, int ksize, int threshold, image_t *mask); // Math Functions -void imlib_replace(image_t *img, - const char *path, - image_t *other, - int scalar, - bool hmirror, - bool vflip, - bool transpose, - image_t *mask); -void imlib_add(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); -void imlib_sub(image_t *img, const char *path, image_t *other, int scalar, bool reverse, image_t *mask); -void imlib_min(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); -void imlib_max(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); -void imlib_difference(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); -void imlib_blend(image_t *img, const char *path, image_t *other, int scalar, float alpha, image_t *mask); +void imlib_add_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data); +void imlib_sub_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data); +void imlib_rsub_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data); +void imlib_min_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data); +void imlib_max_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data); +void imlib_difference_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data); // Filtering Functions void imlib_histeq(image_t *img, image_t *mask); void imlib_clahe_histeq(image_t *img, float clip_limit, image_t *mask); diff --git a/src/omv/imlib/mathop.c b/src/omv/imlib/mathop.c index c45dc0385..42e0a6482 100644 --- a/src/omv/imlib/mathop.c +++ b/src/omv/imlib/mathop.c @@ -1,8 +1,8 @@ /* * This file is part of the OpenMV project. * - * Copyright (c) 2013-2021 Ibrahim Abdelkader - * Copyright (c) 2013-2021 Kwabena W. Agyeman + * Copyright (c) 2013-2024 Ibrahim Abdelkader + * Copyright (c) 2013-2024 Kwabena W. Agyeman * * This work is licensed under the MIT license, see the file LICENSE for details. * @@ -11,177 +11,36 @@ #include "imlib.h" #ifdef IMLIB_ENABLE_MATH_OPS -typedef struct imlib_replace_line_op_state { - bool hmirror, vflip, transpose; - image_t *mask; -} imlib_replace_line_op_state_t; +void imlib_add_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data) { + image_t *mask = (image_t *) data->callback_arg; -static void imlib_replace_line_op(image_t *img, int line, void *other, void *data, bool vflipped) { - bool hmirror = ((imlib_replace_line_op_state_t *) data)->hmirror; - bool vflip = ((imlib_replace_line_op_state_t *) data)->vflip; - bool transpose = ((imlib_replace_line_op_state_t *) data)->transpose; - image_t *mask = ((imlib_replace_line_op_state_t *) data)->mask; - - image_t target; - memcpy(&target, img, sizeof(image_t)); - - if (transpose) { - int w = target.w; - int h = target.h; - target.w = h; - target.h = w; - } - - switch (img->pixfmt) { + switch (data->dst_img->pixfmt) { case PIXFORMAT_BINARY: { - int v_line = vflip ? (img->h - line - 1) : line; - for (int i = 0, j = img->w; i < j; i++) { - int h_i = hmirror ? (img->w - i - 1) : i; - - if ((!mask) || image_get_mask_pixel(mask, h_i, v_line)) { - int pixel = IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), h_i); - IMAGE_PUT_BINARY_PIXEL(&target, transpose ? v_line : i, transpose ? i : v_line, pixel); - } - } + imlib_b_or_line_op(x, x_end, y_row, data); break; } case PIXFORMAT_GRAYSCALE: { - int v_line = vflip ? (img->h - line - 1) : line; - for (int i = 0, j = img->w; i < j; i++) { - int h_i = hmirror ? (img->w - i - 1) : i; - - if ((!mask) || image_get_mask_pixel(mask, h_i, v_line)) { - int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), h_i); - IMAGE_PUT_GRAYSCALE_PIXEL(&target, transpose ? v_line : i, transpose ? i : v_line, pixel); - } - } - break; - } - case PIXFORMAT_RGB565: { - int v_line = vflip ? (img->h - line - 1) : line; - for (int i = 0, j = img->w; i < j; i++) { - int h_i = hmirror ? (img->w - i - 1) : i; - - if ((!mask) || image_get_mask_pixel(mask, h_i, v_line)) { - int pixel = IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), h_i); - IMAGE_PUT_RGB565_PIXEL(&target, transpose ? v_line : i, transpose ? i : v_line, pixel); - } - } - break; - } - default: { - break; - } - } -} - -void imlib_replace(image_t *img, - const char *path, - image_t *other, - int scalar, - bool hmirror, - bool vflip, - bool transpose, - image_t *mask) { - bool in_place = img->data == other->data; - image_t temp; - - if (in_place) { - memcpy(&temp, other, sizeof(image_t)); - temp.data = fb_alloc(image_size(&temp), FB_ALLOC_NO_HINT); - memcpy(temp.data, other->data, image_size(&temp)); - other = &temp; - } - - // To improve transpose performance we will split the operation up into chunks that fit in - // onchip RAM. These chunks will then be copied to the target buffer in an efficent manner. - if (path == NULL && other && transpose) { - uint32_t size; - void *data = fb_alloc_all(&size, FB_ALLOC_PREFER_SPEED); - // line_num stores how many lines we can do at a time with on-chip RAM. - int line_num = size / image_line_size(other); - // Transposed chunks will be copied to the output image... - uint8_t *img_data = img->data; - int t_line_size = (image_line_size(img) * img->h) / img->w; - // Work top to bottom transposing as many lines at a time in a chunk of the image. - for (int i = 0, ii = other->h; i < ii; i += line_num) { - line_num = IM_MIN(line_num, (ii - i)); - // Make an image that is a slice of the input image. - image_t in = {.w = other->w, .h = line_num, .pixfmt = other->pixfmt}; - in.data = other->data + (image_line_size(other) * i); - // Make an image that will hold the transposed output. - image_t out = in; - out.data = data; - // Transpose the slice of the input image. - imlib_replace_line_op_state_t state; - state.hmirror = hmirror; - state.vflip = vflip; - state.mask = mask; - state.transpose = true; - imlib_image_operation(&out, NULL, &in, 0, imlib_replace_line_op, &state); - out.w = line_num; - out.h = other->w; - // Copy lines of the chunk to the target image. - int out_line_size = image_line_size(&out); - for (int j = 0, jj = out.h; j < jj; j++) { - memcpy(img_data + (t_line_size * j), out.data + (out_line_size * j), out_line_size); - } - // Slide the offset for the first line over by the size of the slice we transposed. - img_data += out_line_size; - } - fb_free(); // fb_alloc_all - } else { - imlib_replace_line_op_state_t state; - state.hmirror = hmirror; - state.vflip = vflip; - state.mask = mask; - state.transpose = transpose; - imlib_image_operation(img, path, other, scalar, imlib_replace_line_op, &state); - } - - if (in_place) { - fb_free(); - } - - if (transpose) { - int w = img->w; - int h = img->h; - img->w = h; - img->h = w; - } -} - -static void imlib_add_line_op(image_t *img, int line, void *other, void *data, bool vflipped) { - image_t *mask = (image_t *) data; - - switch (img->pixfmt) { - case PIXFORMAT_BINARY: { - imlib_b_or_line_op(img, line, other, data, vflipped); - break; - } - case PIXFORMAT_GRAYSCALE: { - uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); - uint8_t *row1 = (uint8_t *) other; + uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(data->dst_img, y_row); + uint8_t *row1 = (uint8_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if defined(ARM_MATH_DSP) - for (; (img->w - x) >= 4; x += 4) { + for (; (x_end - x) >= 4; x += 4) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); *((uint32_t *) (row0 + x)) = __UQADD8(p0, p1); } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = __USAT(p0 + p1, 8); IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = __USAT(p0 + p1, 8); @@ -192,13 +51,12 @@ static void imlib_add_line_op(image_t *img, int line, void *other, void *data, b break; } case PIXFORMAT_RGB565: { - uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); - uint16_t *row1 = (uint16_t *) other; + uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(data->dst_img, y_row); + uint16_t *row1 = (uint16_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if defined(ARM_MATH_DSP) - for (; (img->w - x) >= 2; x += 2) { + for (; (x_end - x) >= 2; x += 2) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); uint32_t r = __USAT16(((p0 >> 11) & 0x1f001f) + ((p1 >> 11) & 0x1f001f), 5); @@ -208,7 +66,7 @@ static void imlib_add_line_op(image_t *img, int line, void *other, void *data, b } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t r = __USAT(COLOR_RGB565_TO_R5(p0) + COLOR_RGB565_TO_R5(p1), 5); @@ -217,8 +75,8 @@ static void imlib_add_line_op(image_t *img, int line, void *other, void *data, b IMAGE_PUT_RGB565_PIXEL_FAST(row0, x, COLOR_R5_G6_B5_TO_RGB565(r, g, b)); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t r = __USAT(COLOR_RGB565_TO_R5(p0) + COLOR_RGB565_TO_R5(p1), 5); @@ -236,37 +94,40 @@ static void imlib_add_line_op(image_t *img, int line, void *other, void *data, b } } -void imlib_add(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) { - imlib_image_operation(img, path, other, scalar, imlib_add_line_op, mask); -} +void imlib_sub_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data) { + image_t *mask = (image_t *) data->callback_arg; -static void imlib_sub_line_op(image_t *img, int line, void *other, void *data, bool vflipped) { - image_t *mask = (image_t *) data; - - switch (img->pixfmt) { + switch (data->dst_img->pixfmt) { case PIXFORMAT_BINARY: { - uint32_t *row0 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); - uint32_t *row1 = (uint32_t *) other; + uint32_t *row0 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(data->dst_img, y_row); + uint32_t *row1 = (uint32_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 32; x += 32) { + // Align to 32-bit boundary. + for (; (x % 32) && (x < x_end); x++) { + uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); + uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); + uint32_t p = p0 > p1; + IMAGE_PUT_BINARY_PIXEL_FAST(row0, x, p); + } + + for (; (x_end - x) >= 32; x += 32) { uint32_t p0 = row0[x / 32]; uint32_t p1 = row1[x / 32]; row0[x / 32] = p0 & (~p1); // the same as p0 > p1 for all bits } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); uint32_t p = p0 > p1; IMAGE_PUT_BINARY_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); uint32_t p = p0 > p1; @@ -277,28 +138,27 @@ static void imlib_sub_line_op(image_t *img, int line, void *other, void *data, b break; } case PIXFORMAT_GRAYSCALE: { - uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); - uint8_t *row1 = (uint8_t *) other; + uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(data->dst_img, y_row); + uint8_t *row1 = (uint8_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if defined(ARM_MATH_DSP) - for (; (img->w - x) >= 4; x += 4) { + for (; (x_end - x) >= 4; x += 4) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); *((uint32_t *) (row0 + x)) = __UQSUB8(p0, p1); } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = __USAT((int32_t) (p0 - p1), 8); IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = __USAT((int32_t) (p0 - p1), 8); @@ -309,13 +169,12 @@ static void imlib_sub_line_op(image_t *img, int line, void *other, void *data, b break; } case PIXFORMAT_RGB565: { - uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); - uint16_t *row1 = (uint16_t *) other; + uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(data->dst_img, y_row); + uint16_t *row1 = (uint16_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if defined(ARM_MATH_DSP) - for (; (img->w - x) >= 2; x += 2) { + for (; (x_end - x) >= 2; x += 2) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); uint32_t r = __USAT16(__SSUB16((p0 >> 11) & 0x1f001f, (p1 >> 11) & 0x1f001f), 5); @@ -325,7 +184,7 @@ static void imlib_sub_line_op(image_t *img, int line, void *other, void *data, b } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t r = __USAT((int32_t) (COLOR_RGB565_TO_R5(p0) - COLOR_RGB565_TO_R5(p1)), 5); @@ -334,8 +193,8 @@ static void imlib_sub_line_op(image_t *img, int line, void *other, void *data, b IMAGE_PUT_RGB565_PIXEL_FAST(row0, x, COLOR_R5_G6_B5_TO_RGB565(r, g, b)); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t r = __USAT((int32_t) (COLOR_RGB565_TO_R5(p0) - COLOR_RGB565_TO_R5(p1)), 5); @@ -353,33 +212,40 @@ static void imlib_sub_line_op(image_t *img, int line, void *other, void *data, b } } -static void imlib_rsub_line_op(image_t *img, int line, void *other, void *data, bool vflipped) { - image_t *mask = (image_t *) data; +void imlib_rsub_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data) { + image_t *mask = (image_t *) data->callback_arg; - switch (img->pixfmt) { + switch (data->dst_img->pixfmt) { case PIXFORMAT_BINARY: { - uint32_t *row0 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); - uint32_t *row1 = (uint32_t *) other; + uint32_t *row0 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(data->dst_img, y_row); + uint32_t *row1 = (uint32_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if (__ARM_ARCH > 6) - for (; (img->w - x) >= 32; x += 32) { + // Align to 32-bit boundary. + for (; (x % 32) && (x < x_end); x++) { + uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); + uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); + uint32_t p = p1 > p0; + IMAGE_PUT_BINARY_PIXEL_FAST(row0, x, p); + } + + for (; (x_end - x) >= 32; x += 32) { uint32_t p0 = row0[x / 32]; uint32_t p1 = row1[x / 32]; row0[x / 32] = p1 & (~p0); // the same as p1 > p0 for all bits } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); uint32_t p = p1 > p0; IMAGE_PUT_BINARY_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_BINARY_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_BINARY_PIXEL_FAST(row1, x); uint32_t p = p1 > p0; @@ -390,28 +256,27 @@ static void imlib_rsub_line_op(image_t *img, int line, void *other, void *data, break; } case PIXFORMAT_GRAYSCALE: { - uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); - uint8_t *row1 = (uint8_t *) other; + uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(data->dst_img, y_row); + uint8_t *row1 = (uint8_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if defined(ARM_MATH_DSP) - for (; (img->w - x) >= 4; x += 4) { + for (; (x_end - x) >= 4; x += 4) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); *((uint32_t *) (row0 + x)) = __UQSUB8(p1, p0); } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = __USAT((int32_t) (p1 - p0), 8); IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = __USAT((int32_t) (p1 - p0), 8); @@ -422,13 +287,12 @@ static void imlib_rsub_line_op(image_t *img, int line, void *other, void *data, break; } case PIXFORMAT_RGB565: { - uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); - uint16_t *row1 = (uint16_t *) other; + uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(data->dst_img, y_row); + uint16_t *row1 = (uint16_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if defined(ARM_MATH_DSP) - for (; (img->w - x) >= 2; x += 2) { + for (; (x_end - x) >= 2; x += 2) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); uint32_t r = __USAT16(__SSUB16((p1 >> 11) & 0x1f001f, (p0 >> 11) & 0x1f001f), 5); @@ -438,7 +302,7 @@ static void imlib_rsub_line_op(image_t *img, int line, void *other, void *data, } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t r = __USAT((int32_t) (COLOR_RGB565_TO_R5(p1) - COLOR_RGB565_TO_R5(p0)), 5); @@ -447,8 +311,8 @@ static void imlib_rsub_line_op(image_t *img, int line, void *other, void *data, IMAGE_PUT_RGB565_PIXEL_FAST(row0, x, COLOR_R5_G6_B5_TO_RGB565(r, g, b)); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t r = __USAT((int32_t) (COLOR_RGB565_TO_R5(p1) - COLOR_RGB565_TO_R5(p0)), 5); @@ -466,25 +330,20 @@ static void imlib_rsub_line_op(image_t *img, int line, void *other, void *data, } } -void imlib_sub(image_t *img, const char *path, image_t *other, int scalar, bool reverse, image_t *mask) { - imlib_image_operation(img, path, other, scalar, reverse ? imlib_rsub_line_op : imlib_sub_line_op, mask); -} +void imlib_min_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data) { + image_t *mask = (image_t *) data->callback_arg; -static void imlib_min_line_op(image_t *img, int line, void *other, void *data, bool vflipped) { - image_t *mask = (image_t *) data; - - switch (img->pixfmt) { + switch (data->dst_img->pixfmt) { case PIXFORMAT_BINARY: { - imlib_b_and_line_op(img, line, other, data, vflipped); + imlib_b_and_line_op(x, x_end, y_row, data); } case PIXFORMAT_GRAYSCALE: { - uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); - uint8_t *row1 = (uint8_t *) other; + uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(data->dst_img, y_row); + uint8_t *row1 = (uint8_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if defined(ARM_MATH_DSP) - for (; (img->w - x) >= 4; x += 4) { + for (; (x_end - x) >= 4; x += 4) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); __USUB8(p0, p1); @@ -492,15 +351,15 @@ static void imlib_min_line_op(image_t *img, int line, void *other, void *data, b } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = IM_MIN(p0, p1); IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = IM_MIN(p0, p1); @@ -511,13 +370,12 @@ static void imlib_min_line_op(image_t *img, int line, void *other, void *data, b break; } case PIXFORMAT_RGB565: { - uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); - uint16_t *row1 = (uint16_t *) other; + uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(data->dst_img, y_row); + uint16_t *row1 = (uint16_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if defined(ARM_MATH_DSP) - for (; (img->w - x) >= 2; x += 2) { + for (; (x_end - x) >= 2; x += 2) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); uint32_t p0_rb = p0 & 0xf81ff81f, p1_rb = p1 & 0xf81ff81f; @@ -530,7 +388,7 @@ static void imlib_min_line_op(image_t *img, int line, void *other, void *data, b } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t r = IM_MIN(COLOR_RGB565_TO_R5(p0), COLOR_RGB565_TO_R5(p1)); @@ -539,8 +397,8 @@ static void imlib_min_line_op(image_t *img, int line, void *other, void *data, b IMAGE_PUT_RGB565_PIXEL_FAST(row0, x, COLOR_R5_G6_B5_TO_RGB565(r, g, b)); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t r = IM_MIN(COLOR_RGB565_TO_R5(p0), COLOR_RGB565_TO_R5(p1)); @@ -558,26 +416,21 @@ static void imlib_min_line_op(image_t *img, int line, void *other, void *data, b } } -void imlib_min(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) { - imlib_image_operation(img, path, other, scalar, imlib_min_line_op, mask); -} +void imlib_max_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data) { + image_t *mask = (image_t *) data->callback_arg; -static void imlib_max_line_op(image_t *img, int line, void *other, void *data, bool vflipped) { - image_t *mask = (image_t *) data; - - switch (img->pixfmt) { + switch (data->dst_img->pixfmt) { case PIXFORMAT_BINARY: { - imlib_b_or_line_op(img, line, other, data, vflipped); + imlib_b_or_line_op(x, x_end, y_row, data); break; } case PIXFORMAT_GRAYSCALE: { - uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); - uint8_t *row1 = (uint8_t *) other; + uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(data->dst_img, y_row); + uint8_t *row1 = (uint8_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if defined(ARM_MATH_DSP) - for (; (img->w - x) >= 4; x += 4) { + for (; (x_end - x) >= 4; x += 4) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); __USUB8(p0, p1); @@ -585,15 +438,15 @@ static void imlib_max_line_op(image_t *img, int line, void *other, void *data, b } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = IM_MAX(p0, p1); IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = IM_MAX(p0, p1); @@ -604,13 +457,12 @@ static void imlib_max_line_op(image_t *img, int line, void *other, void *data, b break; } case PIXFORMAT_RGB565: { - uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); - uint16_t *row1 = (uint16_t *) other; + uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(data->dst_img, y_row); + uint16_t *row1 = (uint16_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if defined(ARM_MATH_DSP) - for (; (img->w - x) >= 2; x += 2) { + for (; (x_end - x) >= 2; x += 2) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); uint32_t p0_rb = p0 & 0xf81ff81f, p1_rb = p1 & 0xf81ff81f; @@ -623,7 +475,7 @@ static void imlib_max_line_op(image_t *img, int line, void *other, void *data, b } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t r = IM_MAX(COLOR_RGB565_TO_R5(p0), COLOR_RGB565_TO_R5(p1)); @@ -632,8 +484,8 @@ static void imlib_max_line_op(image_t *img, int line, void *other, void *data, b IMAGE_PUT_RGB565_PIXEL_FAST(row0, x, COLOR_R5_G6_B5_TO_RGB565(r, g, b)); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t r = IM_MAX(COLOR_RGB565_TO_R5(p0), COLOR_RGB565_TO_R5(p1)); @@ -651,26 +503,21 @@ static void imlib_max_line_op(image_t *img, int line, void *other, void *data, b } } -void imlib_max(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) { - imlib_image_operation(img, path, other, scalar, imlib_max_line_op, mask); -} +void imlib_difference_line_op(int x, int x_end, int y_row, imlib_draw_row_data_t *data) { + image_t *mask = (image_t *) data->callback_arg; -static void imlib_difference_line_op(image_t *img, int line, void *other, void *data, bool vflipped) { - image_t *mask = (image_t *) data; - - switch (img->pixfmt) { + switch (data->dst_img->pixfmt) { case PIXFORMAT_BINARY: { - imlib_b_xor_line_op(img, line, other, data, vflipped); + imlib_b_xor_line_op(x, x_end, y_row, data); break; } case PIXFORMAT_GRAYSCALE: { - uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); - uint8_t *row1 = (uint8_t *) other; + uint8_t *row0 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(data->dst_img, y_row); + uint8_t *row1 = (uint8_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if defined(ARM_MATH_DSP) - for (; (img->w - x) >= 4; x += 4) { + for (; (x_end - x) >= 4; x += 4) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); uint32_t sub0 = __USUB8(p0, p1); @@ -679,15 +526,15 @@ static void imlib_difference_line_op(image_t *img, int line, void *other, void * } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = __USAD8(p0, p1); IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row0, x, p); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row1, x); uint32_t p = __USAD8(p0, p1); @@ -698,13 +545,12 @@ static void imlib_difference_line_op(image_t *img, int line, void *other, void * break; } case PIXFORMAT_RGB565: { - uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); - uint16_t *row1 = (uint16_t *) other; + uint16_t *row0 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(data->dst_img, y_row); + uint16_t *row1 = (uint16_t *) data->dst_row_override; if (!mask) { - size_t x = 0; #if defined(ARM_MATH_DSP) - for (; (img->w - x) >= 2; x += 2) { + for (; (x_end - x) >= 2; x += 2) { uint32_t p0 = *((uint32_t *) (row0 + x)); uint32_t p1 = *((uint32_t *) (row1 + x)); uint32_t p0_rb = p0 & 0xf81ff81f, p1_rb = p1 & 0xf81ff81f; @@ -719,7 +565,7 @@ static void imlib_difference_line_op(image_t *img, int line, void *other, void * } #endif - for (; x < img->w; x++) { + for (; x < x_end; x++) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t r = __USAD8(COLOR_RGB565_TO_R5(p0), COLOR_RGB565_TO_R5(p1)); @@ -728,8 +574,8 @@ static void imlib_difference_line_op(image_t *img, int line, void *other, void * IMAGE_PUT_RGB565_PIXEL_FAST(row0, x, COLOR_R5_G6_B5_TO_RGB565(r, g, b)); } } else { - for (size_t x = 0; x < img->w; x++) { - if (image_get_mask_pixel(mask, x, line)) { + for (; x < x_end; x++) { + if (image_get_mask_pixel(mask, x, y_row)) { uint32_t p0 = IMAGE_GET_RGB565_PIXEL_FAST(row0, x); uint32_t p1 = IMAGE_GET_RGB565_PIXEL_FAST(row1, x); uint32_t r = __USAD8(COLOR_RGB565_TO_R5(p0), COLOR_RGB565_TO_R5(p1)); @@ -746,69 +592,4 @@ static void imlib_difference_line_op(image_t *img, int line, void *other, void * } } } - -void imlib_difference(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) { - imlib_image_operation(img, path, other, scalar, imlib_difference_line_op, mask); -} - -typedef struct imlib_blend_line_op_state { - float alpha; - image_t *mask; -} imlib_blend_line_op_t; - -static void imlib_blend_line_op(image_t *img, int line, void *other, void *data, bool vflipped) { - float alpha = ((imlib_blend_line_op_t *) data)->alpha, beta = 1 - alpha; - image_t *mask = ((imlib_blend_line_op_t *) data)->mask; - - switch (img->pixfmt) { - case PIXFORMAT_BINARY: { - uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); - for (int i = 0, j = img->w; i < j; i++) { - if ((!mask) || image_get_mask_pixel(mask, i, line)) { - int dataPixel = IMAGE_GET_BINARY_PIXEL_FAST(data, i); - int otherPixel = IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i); - int p = (dataPixel * alpha) + (otherPixel * beta); - IMAGE_PUT_BINARY_PIXEL_FAST(data, i, p); - } - } - break; - } - case PIXFORMAT_GRAYSCALE: { - uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); - for (int i = 0, j = img->w; i < j; i++) { - if ((!mask) || image_get_mask_pixel(mask, i, line)) { - int dataPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i); - int otherPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i); - int p = (dataPixel * alpha) + (otherPixel * beta); - IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, p); - } - } - break; - } - case PIXFORMAT_RGB565: { - uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); - for (int i = 0, j = img->w; i < j; i++) { - if ((!mask) || image_get_mask_pixel(mask, i, line)) { - int dataPixel = IMAGE_GET_RGB565_PIXEL_FAST(data, i); - int otherPixel = IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i); - int r = (COLOR_RGB565_TO_R5(dataPixel) * alpha) + (COLOR_RGB565_TO_R5(otherPixel) * beta); - int g = (COLOR_RGB565_TO_G6(dataPixel) * alpha) + (COLOR_RGB565_TO_G6(otherPixel) * beta); - int b = (COLOR_RGB565_TO_B5(dataPixel) * alpha) + (COLOR_RGB565_TO_B5(otherPixel) * beta); - IMAGE_PUT_RGB565_PIXEL_FAST(data, i, COLOR_R5_G6_B5_TO_RGB565(r, g, b)); - } - } - break; - } - default: { - break; - } - } -} - -void imlib_blend(image_t *img, const char *path, image_t *other, int scalar, float alpha, image_t *mask) { - imlib_blend_line_op_t state; - state.alpha = alpha; - state.mask = mask; - imlib_image_operation(img, path, other, scalar, imlib_blend_line_op, &state); -} -#endif //IMLIB_ENABLE_MATH_OPS +#endif // IMLIB_ENABLE_MATH_OPS diff --git a/src/omv/modules/py_image.c b/src/omv/modules/py_image.c index d416db159..77f844804 100644 --- a/src/omv/modules/py_image.c +++ b/src/omv/modules/py_image.c @@ -1491,94 +1491,6 @@ static mp_obj_t py_image_draw_edges(uint n_args, const mp_obj_t *args, mp_map_t } static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_edges_obj, 2, py_image_draw_edges); -static mp_obj_t py_image_draw_image(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - fb_alloc_mark(); - image_t *arg_img = py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); - image_t *arg_other = py_helper_arg_to_image(args[1], ARG_IMAGE_ANY | ARG_IMAGE_ALLOC); - - const mp_obj_t *arg_vec; - uint offset = py_helper_consume_array(n_args, args, 2, 2, &arg_vec); - int arg_x_off = mp_obj_get_int(arg_vec[0]); - int arg_y_off = mp_obj_get_int(arg_vec[1]); - - float arg_x_scale = 1.f; - bool got_x_scale = py_helper_keyword_float_maybe(n_args, - args, - offset + 0, - kw_args, - MP_OBJ_NEW_QSTR(MP_QSTR_x_scale), - &arg_x_scale); - - float arg_y_scale = 1.f; - bool got_y_scale = py_helper_keyword_float_maybe(n_args, - args, - offset + 1, - kw_args, - MP_OBJ_NEW_QSTR(MP_QSTR_y_scale), - &arg_y_scale); - - rectangle_t arg_roi; - py_helper_keyword_rectangle_roi(arg_other, n_args, args, offset + 2, kw_args, &arg_roi); - - int arg_rgb_channel = py_helper_keyword_int(n_args, args, offset + 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgb_channel), -1); - if ((arg_rgb_channel < -1) || (2 < arg_rgb_channel)) { - mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("-1 <= rgb_channel <= 2!")); - } - - int arg_alpha = py_helper_keyword_int(n_args, args, offset + 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_alpha), 256); - if ((arg_alpha < 0) || (256 < arg_alpha)) { - mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("0 <= alpha <= 256!")); - } - - const uint16_t *color_palette = py_helper_keyword_color_palette(n_args, args, offset + 5, kw_args, NULL); - const uint8_t *alpha_palette = py_helper_keyword_alpha_palette(n_args, args, offset + 6, kw_args, NULL); - - image_hint_t hint = py_helper_keyword_int(n_args, args, offset + 7, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_hint), 0); - - float arg_x_size; - bool got_x_size = py_helper_keyword_float_maybe(n_args, - args, - offset + 8, - kw_args, - MP_OBJ_NEW_QSTR(MP_QSTR_x_size), - &arg_x_size); - - float arg_y_size; - bool got_y_size = py_helper_keyword_float_maybe(n_args, - args, - offset + 9, - kw_args, - MP_OBJ_NEW_QSTR(MP_QSTR_y_size), - &arg_y_size); - - if (got_x_scale && got_x_size) { - mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Choose either x_scale or x_size not both!")); - } - if (got_y_scale && got_y_size) { - mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Choose either y_scale or y_size not both!")); - } - - if (got_x_size) { - arg_x_scale = arg_x_size / arg_roi.w; - } - if (got_y_size) { - arg_y_scale = arg_y_size / arg_roi.h; - } - - if ((!got_x_scale) && (!got_x_size) && got_y_size) { - arg_x_scale = arg_y_scale; - } - if ((!got_y_scale) && (!got_y_size) && got_x_size) { - arg_y_scale = arg_x_scale; - } - - imlib_draw_image(arg_img, arg_other, arg_x_off, arg_y_off, arg_x_scale, arg_y_scale, &arg_roi, - arg_rgb_channel, arg_alpha, color_palette, alpha_palette, hint, NULL, NULL, NULL); - fb_alloc_free_till_mark(); - return args[0]; -} -static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_image_obj, 3, py_image_draw_image); - static mp_obj_t py_image_draw_keypoints(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { image_t *arg_img = py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); @@ -1772,6 +1684,115 @@ static mp_obj_t py_image_flood_fill(uint n_args, const mp_obj_t *args, mp_map_t static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_flood_fill_obj, 2, py_image_flood_fill); #endif // IMLIB_ENABLE_FLOOD_FILL +static mp_obj_t py_image_line_op(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, + imlib_draw_row_callback_t callback) { + enum { + ARG_image, ARG_x, ARG_y, ARG_x_scale, ARG_y_scale, ARG_roi, + ARG_channel, ARG_alpha, ARG_color_palette, ARG_alpha_palette, ARG_hint, ARG_mask + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_image, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_x, MP_ARG_INT, {.u_int = 0 } }, + { MP_QSTR_y, MP_ARG_INT, {.u_int = 0 } }, + { MP_QSTR_x_scale, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_y_scale, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_roi, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_rgb_channel, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = -1 } }, + { MP_QSTR_alpha, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 256 } }, + { MP_QSTR_color_palette, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_alpha_palette, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_hint, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0 } }, + { MP_QSTR_mask, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} }, + }; + + // Parse args. + image_t *image = py_helper_arg_to_image(pos_args[0], ARG_IMAGE_MUTABLE); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + fb_alloc_mark(); + uint32_t data; + image_t temp = {.w = 1, .h = 1, .pixfmt = image->pixfmt, .data = (uint8_t *) &data}, *other = &temp; + + // Handle passing a scalar as an image. + if (mp_obj_is_integer(args[ARG_image].u_obj)) { + data = mp_obj_get_int(args[ARG_image].u_obj); + args[ARG_hint].u_int |= IMAGE_HINT_SCALE_ASPECT_IGNORE; + // Handle passing a rgb888 value as an image. + } else if (MP_OBJ_IS_TYPE(args[ARG_image].u_obj, &mp_type_tuple) || + MP_OBJ_IS_TYPE(args[ARG_image].u_obj, &mp_type_list)) { + mp_obj_t *rgb888; + mp_obj_get_array_fixed_n(args[ARG_image].u_obj, 3, &rgb888); + int r = IM_CLAMP(mp_obj_get_int(rgb888[0]), COLOR_R8_MIN, COLOR_R8_MAX); + int g = IM_CLAMP(mp_obj_get_int(rgb888[1]), COLOR_G8_MIN, COLOR_G8_MAX); + int b = IM_CLAMP(mp_obj_get_int(rgb888[2]), COLOR_B8_MIN, COLOR_B8_MAX); + switch (image->pixfmt) { + case PIXFORMAT_BINARY: { + data = COLOR_RGB888_TO_Y(r, g, b) > 127; + break; + } + case PIXFORMAT_GRAYSCALE: { + data = COLOR_RGB888_TO_Y(r, g, b); + break; + } + case PIXFORMAT_RGB565: { + data = COLOR_R8_G8_B8_TO_RGB565(r, g, b); + break; + } + default: { + break; + } + } + args[ARG_hint].u_int |= IMAGE_HINT_SCALE_ASPECT_IGNORE; + } else { + other = py_helper_arg_to_image(args[ARG_image].u_obj, ARG_IMAGE_ANY | ARG_IMAGE_ALLOC); + } + + rectangle_t roi = py_helper_arg_to_roi(args[ARG_roi].u_obj, other); + + if (args[ARG_channel].u_int < -1 || args[ARG_channel].u_int > 2) { + mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("RGB channel can be 0, 1, or 2")); + } + + if (args[ARG_alpha].u_int < 0 || args[ARG_alpha].u_int > 256) { + mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Alpha ranges between 0 and 256")); + } + + float x_scale = 1.0f; + float y_scale = 1.0f; + py_helper_arg_to_scale(args[ARG_x_scale].u_obj, args[ARG_y_scale].u_obj, &x_scale, &y_scale); + + const uint16_t *color_palette = py_helper_arg_to_palette(args[ARG_color_palette].u_obj, PIXFORMAT_RGB565); + const uint8_t *alpha_palette = py_helper_arg_to_palette(args[ARG_alpha_palette].u_obj, PIXFORMAT_GRAYSCALE); + + image_t *mask = NULL; + if (args[ARG_mask].u_obj != mp_const_none) { + mask = py_helper_arg_to_image(args[ARG_mask].u_obj, ARG_IMAGE_MUTABLE | ARG_IMAGE_ALLOC); + } + + if ((!callback) && mask) { + callback = imlib_mask_line_op; + } + + void *dst_row_override = NULL; + if (callback) { + dst_row_override = fb_alloc0(image_line_size(image), FB_ALLOC_CACHE_ALIGN); + // Necessary for alpha blending to work correctly. + args[ARG_hint].u_int |= IMAGE_HINT_BLACK_BACKGROUND; + } + + imlib_draw_image(image, other, args[ARG_x].u_int, args[ARG_y].u_int, x_scale, y_scale, &roi, + args[ARG_channel].u_int, args[ARG_alpha].u_int, color_palette, alpha_palette, + args[ARG_hint].u_int, callback, mask, dst_row_override); + + fb_alloc_free_till_mark(); + return pos_args[0]; +} + +static mp_obj_t py_image_draw_image(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return py_image_line_op(n_args, pos_args, kw_args, NULL); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_image_obj, 1, py_image_draw_image); #ifdef IMLIB_ENABLE_ISP_OPS ////////////// @@ -1957,149 +1978,35 @@ static mp_obj_t py_image_invert(mp_obj_t img_obj) { } static MP_DEFINE_CONST_FUN_OBJ_1(py_image_invert_obj, py_image_invert); -static mp_obj_t py_image_b_and(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = - py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); - image_t *arg_msk = - py_helper_keyword_to_image(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL); - - fb_alloc_mark(); - - if (MP_OBJ_IS_STR(args[1])) { - imlib_b_and(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); - } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { - imlib_b_and(arg_img, NULL, py_helper_arg_to_image(args[1], ARG_IMAGE_MUTABLE), 0, arg_msk); - } else { - imlib_b_and(arg_img, NULL, NULL, - py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), - arg_msk); - } - - fb_alloc_free_till_mark(); - - return args[0]; +static mp_obj_t py_image_b_and(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return py_image_line_op(n_args, pos_args, kw_args, imlib_b_and_line_op); } -static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_and_obj, 2, py_image_b_and); +static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_and_obj, 1, py_image_b_and); -static mp_obj_t py_image_b_nand(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = - py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); - image_t *arg_msk = - py_helper_keyword_to_image(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL); - - fb_alloc_mark(); - - if (MP_OBJ_IS_STR(args[1])) { - imlib_b_nand(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); - } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { - imlib_b_nand(arg_img, NULL, py_helper_arg_to_image(args[1], ARG_IMAGE_MUTABLE), 0, arg_msk); - } else { - imlib_b_nand(arg_img, NULL, NULL, - py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), - arg_msk); - } - - fb_alloc_free_till_mark(); - - return args[0]; +static mp_obj_t py_image_b_nand(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return py_image_line_op(n_args, pos_args, kw_args, imlib_b_nand_line_op); } -static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_nand_obj, 2, py_image_b_nand); +static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_nand_obj, 1, py_image_b_nand); -static mp_obj_t py_image_b_or(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = - py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); - image_t *arg_msk = - py_helper_keyword_to_image(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL); - - fb_alloc_mark(); - - if (MP_OBJ_IS_STR(args[1])) { - imlib_b_or(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); - } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { - imlib_b_or(arg_img, NULL, py_helper_arg_to_image(args[1], ARG_IMAGE_MUTABLE), 0, arg_msk); - } else { - imlib_b_or(arg_img, NULL, NULL, - py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), - arg_msk); - } - - fb_alloc_free_till_mark(); - - return args[0]; +static mp_obj_t py_image_b_or(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return py_image_line_op(n_args, pos_args, kw_args, imlib_b_or_line_op); } -static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_or_obj, 2, py_image_b_or); +static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_or_obj, 1, py_image_b_or); -static mp_obj_t py_image_b_nor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = - py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); - image_t *arg_msk = - py_helper_keyword_to_image(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL); - - fb_alloc_mark(); - - if (MP_OBJ_IS_STR(args[1])) { - imlib_b_nor(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); - } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { - imlib_b_nor(arg_img, NULL, py_helper_arg_to_image(args[1], ARG_IMAGE_MUTABLE), 0, arg_msk); - } else { - imlib_b_nor(arg_img, NULL, NULL, - py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), - arg_msk); - } - - fb_alloc_free_till_mark(); - - return args[0]; +static mp_obj_t py_image_b_nor(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return py_image_line_op(n_args, pos_args, kw_args, imlib_b_nor_line_op); } -static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_nor_obj, 2, py_image_b_nor); +static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_nor_obj, 1, py_image_b_nor); -static mp_obj_t py_image_b_xor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = - py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); - image_t *arg_msk = - py_helper_keyword_to_image(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL); - - fb_alloc_mark(); - - if (MP_OBJ_IS_STR(args[1])) { - imlib_b_xor(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); - } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { - imlib_b_xor(arg_img, NULL, py_helper_arg_to_image(args[1], ARG_IMAGE_MUTABLE), 0, arg_msk); - } else { - imlib_b_xor(arg_img, NULL, NULL, - py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), - arg_msk); - } - - fb_alloc_free_till_mark(); - - return args[0]; +static mp_obj_t py_image_b_xor(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return py_image_line_op(n_args, pos_args, kw_args, imlib_b_xor_line_op); } -static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_xor_obj, 2, py_image_b_xor); +static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_xor_obj, 1, py_image_b_xor); -static mp_obj_t py_image_b_xnor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = - py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); - image_t *arg_msk = - py_helper_keyword_to_image(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL); - - fb_alloc_mark(); - - if (MP_OBJ_IS_STR(args[1])) { - imlib_b_xnor(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); - } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { - imlib_b_xnor(arg_img, NULL, py_helper_arg_to_image(args[1], ARG_IMAGE_MUTABLE), 0, arg_msk); - } else { - imlib_b_xnor(arg_img, NULL, NULL, - py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), - arg_msk); - } - - fb_alloc_free_till_mark(); - - return args[0]; +static mp_obj_t py_image_b_xnor(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return py_image_line_op(n_args, pos_args, kw_args, imlib_b_xnor_line_op); } -static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_xnor_obj, 2, py_image_b_xnor); +static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_xnor_obj, 1, py_image_b_xnor); static mp_obj_t py_image_binary_morph_op(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, binary_morph_op_t op) { @@ -2152,202 +2059,36 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_close_obj, 2, py_image_close); // Math Methods /////////////// -static mp_obj_t py_image_replace(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = - py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); - bool arg_hmirror = - py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_hmirror), false); - bool arg_vflip = - py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_vflip), false); - bool arg_transpose = - py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_transpose), false); - image_t *arg_msk = - py_helper_keyword_to_image(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL); - - if (arg_transpose) { - size_t size0 = image_size(arg_img); - int w = arg_img->w; - int h = arg_img->h; - arg_img->w = h; - arg_img->h = w; - size_t size1 = image_size(arg_img); - arg_img->w = w; - arg_img->h = h; - PY_ASSERT_TRUE_MSG(size1 <= size0, - "Unable to transpose the image because it would grow in size!"); - } - - fb_alloc_mark(); - - mp_obj_t arg_1 = (n_args > 1) ? args[1] : args[0]; - - if (MP_OBJ_IS_STR(arg_1)) { - imlib_replace(arg_img, mp_obj_str_get_str(arg_1), NULL, 0, - arg_hmirror, arg_vflip, arg_transpose, arg_msk); - } else if (MP_OBJ_IS_TYPE(arg_1, &py_image_type)) { - imlib_replace(arg_img, NULL, py_helper_arg_to_image(arg_1, ARG_IMAGE_MUTABLE), 0, - arg_hmirror, arg_vflip, arg_transpose, arg_msk); - } else { - imlib_replace(arg_img, NULL, NULL, - py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), - arg_hmirror, arg_vflip, arg_transpose, arg_msk); - } - - fb_alloc_free_till_mark(); - py_helper_update_framebuffer(arg_img); - return args[0]; +static mp_obj_t py_image_add(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return py_image_line_op(n_args, pos_args, kw_args, imlib_add_line_op); } -static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_replace_obj, 1, py_image_replace); +static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_add_obj, 1, py_image_add); -static mp_obj_t py_image_add(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = - py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); - image_t *arg_msk = - py_helper_keyword_to_image(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL); - - fb_alloc_mark(); - - if (MP_OBJ_IS_STR(args[1])) { - imlib_add(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); - } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { - imlib_add(arg_img, NULL, py_helper_arg_to_image(args[1], ARG_IMAGE_MUTABLE), 0, arg_msk); - } else { - imlib_add(arg_img, NULL, NULL, - py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), - arg_msk); - } - - fb_alloc_free_till_mark(); - - return args[0]; +static mp_obj_t py_image_sub(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return py_image_line_op(n_args, pos_args, kw_args, imlib_sub_line_op); } -static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_add_obj, 2, py_image_add); +static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_sub_obj, 1, py_image_sub); -static mp_obj_t py_image_sub(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = - py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); - bool arg_reverse = - py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_reverse), false); - image_t *arg_msk = - py_helper_keyword_to_image(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL); - - fb_alloc_mark(); - - if (MP_OBJ_IS_STR(args[1])) { - imlib_sub(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_reverse, arg_msk); - } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { - imlib_sub(arg_img, NULL, py_helper_arg_to_image(args[1], ARG_IMAGE_MUTABLE), 0, arg_reverse, arg_msk); - } else { - imlib_sub(arg_img, NULL, NULL, - py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), - arg_reverse, arg_msk); - } - - fb_alloc_free_till_mark(); - - return args[0]; +static mp_obj_t py_image_rsub(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return py_image_line_op(n_args, pos_args, kw_args, imlib_rsub_line_op); } -static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_sub_obj, 2, py_image_sub); +static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_rsub_obj, 1, py_image_rsub); -static mp_obj_t py_image_min(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = - py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); - image_t *arg_msk = - py_helper_keyword_to_image(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL); - - fb_alloc_mark(); - - if (MP_OBJ_IS_STR(args[1])) { - imlib_min(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); - } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { - imlib_min(arg_img, NULL, py_helper_arg_to_image(args[1], ARG_IMAGE_MUTABLE), 0, arg_msk); - } else { - imlib_min(arg_img, NULL, NULL, - py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), - arg_msk); - } - - fb_alloc_free_till_mark(); - - return args[0]; +static mp_obj_t py_image_min(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return py_image_line_op(n_args, pos_args, kw_args, imlib_min_line_op); } -static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_min_obj, 2, py_image_min); +static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_min_obj, 1, py_image_min); -static mp_obj_t py_image_max(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = - py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); - image_t *arg_msk = - py_helper_keyword_to_image(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL); - - fb_alloc_mark(); - - if (MP_OBJ_IS_STR(args[1])) { - imlib_max(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); - } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { - imlib_max(arg_img, NULL, py_helper_arg_to_image(args[1], ARG_IMAGE_MUTABLE), 0, arg_msk); - } else { - imlib_max(arg_img, NULL, NULL, - py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), - arg_msk); - } - - fb_alloc_free_till_mark(); - - return args[0]; +static mp_obj_t py_image_max(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return py_image_line_op(n_args, pos_args, kw_args, imlib_max_line_op); } -static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_max_obj, 2, py_image_max); +static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_max_obj, 1, py_image_max); -static mp_obj_t py_image_difference(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = - py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); - image_t *arg_msk = - py_helper_keyword_to_image(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL); - - fb_alloc_mark(); - - if (MP_OBJ_IS_STR(args[1])) { - imlib_difference(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); - } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { - imlib_difference(arg_img, NULL, py_helper_arg_to_image(args[1], ARG_IMAGE_MUTABLE), 0, arg_msk); - } else { - imlib_difference(arg_img, NULL, NULL, - py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), - arg_msk); - } - - fb_alloc_free_till_mark(); - - return args[0]; +static mp_obj_t py_image_difference(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return py_image_line_op(n_args, pos_args, kw_args, imlib_difference_line_op); } -static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_difference_obj, 2, py_image_difference); - -static mp_obj_t py_image_blend(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = - py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); - float arg_alpha = - py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_alpha), 128) / 256.0f; - PY_ASSERT_TRUE_MSG((0 <= arg_alpha) && (arg_alpha <= 1), "Error: 0 <= alpha <= 256!"); - image_t *arg_msk = - py_helper_keyword_to_image(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL); - - fb_alloc_mark(); - - if (MP_OBJ_IS_STR(args[1])) { - imlib_blend(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_alpha, arg_msk); - } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { - imlib_blend(arg_img, NULL, py_helper_arg_to_image(args[1], ARG_IMAGE_MUTABLE), 0, arg_alpha, arg_msk); - } else { - imlib_blend(arg_img, NULL, NULL, - py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), - arg_alpha, arg_msk); - } - - fb_alloc_free_till_mark(); - - return args[0]; -} -static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_blend_obj, 2, py_image_blend); -#endif//IMLIB_ENABLE_MATH_OPS +static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_difference_obj, 1, py_image_difference); +#endif // IMLIB_ENABLE_MATH_OPS #if defined(IMLIB_ENABLE_MATH_OPS) && defined(IMLIB_ENABLE_BINARY_OPS) static mp_obj_t py_image_top_hat(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -6623,18 +6364,19 @@ static const mp_rom_map_elem_t locals_dict_table[] = { {MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&py_func_unavailable_obj)}, {MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&py_func_unavailable_obj)}, #endif - #ifdef IMLIB_ENABLE_MATH_OPS /* Math Methods */ + #ifdef IMLIB_ENABLE_MATH_OPS {MP_ROM_QSTR(MP_QSTR_negate), MP_ROM_PTR(&py_image_invert_obj)}, - {MP_ROM_QSTR(MP_QSTR_assign), MP_ROM_PTR(&py_image_replace_obj)}, - {MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&py_image_replace_obj)}, - {MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&py_image_replace_obj)}, + {MP_ROM_QSTR(MP_QSTR_assign), MP_ROM_PTR(&py_image_draw_image_obj)}, + {MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&py_image_draw_image_obj)}, + {MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&py_image_draw_image_obj)}, {MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&py_image_add_obj)}, {MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&py_image_sub_obj)}, + {MP_ROM_QSTR(MP_QSTR_rsub), MP_ROM_PTR(&py_image_rsub_obj)}, {MP_ROM_QSTR(MP_QSTR_min), MP_ROM_PTR(&py_image_min_obj)}, {MP_ROM_QSTR(MP_QSTR_max), MP_ROM_PTR(&py_image_max_obj)}, {MP_ROM_QSTR(MP_QSTR_difference), MP_ROM_PTR(&py_image_difference_obj)}, - {MP_ROM_QSTR(MP_QSTR_blend), MP_ROM_PTR(&py_image_blend_obj)}, + {MP_ROM_QSTR(MP_QSTR_blend), MP_ROM_PTR(&py_image_draw_image_obj)}, #else {MP_ROM_QSTR(MP_QSTR_negate), MP_ROM_PTR(&py_func_unavailable_obj)}, {MP_ROM_QSTR(MP_QSTR_assign), MP_ROM_PTR(&py_func_unavailable_obj)}, @@ -6653,7 +6395,7 @@ static const mp_rom_map_elem_t locals_dict_table[] = { #else {MP_ROM_QSTR(MP_QSTR_top_hat), MP_ROM_PTR(&py_func_unavailable_obj)}, {MP_ROM_QSTR(MP_QSTR_black_hat), MP_ROM_PTR(&py_func_unavailable_obj)}, - #endif //defined(IMLIB_ENABLE_MATH_OPS) && defined (IMLIB_ENABLE_BINARY_OPS) + #endif // defined(IMLIB_ENABLE_MATH_OPS) && defined (IMLIB_ENABLE_BINARY_OPS) /* Filtering Methods */ {MP_ROM_QSTR(MP_QSTR_histeq), MP_ROM_PTR(&py_image_histeq_obj)}, #ifdef IMLIB_ENABLE_MEAN