mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Add flood fill
The algorithm itself is setup to be used for future filters.
This commit is contained in:
parent
82ff7a250e
commit
7f798a8282
@ -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);
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)},
|
||||
|
||||
@ -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
|
||||
|
||||
35
usr/examples/03-Drawing/flood_fill.py
Normal file
35
usr/examples/03-Drawing/flood_fill.py
Normal 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())
|
||||
Loading…
Reference in New Issue
Block a user