static mp_obj_t py_image_dilate(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_dilate(image, mp_obj_get_int(ksize_obj)); return mp_const_none; }
static mp_obj_t py_image_dilate(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_dilate(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 } }