mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Merge pull request #118 from kwagyeman/master
Fix blob code. * Remove MP code from omv/img/
This commit is contained in:
commit
7ace96de2c
@ -6,9 +6,10 @@
|
||||
* Blob and color code/marker detection code...
|
||||
*
|
||||
*/
|
||||
#include <mp.h>
|
||||
#include <string.h>
|
||||
#include "mdefs.h"
|
||||
#include "fb_alloc.h"
|
||||
#include "xalloc.h"
|
||||
#include "imlib.h"
|
||||
|
||||
ALWAYS_INLINE static uint8_t *init_mask(rectangle_t *roi)
|
||||
@ -106,7 +107,10 @@ ALWAYS_INLINE static bool threshold(image_t *img, int x, int y, simple_color_t l
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t imlib_find_blobs(mp_obj_t img_obj, image_t *img, int num_thresholds, simple_color_t *l_thresholds, simple_color_t *h_thresholds, bool invert, rectangle_t *r, mp_obj_t filtering_fn)
|
||||
array_t *imlib_find_blobs(image_t *img,
|
||||
int num_thresholds, simple_color_t *l_thresholds, simple_color_t *h_thresholds,
|
||||
bool invert, rectangle_t *r,
|
||||
bool (*f_fun)(void*,void*,color_blob_t*), void *f_fun_arg_0, void *f_fun_arg_1)
|
||||
{
|
||||
// We're using a modified wildfire algorithm below where instead of using a
|
||||
// the stack we use a queue along with a burn mask to filter out already
|
||||
@ -114,22 +118,20 @@ mp_obj_t imlib_find_blobs(mp_obj_t img_obj, image_t *img, int num_thresholds, si
|
||||
// an area of connected pixels that all are within a threshold, the algorithm
|
||||
// computes the bounding box around all those pixels, number of pixels in the
|
||||
// blob, centroid, and blob orientation. The algorithm then returns a list
|
||||
// of blobs for each set of thresholds passed in. That is, this function
|
||||
// returns a tuple of lists of blobs.
|
||||
// of all the blobs in the image. Note that blobs can be mapped back to colors
|
||||
// by their blob code number.
|
||||
|
||||
rectangle_t rect;
|
||||
if (!rectangle_subimg(img, r, &rect)) {
|
||||
return mp_const_none;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mp_obj_t blob_lists[num_thresholds];
|
||||
|
||||
uint8_t *mask = init_mask(&rect);
|
||||
stack_queue_t *sq = init_stack_queue(&rect);
|
||||
|
||||
array_t *blobs_list;
|
||||
array_alloc(&blobs_list, xfree);
|
||||
for (int n = 0; n < num_thresholds; n++) {
|
||||
blob_lists[n] = mp_obj_new_list(4, NULL); // 4 is just the intial list size guess
|
||||
mp_obj_list_set_len(blob_lists[n], 0);
|
||||
for (int i = 0; i < rect.h; i++) {
|
||||
for (int j = 0; j < rect.w; j++) {
|
||||
int x = (rect.x + j); // in img
|
||||
@ -188,29 +190,29 @@ mp_obj_t imlib_find_blobs(mp_obj_t img_obj, image_t *img, int num_thresholds, si
|
||||
blob_c += blob_pixels*my*my;
|
||||
// Compute the final blob orientation from a, b, and c sums.
|
||||
float o = ((blob_a!=blob_c)?fast_atan2f(blob_b,blob_a-blob_c):0.0)/2.0;
|
||||
mp_obj_t blob_tuple[10];
|
||||
blob_tuple[0] = mp_obj_new_int(blob_x1);
|
||||
blob_tuple[1] = mp_obj_new_int(blob_y1);
|
||||
blob_tuple[2] = mp_obj_new_int(blob_x2-blob_x1+1);
|
||||
blob_tuple[3] = mp_obj_new_int(blob_y2-blob_y1+1);
|
||||
blob_tuple[4] = mp_obj_new_int(blob_pixels);
|
||||
blob_tuple[5] = mp_obj_new_int(mx);
|
||||
blob_tuple[6] = mp_obj_new_int(my);
|
||||
blob_tuple[7] = mp_obj_new_float(o);
|
||||
blob_tuple[8] = mp_obj_new_int(1<<n);
|
||||
blob_tuple[9] = mp_obj_new_int(1);
|
||||
mp_obj_t blob_tuple_obj = mp_obj_new_tuple(10, blob_tuple);
|
||||
if (filtering_fn != MP_OBJ_NULL) {
|
||||
if (mp_obj_is_true(mp_call_function_2(filtering_fn, img_obj, blob_tuple_obj))) {
|
||||
mp_obj_list_append(blob_lists[n], blob_tuple_obj);
|
||||
} else {
|
||||
mp_obj_tuple_del(blob_tuple_obj);
|
||||
color_blob_t cb;
|
||||
cb.x = blob_x1;
|
||||
cb.y = blob_y1;
|
||||
cb.w = blob_x2-blob_x1+1;
|
||||
cb.h = blob_y2-blob_y1+1;
|
||||
cb.pixels = blob_pixels;
|
||||
cb.cx = mx;
|
||||
cb.cy = my;
|
||||
cb.rotation = o;
|
||||
cb.code = 1<<n;
|
||||
cb.count = 1;
|
||||
// We allocate in the below code to sped things up.
|
||||
if ((f_fun != NULL) && (f_fun_arg_0 != NULL) && (f_fun_arg_1 != NULL)) {
|
||||
if (f_fun(f_fun_arg_0, f_fun_arg_1, &cb)) {
|
||||
color_blob_t *cb2 = xalloc(sizeof(color_blob_t));
|
||||
memcpy(cb2, &cb, sizeof(color_blob_t));
|
||||
array_push_back(blobs_list, cb2);
|
||||
}
|
||||
} else {
|
||||
if (blob_pixels >= ((img->w*img->h)/1000)) {
|
||||
mp_obj_list_append(blob_lists[n], blob_tuple_obj);
|
||||
} else {
|
||||
mp_obj_tuple_del(blob_tuple_obj);
|
||||
color_blob_t *cb2 = xalloc(sizeof(color_blob_t));
|
||||
memcpy(cb2, &cb, sizeof(color_blob_t));
|
||||
array_push_back(blobs_list, cb2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -221,137 +223,125 @@ mp_obj_t imlib_find_blobs(mp_obj_t img_obj, image_t *img, int num_thresholds, si
|
||||
deinit_stack_queue();
|
||||
deinit_mask();
|
||||
|
||||
return mp_obj_new_tuple(num_thresholds, blob_lists);
|
||||
return blobs_list;
|
||||
}
|
||||
|
||||
mp_obj_t imlib_find_markers(mp_obj_t img_obj, mp_obj_t blob_lists_obj, int margin, mp_obj_t filtering_fn)
|
||||
array_t *imlib_find_markers(array_t *blobs_list, int margin,
|
||||
bool (*f_fun)(void*,void*,color_blob_t*), void *f_fun_arg_0, void *f_fun_arg_1)
|
||||
{
|
||||
// After you have a list of blobs this function will merge blobs from the
|
||||
// different colors lists that intersect into one blob. The new merged big
|
||||
// blob will have a bounding box that surronds all the merged blobs, pixels will
|
||||
// include all the blobs, and centroids/orientations are averaged. Additionally,
|
||||
// the new blob will have an extra code value with a bit set for each color
|
||||
// that was merged into the blob along with the number of blobs merged. The
|
||||
// color code provides a nice and easy user controllable way to get an idea
|
||||
// of what colors are in a merged blob.
|
||||
// After you have a list of blobs this function will merge blobs that
|
||||
// intersect into one blob. The new merged big blob will have a bounding box
|
||||
// that surronds all the merged blobs, pixels will include all the blobs,
|
||||
// and centroids/orientations are averaged. Additionally, the new blob will
|
||||
// have an extra code value with a bit set for each color that was merged
|
||||
// into the blob along with the number of blobs merged. The color code
|
||||
// provides a nice and easy user controllable way to get an idea of what
|
||||
// colors are in a merged blob.
|
||||
|
||||
mp_uint_t blob_l_len;
|
||||
mp_obj_t *blob_l;
|
||||
mp_obj_get_array(blob_lists_obj, &blob_l_len, &blob_l);
|
||||
if (!blob_l_len) return mp_const_none;
|
||||
|
||||
mp_uint_t blob_lists_len[blob_l_len];
|
||||
mp_obj_t *blob_lists[blob_l_len];
|
||||
if (!array_length(blobs_list)) return NULL;
|
||||
|
||||
rectangle_t rect; // reusing mask from above - so we need a fake rect obj.
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.w = 0;
|
||||
rect.h = blob_l_len;
|
||||
|
||||
for (mp_uint_t i = 0; i < blob_l_len; i++) {
|
||||
mp_obj_get_array(blob_l[i], &blob_lists_len[i], &blob_lists[i]);
|
||||
rect.w = IM_MAX(rect.w, blob_lists_len[i]); // find longest list
|
||||
}
|
||||
if (!rect.w) return mp_const_none;
|
||||
rect.w = array_length(blobs_list);
|
||||
rect.h = 1;
|
||||
|
||||
uint8_t *mask = init_mask(&rect);
|
||||
|
||||
mp_obj_t out = mp_obj_new_list(4, NULL); // 4 is just the intial list size guess
|
||||
mp_obj_list_set_len(out, 0);
|
||||
for (mp_uint_t i = 0; i < blob_l_len; i++) {
|
||||
for (mp_uint_t j = 0; j < blob_lists_len[i]; j++) {
|
||||
if (get_not_mask_pixel(&rect, mask, j, i)) {
|
||||
set_mask_pixel(&rect, mask, j, i);
|
||||
array_t *blobs_list_ret;
|
||||
array_alloc(&blobs_list_ret, xfree);
|
||||
for (int i = 0, ii = array_length(blobs_list); i < ii; i++) {
|
||||
if (get_not_mask_pixel(&rect, mask, i, 0)) {
|
||||
set_mask_pixel(&rect, mask, i, 0);
|
||||
|
||||
mp_obj_t *temp0;
|
||||
mp_obj_get_array_fixed_n(blob_lists[i][j], 10, &temp0);
|
||||
color_blob_t *cb0 = array_at(blobs_list, i);
|
||||
|
||||
int blob_x = mp_obj_get_int(temp0[0]); // rect x
|
||||
int blob_y = mp_obj_get_int(temp0[1]); // rect y
|
||||
int blob_w = mp_obj_get_int(temp0[2]); // rect w
|
||||
int blob_h = mp_obj_get_int(temp0[3]); // rect h
|
||||
int blob_pixels = mp_obj_get_int(temp0[4]); // pixels
|
||||
int blob_cx = mp_obj_get_int(temp0[5]); // centroid x
|
||||
int blob_cy = mp_obj_get_int(temp0[6]); // centroid y
|
||||
float blob_rotation = mp_obj_get_float(temp0[7]); // rotation
|
||||
int blob_code = mp_obj_get_int(temp0[8]); // code bit
|
||||
int blob_count = mp_obj_get_int(temp0[9]); // blob count
|
||||
int blob_x = cb0->x; // rect x
|
||||
int blob_y = cb0->y; // rect y
|
||||
int blob_w = cb0->w; // rect w
|
||||
int blob_h = cb0->h; // rect h
|
||||
int blob_pixels = cb0->pixels; // pixels
|
||||
int blob_cx = cb0->cx; // centroid x
|
||||
int blob_cy = cb0->cy; // centroid y
|
||||
float blob_rotation = cb0->rotation; // rotation
|
||||
int blob_code = cb0->code; // code bit
|
||||
int blob_count = cb0->count; // blob count
|
||||
|
||||
for (mp_uint_t a = 0; a < blob_l_len; a++) {
|
||||
for (mp_uint_t b = 0; b < blob_lists_len[a]; b++) {
|
||||
if (get_not_mask_pixel(&rect, mask, b, a)) {
|
||||
for (int j = 0, jj = array_length(blobs_list); j < jj;) {
|
||||
if (get_not_mask_pixel(&rect, mask, j, 0)) {
|
||||
|
||||
mp_obj_t *temp1;
|
||||
mp_obj_get_array_fixed_n(blob_lists[a][b], 10, &temp1);
|
||||
color_blob_t *cb1 = array_at(blobs_list, j);
|
||||
|
||||
rectangle_t t0;
|
||||
t0.x = blob_x - margin;
|
||||
t0.y = blob_y - margin;
|
||||
t0.w = blob_w + (2*margin);
|
||||
t0.h = blob_h + (2*margin);
|
||||
rectangle_t t0, t1;
|
||||
t0.x = blob_x - margin;
|
||||
t0.y = blob_y - margin;
|
||||
t0.w = blob_w + (2*margin);
|
||||
t0.h = blob_h + (2*margin);
|
||||
t1.x = cb1->x - margin;
|
||||
t1.y = cb1->y - margin;
|
||||
t1.w = cb1->w + (2*margin);
|
||||
t1.h = cb1->h + (2*margin);
|
||||
|
||||
rectangle_t t1;
|
||||
t1.x = mp_obj_get_int(temp1[0]) - margin;
|
||||
t1.y = mp_obj_get_int(temp1[1]) - margin;
|
||||
t1.w = mp_obj_get_int(temp1[2]) + (2*margin);
|
||||
t1.h = mp_obj_get_int(temp1[3]) + (2*margin);
|
||||
|
||||
if (rectangle_intersects(&t0, &t1)) {
|
||||
set_mask_pixel(&rect, mask, b, a);
|
||||
|
||||
// Compute bounding rect...
|
||||
blob_x = IM_MIN(blob_x, t1.x);
|
||||
blob_y = IM_MIN(blob_y, t1.y);
|
||||
int x2_0 = t0.x+t0.w-1;
|
||||
int x2_1 = t1.x+t1.w-1;
|
||||
int x2 = IM_MAX(x2_0, x2_1);
|
||||
blob_w = x2-blob_x+1;
|
||||
int y2_0 = t0.y+t0.h-1;
|
||||
int y2_1 = t1.y+t1.h-1;
|
||||
int y2 = IM_MAX(y2_0, y2_1);
|
||||
blob_h = y2-blob_y+1;
|
||||
// Update tracking info...
|
||||
blob_pixels += mp_obj_get_int(temp1[4]);
|
||||
blob_cx += mp_obj_get_int(temp1[5]);
|
||||
blob_cy += mp_obj_get_int(temp1[6]);
|
||||
blob_rotation += mp_obj_get_float(temp1[7]);
|
||||
blob_code |= mp_obj_get_int(temp1[8]);
|
||||
blob_count += mp_obj_get_int(temp1[9]);
|
||||
}
|
||||
}
|
||||
if (rectangle_intersects(&t0, &t1)) {
|
||||
set_mask_pixel(&rect, mask, j, 0);
|
||||
// Compute bounding rect...
|
||||
int x2_0 = blob_x+blob_w-1;
|
||||
int x2_1 = cb1->x+cb1->w-1;
|
||||
int x2 = IM_MAX(x2_0, x2_1);
|
||||
blob_x = IM_MIN(blob_x, cb1->x);
|
||||
blob_w = x2-blob_x+1;
|
||||
int y2_0 = blob_y+blob_h-1;
|
||||
int y2_1 = cb1->y+cb1->h-1;
|
||||
int y2 = IM_MAX(y2_0, y2_1);
|
||||
blob_y = IM_MIN(blob_y, cb1->y);
|
||||
blob_h = y2-blob_y+1;
|
||||
// Update tracking info...
|
||||
blob_pixels += cb1->pixels;
|
||||
blob_cx += cb1->cx;
|
||||
blob_cy += cb1->cy;
|
||||
blob_rotation += cb1->rotation;
|
||||
blob_code |= cb1->code;
|
||||
blob_count += cb1->count;
|
||||
// Start over if we merged so we don't miss something.
|
||||
// Since our rect has grown we have to recheck blobs
|
||||
// that didn't intersect previously.
|
||||
j = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
blob_cx /= blob_count;
|
||||
blob_cy /= blob_count;
|
||||
blob_rotation /= blob_count;
|
||||
// Build output object.
|
||||
mp_obj_t blob_tuple[10];
|
||||
blob_tuple[0] = mp_obj_new_int(blob_x);
|
||||
blob_tuple[1] = mp_obj_new_int(blob_y);
|
||||
blob_tuple[2] = mp_obj_new_int(blob_w);
|
||||
blob_tuple[3] = mp_obj_new_int(blob_h);
|
||||
blob_tuple[4] = mp_obj_new_int(blob_pixels);
|
||||
blob_tuple[5] = mp_obj_new_int(blob_cx);
|
||||
blob_tuple[6] = mp_obj_new_int(blob_cy);
|
||||
blob_tuple[7] = mp_obj_new_float(blob_rotation);
|
||||
blob_tuple[8] = mp_obj_new_int(blob_code);
|
||||
blob_tuple[9] = mp_obj_new_int(blob_count);
|
||||
mp_obj_t blob_tuple_obj = mp_obj_new_tuple(10, blob_tuple);
|
||||
if (filtering_fn != MP_OBJ_NULL) {
|
||||
if (mp_obj_is_true(mp_call_function_2(filtering_fn, img_obj, blob_tuple_obj))) {
|
||||
mp_obj_list_append(out, blob_tuple_obj);
|
||||
} else {
|
||||
mp_obj_tuple_del(blob_tuple_obj);
|
||||
}
|
||||
} else {
|
||||
mp_obj_list_append(out, blob_tuple_obj);
|
||||
j += 1;
|
||||
}
|
||||
blob_cx /= blob_count;
|
||||
blob_cy /= blob_count;
|
||||
blob_rotation /= blob_count;
|
||||
// Build output object.
|
||||
color_blob_t cb;
|
||||
cb.x = blob_x;
|
||||
cb.y = blob_y;
|
||||
cb.w = blob_w;
|
||||
cb.h = blob_h;
|
||||
cb.pixels = blob_pixels;
|
||||
cb.cx = blob_cx;
|
||||
cb.cy = blob_cy;
|
||||
cb.rotation = blob_rotation;
|
||||
cb.code = blob_code;
|
||||
cb.count = blob_count;
|
||||
// We allocate in the below code to sped things up.
|
||||
if ((f_fun != NULL) && (f_fun_arg_0 != NULL) && (f_fun_arg_1 != NULL)) {
|
||||
if (f_fun(f_fun_arg_0, f_fun_arg_1, &cb)) {
|
||||
color_blob_t *cb2 = xalloc(sizeof(color_blob_t));
|
||||
memcpy(cb2, &cb, sizeof(color_blob_t));
|
||||
array_push_back(blobs_list_ret, cb2);
|
||||
}
|
||||
} else {
|
||||
color_blob_t *cb2 = xalloc(sizeof(color_blob_t));
|
||||
memcpy(cb2, &cb, sizeof(color_blob_t));
|
||||
array_push_back(blobs_list_ret, cb2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deinit_mask();
|
||||
|
||||
return out;
|
||||
return blobs_list_ret;
|
||||
}
|
||||
|
||||
@ -398,7 +398,9 @@ void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void imlib_binary(image_t *img, int num_thresholds, simple_color_t *l_thresholds, simple_color_t *h_thresholds, bool invert)
|
||||
void imlib_binary(image_t *img,
|
||||
int num_thresholds, simple_color_t *l_thresholds, simple_color_t *h_thresholds,
|
||||
bool invert)
|
||||
{
|
||||
if (IM_IS_GS(img)) {
|
||||
uint8_t *pixels = img->pixels;
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
#include <ff.h>
|
||||
#include "array.h"
|
||||
#include "fmath.h"
|
||||
#include "obj.h"
|
||||
|
||||
#define IM_SWAP16(x) __REV16(x) // Swap bottom two chars in short.
|
||||
#define IM_SWAP32(x) __REV32(x) // Swap bottom two shorts in long.
|
||||
@ -232,6 +231,20 @@ typedef struct statistics {
|
||||
int8_t l_upper_q, a_upper_q, b_upper_q;
|
||||
} statistics_t;
|
||||
|
||||
typedef struct color_blob { // organized this way to pack it...
|
||||
int16_t x; // rect - 0
|
||||
int16_t y; // rect - 1
|
||||
int16_t w; // rect - 2
|
||||
int16_t h; // rect - 3
|
||||
int16_t cx; // centroid - 5
|
||||
int16_t cy; // centroid - 6
|
||||
float rotation; // rotation - 7
|
||||
uint16_t pixels; // number of pixels in merged blobs - 4
|
||||
uint16_t count; // number of blobs merged into this blob - 9
|
||||
uint32_t code; // color code index bits of merged blobs - 8
|
||||
}
|
||||
color_blob_t;
|
||||
|
||||
typedef struct color {
|
||||
union {
|
||||
uint8_t vec[3];
|
||||
@ -426,7 +439,9 @@ void imlib_draw_circle(image_t *img, int cx, int cy, int r, int c);
|
||||
void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int c);
|
||||
|
||||
/* Binary functions */
|
||||
void imlib_binary(image_t *img, int num_thresholds, simple_color_t *l_thresholds, simple_color_t *h_thresholds, bool invert);
|
||||
void imlib_binary(image_t *img,
|
||||
int num_thresholds, simple_color_t *l_thresholds, simple_color_t *h_thresholds,
|
||||
bool invert);
|
||||
void imlib_invert(image_t *img);
|
||||
void imlib_and(image_t *img, const char *path, image_t *other);
|
||||
void imlib_nand(image_t *img, const char *path, image_t *other);
|
||||
@ -455,8 +470,12 @@ void imlib_mode_filter(image_t *img, const int ksize);
|
||||
void imlib_median_filter(image_t *img, const int ksize, const int percentile);
|
||||
|
||||
/* Color Tracking */
|
||||
mp_obj_t imlib_find_blobs(mp_obj_t img_obj, image_t *img, int num_thresholds, simple_color_t *l_thresholds, simple_color_t *h_thresholds, bool invert, rectangle_t *r, mp_obj_t filtering_fn);
|
||||
mp_obj_t imlib_find_markers(mp_obj_t img_obj, mp_obj_t blob_lists_obj, int margin, mp_obj_t filtering_fn);
|
||||
array_t *imlib_find_blobs(image_t *img,
|
||||
int num_thresholds, simple_color_t *l_thresholds, simple_color_t *h_thresholds,
|
||||
bool invert, rectangle_t *r,
|
||||
bool (*f_fun)(void*,void*,color_blob_t*), void *f_fun_arg_0, void *f_fun_arg_1);
|
||||
array_t *imlib_find_markers(array_t *blobs_list, int margin,
|
||||
bool (*f_fun)(void*,void*,color_blob_t*), void *f_fun_arg_0, void *f_fun_arg_1);
|
||||
|
||||
/* Clustering functions */
|
||||
array_t *cluster_kmeans(array_t *points, int k);
|
||||
|
||||
@ -696,6 +696,23 @@ static mp_obj_t py_image_median(uint n_args, const mp_obj_t *args, mp_map_t *kw_
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
static bool py_image_find_blobs_f_fun(void *fun_obj, void *img_obj, color_blob_t *cb)
|
||||
{
|
||||
mp_obj_t blob_obj[10] = {
|
||||
mp_obj_new_int(cb->x),
|
||||
mp_obj_new_int(cb->y),
|
||||
mp_obj_new_int(cb->w),
|
||||
mp_obj_new_int(cb->h),
|
||||
mp_obj_new_int(cb->pixels),
|
||||
mp_obj_new_int(cb->cx),
|
||||
mp_obj_new_int(cb->cy),
|
||||
mp_obj_new_float(cb->rotation),
|
||||
mp_obj_new_int(cb->code),
|
||||
mp_obj_new_int(cb->count)
|
||||
};
|
||||
return mp_obj_is_true(mp_call_function_2(fun_obj, img_obj, mp_obj_new_tuple(10, blob_obj)));
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_find_blobs(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
{
|
||||
image_t *arg_img = py_image_cobj(args[0]);
|
||||
@ -742,10 +759,50 @@ static mp_obj_t py_image_find_blobs(uint n_args, const mp_obj_t *args, mp_map_t
|
||||
py_helper_lookup_rectangle(kw_args, arg_img, &arg_r);
|
||||
|
||||
mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_feature_filter), MP_MAP_LOOKUP);
|
||||
mp_obj_t kw_val = (kw_arg != NULL) ? kw_arg->value : MP_OBJ_NULL;
|
||||
mp_obj_t kw_val = (kw_arg != NULL) ? kw_arg->value : NULL;
|
||||
|
||||
int arg_invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), 0);
|
||||
return imlib_find_blobs(args[0], arg_img, arg_t_len, l_t, u_t, arg_invert ? 1 : 0, &arg_r, kw_val);
|
||||
array_t *blobs_list = imlib_find_blobs(arg_img, arg_t_len, l_t, u_t, arg_invert ? 1 : 0, &arg_r,
|
||||
py_image_find_blobs_f_fun, kw_val, args[0]);
|
||||
if (blobs_list == NULL) {
|
||||
return mp_const_none;
|
||||
}
|
||||
mp_obj_t objects_list = mp_obj_new_list(0, NULL);
|
||||
for (int i=0, j=array_length(blobs_list); i<j; i++) {
|
||||
color_blob_t *cb = array_at(blobs_list, i);
|
||||
mp_obj_t blob_obj[10] = {
|
||||
mp_obj_new_int(cb->x),
|
||||
mp_obj_new_int(cb->y),
|
||||
mp_obj_new_int(cb->w),
|
||||
mp_obj_new_int(cb->h),
|
||||
mp_obj_new_int(cb->pixels),
|
||||
mp_obj_new_int(cb->cx),
|
||||
mp_obj_new_int(cb->cy),
|
||||
mp_obj_new_float(cb->rotation),
|
||||
mp_obj_new_int(cb->code),
|
||||
mp_obj_new_int(cb->count)
|
||||
};
|
||||
mp_obj_list_append(objects_list, mp_obj_new_tuple(10, blob_obj));
|
||||
}
|
||||
array_free(blobs_list);
|
||||
return objects_list;
|
||||
}
|
||||
|
||||
static bool py_image_find_markers_f_fun(void *fun_obj, void *img_obj, color_blob_t *cb)
|
||||
{
|
||||
mp_obj_t blob_obj[10] = {
|
||||
mp_obj_new_int(cb->x),
|
||||
mp_obj_new_int(cb->y),
|
||||
mp_obj_new_int(cb->w),
|
||||
mp_obj_new_int(cb->h),
|
||||
mp_obj_new_int(cb->pixels),
|
||||
mp_obj_new_int(cb->cx),
|
||||
mp_obj_new_int(cb->cy),
|
||||
mp_obj_new_float(cb->rotation),
|
||||
mp_obj_new_int(cb->code),
|
||||
mp_obj_new_int(cb->count)
|
||||
};
|
||||
return mp_obj_is_true(mp_call_function_2(fun_obj, img_obj, mp_obj_new_tuple(10, blob_obj)));
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_find_markers(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
@ -757,9 +814,56 @@ static mp_obj_t py_image_find_markers(uint n_args, const mp_obj_t *args, mp_map_
|
||||
int margin = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_margin), 2);
|
||||
|
||||
mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_feature_filter), MP_MAP_LOOKUP);
|
||||
mp_obj_t kw_val = (kw_arg != NULL) ? kw_arg->value : MP_OBJ_NULL;
|
||||
mp_obj_t kw_val = (kw_arg != NULL) ? kw_arg->value : NULL;
|
||||
|
||||
return imlib_find_markers(args[0], args[1], margin, kw_val);
|
||||
mp_uint_t arg_t_len;
|
||||
mp_obj_t *arg_t;
|
||||
mp_obj_get_array(args[1], &arg_t_len, &arg_t);
|
||||
if (!arg_t_len) return mp_const_none;
|
||||
|
||||
array_t *blobs_list;
|
||||
array_alloc_init(&blobs_list, xfree, arg_t_len);
|
||||
for (int i=0; i<arg_t_len; i++) {
|
||||
mp_obj_t *temp;
|
||||
mp_obj_get_array_fixed_n(arg_t[i], 10, &temp);
|
||||
color_blob_t *cb = xalloc(sizeof(color_blob_t));
|
||||
cb->x = mp_obj_get_int(temp[0]);
|
||||
cb->y = mp_obj_get_int(temp[1]);
|
||||
cb->w = mp_obj_get_int(temp[2]);
|
||||
cb->h = mp_obj_get_int(temp[3]);
|
||||
cb->pixels = mp_obj_get_int(temp[4]);
|
||||
cb->cx = mp_obj_get_int(temp[5]);
|
||||
cb->cy = mp_obj_get_int(temp[6]);
|
||||
cb->rotation = mp_obj_get_float(temp[7]);
|
||||
cb->code = mp_obj_get_int(temp[8]);
|
||||
cb->count = mp_obj_get_int(temp[9]);
|
||||
array_push_back(blobs_list, cb);
|
||||
}
|
||||
array_t *blobs_list_ret = imlib_find_markers(blobs_list, margin,
|
||||
py_image_find_markers_f_fun, kw_val, args[0]);
|
||||
if (blobs_list_ret == NULL) {
|
||||
return mp_const_none;
|
||||
}
|
||||
array_free(blobs_list);
|
||||
mp_obj_t objects_list = mp_obj_new_list(0, NULL);
|
||||
for (int i=0, j=array_length(blobs_list_ret); i<j; i++) {
|
||||
color_blob_t *cb = array_at(blobs_list_ret, i);
|
||||
mp_obj_t blob_obj[10] = {
|
||||
mp_obj_new_int(cb->x),
|
||||
mp_obj_new_int(cb->y),
|
||||
mp_obj_new_int(cb->w),
|
||||
mp_obj_new_int(cb->h),
|
||||
mp_obj_new_int(cb->pixels),
|
||||
mp_obj_new_int(cb->cx),
|
||||
mp_obj_new_int(cb->cy),
|
||||
mp_obj_new_float(cb->rotation),
|
||||
mp_obj_new_int(cb->code),
|
||||
mp_obj_new_int(cb->count)
|
||||
};
|
||||
mp_obj_list_append(objects_list, mp_obj_new_tuple(10, blob_obj));
|
||||
}
|
||||
array_free(blobs_list_ret);
|
||||
return objects_list;
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_scale(mp_obj_t image_obj, mp_obj_t size_obj)
|
||||
|
||||
@ -33,10 +33,12 @@ while(True):
|
||||
while(diff):
|
||||
img = sensor.snapshot()
|
||||
img.difference("temp/bg.bmp")
|
||||
for blob_l in img.find_blobs([(20, 100, -128, 127, -128, 127)]):
|
||||
for blob in blob_l:
|
||||
# Over 100 pixels need to change to detect motion.
|
||||
if (diff and (blob[4] > 100)): diff -= 1
|
||||
stats = img.statistics()
|
||||
# Stats 5 is the max of the lighting color channel. The below code
|
||||
# triggers when the lighting max for the whole image goes above 10.
|
||||
# The lighting difference maximum should be zero normally.
|
||||
if (stats[5] > 10):
|
||||
diff -= 1
|
||||
|
||||
pyb.LED(BLUE_LED_PIN).off()
|
||||
print("Movement detected! Saving image...")
|
||||
|
||||
@ -37,10 +37,12 @@ while(True):
|
||||
while(diff):
|
||||
img = sensor.snapshot()
|
||||
img.difference("temp/bg.bmp")
|
||||
for blob_l in img.find_blobs([(20, 100, -128, 127, -128, 127)]):
|
||||
for blob in blob_l:
|
||||
# Over 100 pixels need to change to detect motion.
|
||||
if (diff and (blob[4] > 100)): diff -= 1
|
||||
stats = img.statistics()
|
||||
# Stats 5 is the max of the lighting color channel. The below code
|
||||
# triggers when the lighting max for the whole image goes above 10.
|
||||
# The lighting difference maximum should be zero normally.
|
||||
if (stats[5] > 10):
|
||||
diff -= 1
|
||||
|
||||
g = gif.Gif("example-%d.gif" % pyb.rng(), loop=True)
|
||||
|
||||
|
||||
@ -38,10 +38,12 @@ while(True):
|
||||
while(diff):
|
||||
img = sensor.snapshot()
|
||||
img.difference("temp/bg.bmp")
|
||||
for blob_l in img.find_blobs([(20, 100, -128, 127, -128, 127)]):
|
||||
for blob in blob_l:
|
||||
# Over 100 pixels need to change to detect motion.
|
||||
if (diff and (blob[4] > 100)): diff -= 1
|
||||
stats = img.statistics()
|
||||
# Stats 5 is the max of the lighting color channel. The below code
|
||||
# triggers when the lighting max for the whole image goes above 10.
|
||||
# The lighting difference maximum should be zero normally.
|
||||
if (stats[5] > 10):
|
||||
diff -= 1
|
||||
|
||||
m = mjpeg.Mjpeg("example-%d.mjpeg" % pyb.rng())
|
||||
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import sensor, time, pyb
|
||||
|
||||
led_r = pyb.LED(1)
|
||||
|
||||
sensor.reset()
|
||||
sensor.set_framesize(sensor.QVGA)
|
||||
sensor.set_pixformat(sensor.RGB565)
|
||||
@ -18,14 +16,10 @@ while (True):
|
||||
image = sensor.snapshot()
|
||||
|
||||
# Detect blobs in image
|
||||
blob_l = image.find_blobs([COLOR1])
|
||||
|
||||
led_r.off()
|
||||
blobs = image.find_blobs([COLOR1])
|
||||
|
||||
# Draw rectangles around detected blobs
|
||||
for blobs in blob_l:
|
||||
for r in blobs:
|
||||
if r[8]==1:
|
||||
led_r.on()
|
||||
image.draw_rectangle(r[0:4])
|
||||
for blob in blobs:
|
||||
image.draw_rectangle(blob[0:4])
|
||||
|
||||
print(clock.fps())
|
||||
|
||||
Loading…
Reference in New Issue
Block a user