Add flood fill

The algorithm itself is setup to be used for future filters.
This commit is contained in:
Kwabena W. Agyeman 2018-04-06 00:19:36 -04:00
parent 82ff7a250e
commit 7f798a8282
7 changed files with 581 additions and 23 deletions

View File

@ -605,3 +605,341 @@ void imlib_find_blobs(list_t *out, image_t *ptr, rectangle_t *roi, unsigned int
}
}
}
void imlib_flood_fill_int(image_t *out, image_t *img, int x, int y,
int seed_threshold, int floating_threshold,
flood_fill_call_back_t cb, void *data)
{
lifo_t lifo;
size_t lifo_len;
lifo_alloc_all(&lifo, &lifo_len, sizeof(xylf_t));
switch(img->bpp) {
case IMAGE_BPP_BINARY: {
for(int seed_pixel = IMAGE_GET_BINARY_PIXEL(img, x, y);;) {
int left = x, right = x;
uint32_t *row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y);
uint32_t *out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y);
while ((left > 0)
&& (!IMAGE_GET_BINARY_PIXEL_FAST(out_row, left - 1))
&& COLOR_BOUND_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, left - 1), seed_pixel, seed_threshold)
&& COLOR_BOUND_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, left - 1),
IMAGE_GET_BINARY_PIXEL_FAST(row, left), floating_threshold)) {
left--;
}
while ((right < (img->w - 1))
&& (!IMAGE_GET_BINARY_PIXEL_FAST(out_row, right + 1))
&& COLOR_BOUND_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, right + 1), seed_pixel, seed_threshold)
&& COLOR_BOUND_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, right + 1),
IMAGE_GET_BINARY_PIXEL_FAST(row, right), floating_threshold)) {
right++;
}
for (int i = left; i <= right; i++) {
IMAGE_SET_BINARY_PIXEL_FAST(out_row, i);
}
bool break_out = false;
for(;;) {
if (lifo_size(&lifo) < lifo_len) {
uint32_t *old_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y);
if (y > 0) {
row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y - 1);
out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y - 1);
bool recurse = false;
for (int i = left; i <= right; i++) {
if ((!IMAGE_GET_BINARY_PIXEL_FAST(out_row, i))
&& COLOR_BOUND_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, i), seed_pixel, seed_threshold)
&& COLOR_BOUND_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, i),
IMAGE_GET_BINARY_PIXEL_FAST(old_row, i), floating_threshold)) {
xylf_t context;
context.x = x;
context.y = y;
context.l = left;
context.r = right;
lifo_enqueue(&lifo, &context);
x = i;
y = y - 1;
recurse = true;
break;
}
}
if (recurse) {
break;
}
}
if (y < (img->h - 1)) {
row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y + 1);
out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y + 1);
bool recurse = false;
for (int i = left; i <= right; i++) {
if ((!IMAGE_GET_BINARY_PIXEL_FAST(out_row, i))
&& COLOR_BOUND_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, i), seed_pixel, seed_threshold)
&& COLOR_BOUND_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, i),
IMAGE_GET_BINARY_PIXEL_FAST(old_row, i), floating_threshold)) {
xylf_t context;
context.x = x;
context.y = y;
context.l = left;
context.r = right;
lifo_enqueue(&lifo, &context);
x = i;
y = y + 1;
recurse = true;
break;
}
}
if (recurse) {
break;
}
}
}
if (cb) cb(img, y, left, right, data);
if (!lifo_size(&lifo)) {
break_out = true;
break;
}
xylf_t context;
lifo_dequeue(&lifo, &context);
x = context.x;
y = context.y;
left = context.l;
right = context.r;
}
if (break_out) {
break;
}
}
break;
}
case IMAGE_BPP_GRAYSCALE: {
for(int seed_pixel = IMAGE_GET_GRAYSCALE_PIXEL(img, x, y);;) {
int left = x, right = x;
uint8_t *row = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y);
uint32_t *out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y);
while ((left > 0)
&& (!IMAGE_GET_BINARY_PIXEL_FAST(out_row, left - 1))
&& COLOR_BOUND_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, left - 1), seed_pixel, seed_threshold)
&& COLOR_BOUND_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, left - 1),
IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, left), floating_threshold)) {
left--;
}
while ((right < (img->w - 1))
&& (!IMAGE_GET_BINARY_PIXEL_FAST(out_row, right + 1))
&& COLOR_BOUND_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, right + 1), seed_pixel, seed_threshold)
&& COLOR_BOUND_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, right + 1),
IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, right), floating_threshold)) {
right++;
}
for (int i = left; i <= right; i++) {
IMAGE_SET_BINARY_PIXEL_FAST(out_row, i);
}
bool break_out = false;
for(;;) {
if (lifo_size(&lifo) < lifo_len) {
uint8_t *old_row = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y);
if (y > 0) {
row = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y - 1);
out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y - 1);
bool recurse = false;
for (int i = left; i <= right; i++) {
if ((!IMAGE_GET_BINARY_PIXEL_FAST(out_row, i))
&& COLOR_BOUND_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, i), seed_pixel, seed_threshold)
&& COLOR_BOUND_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, i),
IMAGE_GET_GRAYSCALE_PIXEL_FAST(old_row, i), floating_threshold)) {
xylf_t context;
context.x = x;
context.y = y;
context.l = left;
context.r = right;
lifo_enqueue(&lifo, &context);
x = i;
y = y - 1;
recurse = true;
break;
}
}
if (recurse) {
break;
}
}
if (y < (img->h - 1)) {
row = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y + 1);
out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y + 1);
bool recurse = false;
for (int i = left; i <= right; i++) {
if ((!IMAGE_GET_BINARY_PIXEL_FAST(out_row, i))
&& COLOR_BOUND_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, i), seed_pixel, seed_threshold)
&& COLOR_BOUND_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, i),
IMAGE_GET_GRAYSCALE_PIXEL_FAST(old_row, i), floating_threshold)) {
xylf_t context;
context.x = x;
context.y = y;
context.l = left;
context.r = right;
lifo_enqueue(&lifo, &context);
x = i;
y = y + 1;
recurse = true;
break;
}
}
if (recurse) {
break;
}
}
}
if (cb) cb(img, y, left, right, data);
if (!lifo_size(&lifo)) {
break_out = true;
break;
}
xylf_t context;
lifo_dequeue(&lifo, &context);
x = context.x;
y = context.y;
left = context.l;
right = context.r;
}
if (break_out) {
break;
}
}
break;
}
case IMAGE_BPP_RGB565: {
for(int seed_pixel = IMAGE_GET_RGB565_PIXEL(img, x, y);;) {
int left = x, right = x;
uint16_t *row = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);
uint32_t *out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y);
while ((left > 0)
&& (!IMAGE_GET_BINARY_PIXEL_FAST(out_row, left - 1))
&& COLOR_BOUND_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, left - 1), seed_pixel, seed_threshold)
&& COLOR_BOUND_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, left - 1),
IMAGE_GET_RGB565_PIXEL_FAST(row, left), floating_threshold)) {
left--;
}
while ((right < (img->w - 1))
&& (!IMAGE_GET_BINARY_PIXEL_FAST(out_row, right + 1))
&& COLOR_BOUND_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, right + 1), seed_pixel, seed_threshold)
&& COLOR_BOUND_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, right + 1),
IMAGE_GET_RGB565_PIXEL_FAST(row, right), floating_threshold)) {
right++;
}
for (int i = left; i <= right; i++) {
IMAGE_SET_BINARY_PIXEL_FAST(out_row, i);
}
bool break_out = false;
for(;;) {
if (lifo_size(&lifo) < lifo_len) {
uint16_t *old_row = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);
if (y > 0) {
row = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y - 1);
out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y - 1);
bool recurse = false;
for (int i = left; i <= right; i++) {
if ((!IMAGE_GET_BINARY_PIXEL_FAST(out_row, i))
&& COLOR_BOUND_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, i), seed_pixel, seed_threshold)
&& COLOR_BOUND_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, i),
IMAGE_GET_RGB565_PIXEL_FAST(old_row, i), floating_threshold)) {
xylf_t context;
context.x = x;
context.y = y;
context.l = left;
context.r = right;
lifo_enqueue(&lifo, &context);
x = i;
y = y - 1;
recurse = true;
break;
}
}
if (recurse) {
break;
}
}
if (y < (img->h - 1)) {
row = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y + 1);
out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y + 1);
bool recurse = false;
for (int i = left; i <= right; i++) {
if ((!IMAGE_GET_BINARY_PIXEL_FAST(out_row, i))
&& COLOR_BOUND_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, i), seed_pixel, seed_threshold)
&& COLOR_BOUND_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, i),
IMAGE_GET_RGB565_PIXEL_FAST(old_row, i), floating_threshold)) {
xylf_t context;
context.x = x;
context.y = y;
context.l = left;
context.r = right;
lifo_enqueue(&lifo, &context);
x = i;
y = y + 1;
recurse = true;
break;
}
}
if (recurse) {
break;
}
}
}
if (cb) cb(img, y, left, right, data);
if (!lifo_size(&lifo)) {
break_out = true;
break;
}
xylf_t context;
lifo_dequeue(&lifo, &context);
x = context.x;
y = context.y;
left = context.l;
right = context.r;
}
if (break_out) {
break;
}
}
break;
}
default: {
break;
}
}
lifo_free(&lifo);
}

