static mp_obj_t py_image_draw_circle(mp_obj_t image_obj, mp_obj_t c_obj, mp_obj_t r_obj) { int cx, cy, r; mp_obj_t *array; struct image *image; color_t c = {.r=0xFF, .g=0xFF, .b=0xFF}; /* get image pointer */ image = py_image_cobj(image_obj); /* center */ mp_obj_get_array_fixed_n(c_obj, 2, &array); cx = mp_obj_get_int(array[0]); cy = mp_obj_get_int(array[1]); /* radius */ r = mp_obj_get_int(r_obj); imlib_draw_circle(image, cx, cy, r, &c); return mp_const_none; } static mp_obj_t py_image_draw_string(uint n_args, const mp_obj_t *args) { int x = mp_obj_get_int(args[1]); int y = mp_obj_get_int(args[2]); image_t *image =py_image_cobj(args[0]); const char *str = mp_obj_str_get_str(args[3]); color_t c = {.r=0xFF, .g=0xFF, .b=0xFF}; // check x, y PY_ASSERT_TRUE_MSG(x>=0 && x<image->w, "Image index out of range"); PY_ASSERT_TRUE_MSG(y>=0 && y<image->h, "Image index out of range"); PY_ASSERT_TRUE_MSG(image->bpp <= 2, "This function is not supported on JPEG images"); if (n_args == 5) { // get color mp_obj_t *array; mp_obj_get_array_fixed_n(args[4], 3, &array); c.r = mp_obj_get_int(array[0]); c.g = mp_obj_get_int(array[1]); c.b = mp_obj_get_int(array[2]); } imlib_draw_string(image, x, y, str, &c); return mp_const_none; } static mp_obj_t py_image_erode(mp_obj_t image_obj, mp_obj_t ksize_obj) { image_t *image = NULL; image = py_image_cobj(image_obj); /* sanity checks */ PY_ASSERT_TRUE_MSG(image->bpp == 1, "This function is only supported on GRAYSCALE images"); imlib_erode(image, mp_obj_get_int(ksize_obj)); return mp_const_none; }
void imlib_edge_simple(image_t *src, rectangle_t *roi, int low_thresh, int high_thresh) { imlib_morph(src, 1, kernel_high_pass_3, 1.0f, 0.0f, false, 0, false, NULL); list_t thresholds; list_init(&thresholds, sizeof(color_thresholds_list_lnk_data_t)); color_thresholds_list_lnk_data_t lnk_data; lnk_data.LMin=low_thresh; lnk_data.LMax=high_thresh; list_push_back(&thresholds, &lnk_data); imlib_binary(src, src, &thresholds, false, false, NULL); list_free(&thresholds); imlib_erode(src, 1, 2, NULL); }
static mp_obj_t py_image_threshold(mp_obj_t image_obj, mp_obj_t color_list_obj, mp_obj_t threshold) { color_t *color; image_t *image; /* sanity checks */ PY_ASSERT_TRUE(sensor.pixformat == PIXFORMAT_RGB565); PY_ASSERT_TRUE(sensor.framesize <= FRAMESIZE_QCIF); /* read arguments */ image = py_image_cobj(image_obj); int thresh = mp_obj_get_int(threshold); /* returned image */ image_t bimage = { .w=image->w, .h=image->h, .bpp=1, .pixels=image->data+(image->w*image->h*image->bpp) }; /* copy color list */ uint len; mp_obj_t *color_arr; mp_obj_get_array(color_list_obj, &len, &color_arr); color = xalloc(len*sizeof*color); for (int i=0; i<len; i++) { mp_obj_t *color_obj; mp_obj_get_array_fixed_n(color_arr[i], 3, &color_obj); color[i].r = mp_obj_get_int(color_obj[0]); color[i].g = mp_obj_get_int(color_obj[1]); color[i].b = mp_obj_get_int(color_obj[2]); } /* Threshold image using reference color */ imlib_threshold(image, &bimage, color, len, thresh); return py_image_from_struct(&bimage); } static mp_obj_t py_image_rainbow(mp_obj_t src_image_obj) { image_t *src_image = NULL; /* get C image pointer */ src_image = py_image_cobj(src_image_obj); /* sanity checks */ PY_ASSERT_TRUE(src_image->bpp==1); image_t dst_image = { .w=src_image->w, .h=src_image->h, .bpp=2, .pixels=xalloc(src_image->w*src_image->h*2) }; imlib_rainbow(src_image, &dst_image); *src_image = dst_image; return src_image_obj; } static mp_obj_t py_image_compress(mp_obj_t image_obj, mp_obj_t quality) { image_t *image = py_image_cobj(image_obj); image_t cimage = { .w=image->w, .h=image->h, .bpp=0, .pixels= NULL }; jpeg_compress(image, &cimage, mp_obj_get_int(quality)); return py_image_from_struct(&cimage); } static mp_obj_t py_image_draw_line(mp_obj_t image_obj, mp_obj_t line_obj) { /* get image pointer */ struct image *image; image = py_image_cobj(image_obj); mp_obj_t *array; mp_obj_get_array_fixed_n(line_obj, 4, &array); int x0 = mp_obj_get_int(array[0]); int y0 = mp_obj_get_int(array[1]); int x1 = mp_obj_get_int(array[2]); int y1 = mp_obj_get_int(array[3]); imlib_draw_line(image, x0, y0, x1, y1); return mp_const_none; } static mp_obj_t py_image_draw_circle(mp_obj_t image_obj, mp_obj_t c_obj, mp_obj_t r_obj) { int cx, cy, r; mp_obj_t *array; struct image *image; color_t c = {.r=0xFF, .g=0xFF, .b=0xFF}; /* get image pointer */ image = py_image_cobj(image_obj); /* center */ mp_obj_get_array_fixed_n(c_obj, 2, &array); cx = mp_obj_get_int(array[0]); cy = mp_obj_get_int(array[1]); /* radius */ r = mp_obj_get_int(r_obj); imlib_draw_circle(image, cx, cy, r, &c); return mp_const_none; } static mp_obj_t py_image_draw_string(uint n_args, const mp_obj_t *args) { int x = mp_obj_get_int(args[1]); int y = mp_obj_get_int(args[2]); image_t *image =py_image_cobj(args[0]); const char *str = mp_obj_str_get_str(args[3]); color_t c = {.r=0xFF, .g=0xFF, .b=0xFF}; if (n_args == 5) { // get color mp_obj_t *array; mp_obj_get_array_fixed_n(args[4], 3, &array); c.r = mp_obj_get_int(array[0]); c.g = mp_obj_get_int(array[1]); c.b = mp_obj_get_int(array[2]); } imlib_draw_string(image, x, y, str, &c); return mp_const_none; } static mp_obj_t py_image_erode(mp_obj_t image_obj, mp_obj_t ksize_obj) { image_t *image = NULL; image = py_image_cobj(image_obj); /* sanity checks */ PY_ASSERT_TRUE(image->bpp==1); imlib_erode(image, mp_obj_get_int(ksize_obj)); return mp_const_none; }
void imlib_remove_shadows(image_t *img, const char *path, image_t *other, int scalar, bool single) { if (!single) { imlib_remove_shadows_line_op_state_t state; for (int i = 0; i < imlib_remove_shadows_kernel_size; i++) { state.img_lines[i] = fb_alloc(img->w * sizeof(uint16_t)); state.other_lines[i] = fb_alloc(img->w * sizeof(uint16_t)); state.out_lines[i] = fb_alloc(img->w * sizeof(uint16_t)); } state.lines_processed = 0; imlib_image_operation(img, path, other, scalar, imlib_remove_shadows_line_op, &state); for (int i = 0; i < imlib_remove_shadows_kernel_size; i++) { fb_free(); fb_free(); fb_free(); } } else { // Create Shadow Mask image_t temp_image; temp_image.w = img->w; temp_image.h = img->h; temp_image.bpp = img->bpp; temp_image.data = fb_alloc(image_size(img)); memcpy(temp_image.data, img->data, image_size(img)); rectangle_t r; r.x = 0; r.y = 0; r.w = temp_image.w; r.h = temp_image.h; histogram_t h; h.LBinCount = COLOR_L_MAX - COLOR_L_MIN + 1; h.ABinCount = COLOR_A_MAX - COLOR_A_MIN + 1; h.BBinCount = COLOR_B_MAX - COLOR_B_MIN + 1; h.LBins = fb_alloc(h.LBinCount * sizeof(float)); h.ABins = fb_alloc(h.ABinCount * sizeof(float)); h.BBins = fb_alloc(h.BBinCount * sizeof(float)); imlib_get_histogram(&h, &temp_image, &r, NULL, false); statistics_t s; imlib_get_statistics(&s, temp_image.bpp, &h); int sum = 0; int mean = s.LMean * 0.8f; for (int y = 0, yy = temp_image.h; y < yy; y++) { uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&temp_image, y); for (int x = 0, xx = temp_image.w; x < xx; x++) { sum += COLOR_RGB565_TO_L(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)) < mean; } } if (sum > ((temp_image.w * temp_image.h) / 20)) { // Don't do anything if the image is mostly flat. threshold_t t; imlib_get_threshold(&t, temp_image.bpp, &h); list_t thresholds; list_init(&thresholds, sizeof(color_thresholds_list_lnk_data_t)); color_thresholds_list_lnk_data_t lnk_data; lnk_data.LMin = COLOR_L_MIN; lnk_data.AMin = COLOR_A_MIN; lnk_data.BMin = COLOR_B_MIN; lnk_data.LMax = t.LValue; lnk_data.AMax = COLOR_A_MAX; lnk_data.BMax = COLOR_B_MAX; list_push_back(&thresholds, &lnk_data); imlib_binary(&temp_image, &temp_image, &thresholds, false, false, NULL); list_free(&thresholds); imlib_erode(&temp_image, 3, 30, NULL); imlib_dilate(&temp_image, 1, 1, NULL); // Get Shadow Average image_t temp_image_2; temp_image_2.w = temp_image.w; temp_image_2.h = temp_image.h; temp_image_2.bpp = temp_image.bpp; temp_image_2.data = fb_alloc(image_size(&temp_image)); memcpy(temp_image_2.data, temp_image.data, image_size(&temp_image)); imlib_erode(&temp_image_2, 3, 48, NULL); int shadow_r_sum = 0; int shadow_g_sum = 0; int shadow_b_sum = 0; int shadow_count = 0; for (int y = 0, yy = temp_image_2.h; y < yy; y++) { uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&temp_image_2, y); uint16_t *row_ptr_2 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); for (int x = 0, xx = temp_image_2.w; x < xx; x++) { if (IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)) { int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr_2, x); int r = COLOR_RGB565_TO_R8(pixel); int g = COLOR_RGB565_TO_G8(pixel); int b = COLOR_RGB565_TO_R8(pixel); shadow_r_sum += r; shadow_g_sum += g; shadow_b_sum += b; shadow_count += 1; } } } memcpy(temp_image_2.data, temp_image.data, image_size(&temp_image)); imlib_invert(&temp_image_2); imlib_erode(&temp_image_2, 5, 120, NULL); imlib_invert(&temp_image_2); imlib_b_xor(&temp_image_2, NULL, &temp_image, 0, NULL); imlib_erode(&temp_image_2, 2, 24, NULL); int not_shadow_r_sum = 0; int not_shadow_g_sum = 0; int not_shadow_b_sum = 0; int not_shadow_count = 0; for (int y = 0, yy = temp_image_2.h; y < yy; y++) { uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&temp_image_2, y); uint16_t *row_ptr_2 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); for (int x = 0, xx = temp_image_2.w; x < xx; x++) { if (IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)) { int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr_2, x); int r = COLOR_RGB565_TO_R8(pixel); int g = COLOR_RGB565_TO_G8(pixel); int b = COLOR_RGB565_TO_R8(pixel); not_shadow_r_sum += r; not_shadow_g_sum += g; not_shadow_b_sum += b; not_shadow_count += 1; } } } // Fill in the umbra... (inner part of the shadow)... memcpy(temp_image_2.data, temp_image.data, image_size(&temp_image)); imlib_mean_filter(&temp_image, 2, false, 0, false, NULL); if (shadow_count && not_shadow_count) { float shadow_r_average = ((float) shadow_r_sum) / ((float) shadow_count); float shadow_g_average = ((float) shadow_g_sum) / ((float) shadow_count); float shadow_b_average = ((float) shadow_b_sum) / ((float) shadow_count); float not_shadow_r_average = ((float) not_shadow_r_sum) / ((float) not_shadow_count); float not_shadow_g_average = ((float) not_shadow_g_sum) / ((float) not_shadow_count); float not_shadow_b_average = ((float) not_shadow_b_sum) / ((float) not_shadow_count); float diff_r = not_shadow_r_average - shadow_r_average; float diff_g = not_shadow_g_average - shadow_g_average; float diff_b = not_shadow_b_average - shadow_b_average; for (int y = 0; y < img->h; y++) { uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&temp_image, y); uint16_t *row_ptr_2 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); for (int x = 0; x < img->w; x++) { float alpha = ((float) (COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)) - COLOR_Y_MIN)) / ((float) (COLOR_Y_MAX - COLOR_Y_MIN)); int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr_2, x); int r = COLOR_RGB565_TO_R8(pixel); int g = COLOR_RGB565_TO_G8(pixel); int b = COLOR_RGB565_TO_B8(pixel); int r_new = IM_MIN(IM_MAX(r + (diff_r * alpha), COLOR_R8_MIN), COLOR_R8_MAX); int g_new = IM_MIN(IM_MAX(g + (diff_g * alpha), COLOR_G8_MIN), COLOR_G8_MAX); int b_new = IM_MIN(IM_MAX(b + (diff_b * alpha), COLOR_B8_MIN), COLOR_B8_MAX); IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr_2, x, COLOR_R8_G8_B8_TO_RGB565(r_new, g_new, b_new)); } } } // Fill in the penumbra... (outer part of the shadow)... memcpy(temp_image.data, temp_image_2.data, image_size(&temp_image_2)); imlib_erode(&temp_image_2, 1, 8, NULL); imlib_b_xor(&temp_image, NULL, &temp_image_2, 0, NULL); imlib_dilate(&temp_image, 3, 0, NULL); imlib_median_filter(img, 2, 12, false, 0, false, &temp_image); fb_free(); // temp_image_2 } fb_free(); // BBins fb_free(); // ABins fb_free(); // LBins fb_free(); // temp_image } }