View File

@ -209,3 +209,105 @@ void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int
x_off += (g->w * scale) + x_spacing;
}
}
void imlib_flood_fill(image_t *img, int x, int y,
float seed_threshold, float floating_threshold,
int c, bool invert, bool clear_background, image_t *mask)
{
if ((0 <= x) && (x < img->w) && (0 <= y) && (y < img->h)) {
image_t out;
out.w = img->w;
out.h = img->h;
out.bpp = IMAGE_BPP_BINARY;
out.data = fb_alloc0(image_size(&out));
if (mask) {
for (int y = 0, yy = out.h; y < yy; y++) {
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
if (image_get_mask_pixel(mask, x, y)) IMAGE_SET_BINARY_PIXEL_FAST(row_ptr, x);
}
}
}
int color_seed_threshold = 0;
int color_floating_threshold = 0;
switch(img->bpp) {
case IMAGE_BPP_BINARY: {
color_seed_threshold = fast_roundf(seed_threshold * COLOR_BINARY_MAX);
color_floating_threshold = fast_roundf(floating_threshold * COLOR_BINARY_MAX);
break;
}
case IMAGE_BPP_GRAYSCALE: {
color_seed_threshold = fast_roundf(seed_threshold * COLOR_GRAYSCALE_MAX);
color_floating_threshold = fast_roundf(floating_threshold * COLOR_GRAYSCALE_MAX);
break;
}
case IMAGE_BPP_RGB565: {
color_seed_threshold = COLOR_R5_G6_B5_TO_RGB565(fast_roundf(seed_threshold * COLOR_R5_MAX),
fast_roundf(seed_threshold * COLOR_G6_MAX),
fast_roundf(seed_threshold * COLOR_B5_MAX));
color_floating_threshold = COLOR_R5_G6_B5_TO_RGB565(fast_roundf(floating_threshold * COLOR_R5_MAX),
fast_roundf(floating_threshold * COLOR_G6_MAX),
fast_roundf(floating_threshold * COLOR_B5_MAX));
break;
}
default: {
break;
}
}
imlib_flood_fill_int(&out, img, x, y, color_seed_threshold, color_floating_threshold, NULL, NULL);
switch(img->bpp) {
case IMAGE_BPP_BINARY: {
for (int y = 0, yy = out.h; y < yy; y++) {
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y);
uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
if (IMAGE_GET_BINARY_PIXEL_FAST(out_row_ptr, x) ^ invert) {
IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr, x, c);
} else if (clear_background) {
IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr, x, 0);
}
}
}
break;
}
case IMAGE_BPP_GRAYSCALE: {
for (int y = 0, yy = out.h; y < yy; y++) {
uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y);
uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
if (IMAGE_GET_BINARY_PIXEL_FAST(out_row_ptr, x) ^ invert) {
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr, x, c);
} else if (clear_background) {
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr, x, 0);
}
}
}
break;
}
case IMAGE_BPP_RGB565: {
for (int y = 0, yy = out.h; y < yy; y++) {
uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);
uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
if (IMAGE_GET_BINARY_PIXEL_FAST(out_row_ptr, x) ^ invert) {
IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, c);
} else if (clear_background) {
IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, 0);
}
}
}
break;
}
default: {
break;
}
}
fb_free();
}
}

View File

@ -194,20 +194,24 @@ size_t image_size(image_t *ptr)
bool image_get_mask_pixel(image_t *ptr, int x, int y)
{
switch (ptr->bpp) {
case IMAGE_BPP_BINARY: {
return IMAGE_GET_BINARY_PIXEL(ptr, x, y);
}
case IMAGE_BPP_GRAYSCALE: {
return COLOR_GRAYSCALE_TO_BINARY(IMAGE_GET_GRAYSCALE_PIXEL(ptr, x, y));
}
case IMAGE_BPP_RGB565: {
return COLOR_RGB565_TO_BINARY(IMAGE_GET_RGB565_PIXEL(ptr, x, y));
}
default: {
return false;
if ((0 <= x) && (x < ptr->w) && (0 <= y) && (y < ptr->h)) {
switch (ptr->bpp) {
case IMAGE_BPP_BINARY: {
return IMAGE_GET_BINARY_PIXEL(ptr, x, y);
}
case IMAGE_BPP_GRAYSCALE: {
return COLOR_GRAYSCALE_TO_BINARY(IMAGE_GET_GRAYSCALE_PIXEL(ptr, x, y));
}
case IMAGE_BPP_RGB565: {
return COLOR_RGB565_TO_BINARY(IMAGE_GET_RGB565_PIXEL(ptr, x, y));
}
default: {
return false;
}
}
}
return false;
}
// Gamma uncompress

View File

@ -151,7 +151,35 @@ color_thresholds_list_lnk_data_t;
uint8_t _l = COLOR_RGB565_TO_L(_pixel); \
int8_t _a = COLOR_RGB565_TO_A(_pixel); \
int8_t _b = COLOR_RGB565_TO_B(_pixel); \
((_threshold->LMin <= _l) && (_l <= _threshold->LMax) && (_threshold->AMin <= _a) && (_a <= _threshold->AMax) && (_threshold->BMin <= _b) && (_b <= _threshold->BMax)) ^ _invert; \
((_threshold->LMin <= _l) && (_l <= _threshold->LMax) && \
(_threshold->AMin <= _a) && (_a <= _threshold->AMax) && \
(_threshold->BMin <= _b) && (_b <= _threshold->BMax)) ^ _invert; \
})
#define COLOR_BOUND_BINARY(pixel0, pixel1, threshold) \
({ \
__typeof__ (pixel0) _pixel0 = (pixel0); \
__typeof__ (pixel1) _pixel1 = (pixel1); \
__typeof__ (threshold) _threshold = (threshold); \
(abs(_pixel0 - _pixel1) <= _threshold); \
})
#define COLOR_BOUND_GRAYSCALE(pixel0, pixel1, threshold) \
({ \
__typeof__ (pixel0) _pixel0 = (pixel0); \
__typeof__ (pixel1) _pixel1 = (pixel1); \
__typeof__ (threshold) _threshold = (threshold); \
(abs(_pixel0 - _pixel1) <= _threshold); \
})
#define COLOR_BOUND_RGB565(pixel0, pixel1, threshold) \
({ \
__typeof__ (pixel0) _pixel0 = (pixel0); \
__typeof__ (pixel1) _pixel1 = (pixel1); \
__typeof__ (threshold) _threshold = (threshold); \
(abs(COLOR_RGB565_TO_R5(_pixel0) - COLOR_RGB565_TO_R5(_pixel1)) <= COLOR_RGB565_TO_R5(_threshold)) && \
(abs(COLOR_RGB565_TO_G6(_pixel0) - COLOR_RGB565_TO_G6(_pixel1)) <= COLOR_RGB565_TO_G6(_threshold)) && \
(abs(COLOR_RGB565_TO_B5(_pixel0) - COLOR_RGB565_TO_B5(_pixel1)) <= COLOR_RGB565_TO_B5(_threshold)); \
})
#define COLOR_BINARY_MIN 0
@ -942,6 +970,7 @@ typedef struct img_read_settings {
} img_read_settings_t;
typedef void (*line_op_t)(image_t*, int, void*, void*, bool);
typedef void (*flood_fill_call_back_t)(image_t *, int, int, int, void *);
typedef enum descriptor_type {
DESC_LBP,
@ -1210,6 +1239,10 @@ void imlib_edge_canny(image_t *src, rectangle_t *roi, int low_thresh, int high_t
// HoG
void imlib_find_hog(image_t *src, rectangle_t *roi, int cell_size);
// Helper Functions
void imlib_flood_fill_int(image_t *out, image_t *img, int x, int y,
int seed_threshold, int floating_threshold,
flood_fill_call_back_t cb, void *data);
// Drawing Functions
int imlib_get_pixel(image_t *img, int x, int y);
void imlib_set_pixel(image_t *img, int x, int y, int p);
@ -1217,6 +1250,9 @@ void imlib_draw_line(image_t *img, int x0, int y0, int x1, int y1, int c, int th
void imlib_draw_rectangle(image_t *img, int rx, int ry, int rw, int rh, int c, int thickness, bool fill);
void imlib_draw_circle(image_t *img, int cx, int cy, int r, int c, int thickness, bool fill);
void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int c, int scale, int x_spacing, int y_spacing);
void imlib_flood_fill(image_t *img, int x, int y,
float seed_threshold, float floating_threshold,
int c, bool invert, bool clear_background, image_t *mask);
// Binary Functions
void imlib_binary(image_t *img, list_t *thresholds, bool invert, bool zero, image_t *mask);
void imlib_invert(image_t *img);

View File

@ -1070,7 +1070,7 @@ STATIC mp_obj_t py_image_draw_circle(uint n_args, const mp_obj_t *args, mp_map_t
imlib_draw_circle(arg_img, arg_cx, arg_cy, arg_cr, arg_c, arg_thickness, arg_fill);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_circle_obj, 4, py_image_draw_circle);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_circle_obj, 2, py_image_draw_circle);
STATIC mp_obj_t py_image_draw_string(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
@ -1094,7 +1094,7 @@ STATIC mp_obj_t py_image_draw_string(uint n_args, const mp_obj_t *args, mp_map_t
imlib_draw_string(arg_img, arg_x_off, arg_y_off, arg_str, arg_c, arg_scale, arg_x_spacing, arg_y_spacing);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_string_obj, 4, py_image_draw_string);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_string_obj, 2, py_image_draw_string);
STATIC mp_obj_t py_image_draw_cross(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
@ -1185,6 +1185,40 @@ STATIC mp_obj_t py_image_draw_keypoints(uint n_args, const mp_obj_t *args, mp_ma
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_keypoints_obj, 2, py_image_draw_keypoints);
STATIC mp_obj_t py_image_flood_fill(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_mutable(args[0]);
const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 1, 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_seed_threshold =
py_helper_keyword_float(n_args, args, offset + 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_seed_threshold), 0.05);
PY_ASSERT_TRUE_MSG((0.0f <= arg_seed_threshold) && (arg_seed_threshold <= 1.0f),
"Error: 0.0 <= seed_threshold <= 1.0!");
float arg_floating_threshold =
py_helper_keyword_float(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_floating_threshold), 0.05);
PY_ASSERT_TRUE_MSG((0.0f <= arg_floating_threshold) && (arg_floating_threshold <= 1.0f),
"Error: 0.0 <= floating_threshold <= 1.0!");
int arg_c =
py_helper_keyword_color(arg_img, n_args, args, offset + 2, kw_args, -1); // White.
bool arg_invert =
py_helper_keyword_float(n_args, args, offset + 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false);
bool clear_background =
py_helper_keyword_float(n_args, args, offset + 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_clear_background), false);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, offset + 5, kw_args);
fb_alloc_mark();
imlib_flood_fill(arg_img, arg_x_off, arg_y_off, arg_seed_threshold, arg_floating_threshold,
arg_c, arg_invert, clear_background, arg_msk);
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_flood_fill_obj, 2, py_image_flood_fill);
/////////////////
// Binary Methods
/////////////////
@ -2002,10 +2036,8 @@ STATIC mp_obj_t py_image_bilateral(uint n_args, const mp_obj_t *args, mp_map_t *
py_helper_arg_to_ksize(args[1]);
float arg_color_sigma =
py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color_sigma), 0.1);
PY_ASSERT_TRUE_MSG((0 <= arg_color_sigma), "Error: 0 <= color_sigma!");
float arg_space_sigma =
py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_space_sigma), 1);
PY_ASSERT_TRUE_MSG((0 <= arg_space_sigma), "Error: 0 <= space_sigma!");
bool arg_threshold =
py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false);
int arg_offset =
@ -4906,6 +4938,7 @@ static const mp_rom_map_elem_t locals_dict_table[] = {
{MP_ROM_QSTR(MP_QSTR_draw_string), MP_ROM_PTR(&py_image_draw_string_obj)},
{MP_ROM_QSTR(MP_QSTR_draw_cross), MP_ROM_PTR(&py_image_draw_cross_obj)},
{MP_ROM_QSTR(MP_QSTR_draw_arrow), MP_ROM_PTR(&py_image_draw_arrow_obj)},
{MP_ROM_QSTR(MP_QSTR_flood_fill), MP_ROM_PTR(&py_image_flood_fill_obj)},
{MP_ROM_QSTR(MP_QSTR_draw_keypoints), MP_ROM_PTR(&py_image_draw_keypoints_obj)},
/* Binary Methods */
{MP_ROM_QSTR(MP_QSTR_binary), MP_ROM_PTR(&py_image_binary_obj)},

View File

@ -38,7 +38,6 @@ Q(width)
Q(height)
Q(format)
Q(size)
Q(gaussian)
Q(midpoint_pool)
Q(midpoint_pooled)
Q(mean_pool)
@ -47,7 +46,6 @@ Q(find_template)
Q(kp_desc)
Q(lbp_desc)
Q(Cascade)
Q(mask_ellipse)
Q(find_features)
Q(find_keypoints)
Q(find_lbp)
@ -317,6 +315,9 @@ Q(rgbtuple)
Q(set_pixel)
Q(color)
// Clear
Q(clear)
// Draw Line
Q(draw_line)
// duplicate Q(color)
@ -360,11 +361,20 @@ Q(draw_keypoints)
// duplicate Q(thickness)
// duplicate Q(fill)
// Flood Fill
Q(flood_fill)
Q(seed_threshold)
Q(floating_threshold)
// duplicate Q(color)
Q(invert)
Q(clear_background)
Q(mask)
// Binary
Q(binary)
Q(invert)
// duplicate Q(invert)
Q(zero)
Q(mask)
// duplicate Q(mask)
// Invert
// duplicate Q(invert)
@ -401,12 +411,12 @@ Q(b_xnor)
// Erode
Q(erode)
Q(threshold)
// duplicate Q(threshold)
// duplicate Q(mask)
// Dilate
Q(dilate)
// duplicate Q(threshold)
Q(threshold)
// duplicate Q(mask)
// Open

View File

@ -0,0 +1,35 @@
# Flood Fill
#
# This example shows off flood filling areas in the image.
import sensor, image, time
sensor.reset()
sensor.set_pixformat(sensor.RGB565) # or GRAYSCALE...
sensor.set_framesize(sensor.QVGA) # or QQVGA...
sensor.skip_frames(time = 2000)
clock = time.clock()
while(True):
clock.tick()
# seed_threshold controls the maximum allowed difference between
# the initial pixel and any filled pixels. It's important to
# set this such that flood fill doesn't fill the whole image.
# floating_threshold controls the maximum allowed difference
# between any two pixels. This can easily fill the whole image
# with even a very low threshold.
# flood_fill will fill pixels that both thresholds.
# You can invert what gets filled with "invert" and clear
# everything but the filled area with "clear_background".
x = sensor.width() // 2
y = sensor.height() // 2
img = sensor.snapshot().flood_fill(x, y, \
seed_threshold=0.05, floating_thresholds=0.05, \
color=(255, 0, 0), invert=False, clear_background=False)
print(clock.fps())