mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
commit
b5c20cd022
@ -126,36 +126,6 @@ static void imlib_read_pixels(FIL *fp, image_t *img, int line_start, int line_en
|
||||
}
|
||||
}
|
||||
|
||||
// Main Ram = 196,608 bytes
|
||||
// -
|
||||
// struct framebuffer = 20 bytes
|
||||
// FB_JPEG_OFFS_SIZE = 1,024 bytes
|
||||
// GRAYSCALE 320x240x1 image = 76,800 bytes
|
||||
// fb_alloc = 4 bytes
|
||||
// flash cache = 16,384 bytes
|
||||
// =
|
||||
// 102,376 bytes
|
||||
// /
|
||||
// GRAYSCALE 320x1 lines
|
||||
// =
|
||||
// 319 GRAYSCALE 320x1 lines
|
||||
#define GS_LINE_BUFFER_SIZE (64) // double rgb565
|
||||
|
||||
// Main Ram = 196,608 bytes
|
||||
// -
|
||||
// struct framebuffer = 20 bytes
|
||||
// FB_JPEG_OFFS_SIZE = 1,024 bytes
|
||||
// RGB565 320x240x2 image = 153,600 bytes
|
||||
// fb_alloc = 4 bytes
|
||||
// flash cache = 16,384 bytes
|
||||
// =
|
||||
// 25,576 bytes
|
||||
// /
|
||||
// RGB565 320x2 lines
|
||||
// =
|
||||
// 39 RGB565 320x2 lines
|
||||
#define RGB565_LINE_BUFFER_SIZE (32)
|
||||
|
||||
void imlib_image_operation(image_t *img, const char *path, image_t *other, line_op_t op)
|
||||
{
|
||||
if (path) {
|
||||
@ -631,6 +601,102 @@ float imlib_orientation_degrees(image_t *img, int *sum, int *x_center, int *y_ce
|
||||
return (imlib_orientation_radians(img, sum, x_center, y_center, r) * 180.0) / M_PI;
|
||||
}
|
||||
|
||||
static void imlib_erode_dilate(image_t *img, int ksize, int threshold, int e_or_d)
|
||||
{
|
||||
int brows = ksize + 1;
|
||||
uint8_t *buffer = fb_alloc(img->w * brows * img->bpp);
|
||||
if (IM_IS_GS(img)) {
|
||||
for (int y=0; y<img->h; y++) {
|
||||
for (int x=0; x<img->w; x++) {
|
||||
// We're writing into the buffer like if it were a window.
|
||||
int buffer_idx = ((y%brows)*img->w)+x;
|
||||
buffer[buffer_idx] = IM_GET_GS_PIXEL(img, x, y);
|
||||
if ((!!buffer[buffer_idx]) == e_or_d) {
|
||||
continue; // short circuit (makes this very fast - usually)
|
||||
}
|
||||
int acc = 0;
|
||||
for (int j=-ksize; j<=ksize; j++) {
|
||||
for (int k=-ksize; k<=ksize; k++) {
|
||||
if (IM_X_INSIDE(img, x+k) && IM_Y_INSIDE(img, y+j)) {
|
||||
acc += !!IM_GET_GS_PIXEL(img, x+k, y+j);
|
||||
} else { // outer pixels should not affect result.
|
||||
acc += e_or_d ? 0 : 1;
|
||||
// 1 for erode prevents acc from being lower.
|
||||
// 0 for dilate prevents acc from being higher.
|
||||
}
|
||||
}
|
||||
}
|
||||
buffer[buffer_idx] = (acc >= threshold) ? 0xFF : 0;
|
||||
}
|
||||
if (y>=ksize) {
|
||||
memcpy(img->pixels+((y-ksize)*img->w),
|
||||
buffer+(((y-ksize)%brows)*img->w),
|
||||
img->w * sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
for (int y=img->h-ksize; y<img->h; y++) {
|
||||
memcpy(img->pixels+(y*img->w),
|
||||
buffer+((y%brows)*img->w),
|
||||
img->w * sizeof(uint8_t));
|
||||
}
|
||||
} else {
|
||||
for (int y=0; y<img->h; y++) {
|
||||
for (int x=0; x<img->w; x++) {
|
||||
// We're writing into the buffer like if it were a window.
|
||||
int buffer_idx = ((y%brows)*img->w)+x;
|
||||
((uint16_t *) buffer)[buffer_idx] = IM_GET_RGB565_PIXEL(img, x, y);
|
||||
if ((!!((uint16_t *) buffer)[buffer_idx]) == e_or_d) {
|
||||
continue; // short circuit (makes this very fast - usually)
|
||||
}
|
||||
int acc = 0;
|
||||
for (int j=-ksize; j<=ksize; j++) {
|
||||
for (int k=-ksize; k<=ksize; k++) {
|
||||
if (IM_X_INSIDE(img, x+k) && IM_Y_INSIDE(img, y+j)) {
|
||||
acc += !!IM_GET_RGB565_PIXEL(img, x+k, y+j);
|
||||
} else { // outer pixels should not affect result.
|
||||
acc += e_or_d ? 0 : 1;
|
||||
// 1 for erode prevents acc from being lower.
|
||||
// 0 for dilate prevents acc from being higher.
|
||||
}
|
||||
}
|
||||
}
|
||||
((uint16_t *) buffer)[buffer_idx] = (acc >= threshold) ? 0xFFFF : 0;
|
||||
}
|
||||
if (y>=ksize) {
|
||||
memcpy(((uint16_t *) img->pixels)+((y-ksize)*img->w),
|
||||
((uint16_t *) buffer)+(((y-ksize)%brows)*img->w),
|
||||
img->w * sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
for (int y=img->h-ksize; y<img->h; y++) {
|
||||
memcpy(((uint16_t *) img->pixels)+(y*img->w),
|
||||
((uint16_t *) buffer)+((y%brows)*img->w),
|
||||
img->w * sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
fb_free();
|
||||
}
|
||||
|
||||
void imlib_erode(image_t *img, int ksize, int threshold)
|
||||
{
|
||||
// Threshold should be equal to ((ksize*2)+1)*((ksize*2)+1)
|
||||
// for normal operation. E.g. for ksize==3 -> threshold==9
|
||||
// Basically you're adjusting the number of pixels that
|
||||
// must be set in the kernel for the output to be 1.
|
||||
// Erode normally requires all pixels to be 1.
|
||||
imlib_erode_dilate(img, ksize, threshold, 0);
|
||||
}
|
||||
|
||||
void imlib_dilate(image_t *img, int ksize, int threshold)
|
||||
{
|
||||
// Threshold should be equal to 1
|
||||
// for normal operation. E.g. for ksize==3 -> threshold==1
|
||||
// Basically you're adjusting the number of pixels that
|
||||
// must be set in the kernel for the output to be 1.
|
||||
// Dilate normally requires one pixel to be 1.
|
||||
imlib_erode_dilate(img, ksize, threshold, 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void imlib_negate(image_t *img)
|
||||
@ -782,70 +848,6 @@ void imlib_grayscale_to_rgb565(struct image *image)
|
||||
#endif
|
||||
}
|
||||
|
||||
void imlib_erode(image_t *src, int ksize)
|
||||
{
|
||||
int c = ksize/2;// center pixel
|
||||
int k_rows = (ksize+1)*2;
|
||||
uint8_t *dst = fb_alloc0(src->w * k_rows);
|
||||
|
||||
for (int y=1; y<src->h-ksize; y++) {
|
||||
for (int x=1; x<src->w-ksize; x++) {
|
||||
int i = y*src->w+x;
|
||||
int di = (y%k_rows)*src->w+x;
|
||||
if ((dst[di] = src->pixels[i])==0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j=-c; j<c; j++) {
|
||||
for (int k=-c; k<c; k++) {
|
||||
if (src->pixels[(y+j)*src->w+x+k]==0) {
|
||||
dst[di]=0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
done:;
|
||||
}
|
||||
|
||||
if ((y+1)%k_rows==0) {
|
||||
memcpy(src->pixels+((y/k_rows)*k_rows*src->w), dst, src->w*k_rows);
|
||||
}
|
||||
}
|
||||
fb_free();
|
||||
}
|
||||
|
||||
void imlib_dilate(image_t *src, int ksize)
|
||||
{
|
||||
int c = ksize/2;// center pixel
|
||||
int k_rows = (ksize+1)*2;
|
||||
uint8_t *dst = fb_alloc0(src->w * k_rows);
|
||||
|
||||
for (int y=1; y<src->h-ksize; y++) {
|
||||
for (int x=1; x<src->w-ksize; x++) {
|
||||
int i = y*src->w+x;
|
||||
int di = (y%k_rows)*src->w+x;
|
||||
if ((dst[di] = src->pixels[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j=-c; j<c; j++) {
|
||||
for (int k=-c; k<c; k++) {
|
||||
if (src->pixels[(y+j)*src->w+x+k]) {
|
||||
dst[di]=src->pixels[(y+j)*src->w+x+k];
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
done:;
|
||||
}
|
||||
|
||||
if ((y+1)%k_rows==0) {
|
||||
memcpy(src->pixels+((y/k_rows)*k_rows*src->w), dst, src->w*k_rows);
|
||||
}
|
||||
}
|
||||
fb_free();
|
||||
}
|
||||
|
||||
#ifdef OPENMV1
|
||||
void imlib_threshold(image_t *src, image_t *dst, color_t *color, int color_size, int threshold)
|
||||
{
|
||||
|
||||
@ -146,6 +146,36 @@ extern const uint8_t g826_table[256];
|
||||
__typeof__ (img1) _img1 = (img1); \
|
||||
(_img0->w==_img1->w)&&(_img0->h==_img1->h)&&(_img0->bpp==_img1->bpp); })
|
||||
|
||||
// Main Ram = 196,608 bytes
|
||||
// -
|
||||
// struct framebuffer = 20 bytes
|
||||
// FB_JPEG_OFFS_SIZE = 1,024 bytes
|
||||
// GRAYSCALE 320x240x1 image = 76,800 bytes
|
||||
// fb_alloc = 4 bytes
|
||||
// flash cache = 16,384 bytes
|
||||
// =
|
||||
// 102,376 bytes
|
||||
// /
|
||||
// GRAYSCALE 320x1 lines
|
||||
// =
|
||||
// 319 GRAYSCALE 320x1 lines
|
||||
#define GS_LINE_BUFFER_SIZE (64) // double rgb565
|
||||
|
||||
// Main Ram = 196,608 bytes
|
||||
// -
|
||||
// struct framebuffer = 20 bytes
|
||||
// FB_JPEG_OFFS_SIZE = 1,024 bytes
|
||||
// RGB565 320x240x2 image = 153,600 bytes
|
||||
// fb_alloc = 4 bytes
|
||||
// flash cache = 16,384 bytes
|
||||
// =
|
||||
// 25,576 bytes
|
||||
// /
|
||||
// RGB565 320x2 lines
|
||||
// =
|
||||
// 39 RGB565 320x2 lines
|
||||
#define RGB565_LINE_BUFFER_SIZE (32)
|
||||
|
||||
typedef struct size {
|
||||
int w;
|
||||
int h;
|
||||
@ -370,6 +400,8 @@ int imlib_pixels(image_t *img, rectangle_t *r);
|
||||
int imlib_centroid(image_t *img, int *x_center, int *y_center, rectangle_t *r);
|
||||
float imlib_orientation_radians(image_t *img, int *sum, int *x_center, int *y_center, rectangle_t *r);
|
||||
float imlib_orientation_degrees(image_t *img, int *sum, int *x_center, int *y_center, rectangle_t *r);
|
||||
void imlib_erode(image_t *img, int ksize, int threshold);
|
||||
void imlib_dilate(image_t *img, int ksize, int threshold);
|
||||
|
||||
/* Background Subtraction (Frame Differencing) functions */
|
||||
void imlib_negate(image_t *img);
|
||||
@ -391,8 +423,6 @@ void imlib_rgb_to_hsv(struct color *rgb, struct color *hsv);
|
||||
int imlib_image_mean(struct image *src);
|
||||
void imlib_histeq(struct image *src);
|
||||
void imlib_median_filter(image_t *src, int r);
|
||||
void imlib_erode(image_t *src, int ksize);
|
||||
void imlib_dilate(image_t *src, int ksize);
|
||||
void imlib_threshold(image_t *src, image_t *dst, color_t *color, int color_size, int threshold);
|
||||
void imlib_rainbow(image_t *src, struct image *dst);
|
||||
array_t *imlib_count_blobs(struct image *image);
|
||||
|
||||
@ -575,6 +575,34 @@ static mp_obj_t py_image_orientation_degrees(uint n_args, const mp_obj_t *args,
|
||||
{mp_obj_new_int(sum), mp_obj_new_int(x), mp_obj_new_int(y), mp_obj_new_float(o)});
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_erode(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
{
|
||||
image_t *arg_img = py_image_cobj(args[0]);
|
||||
PY_ASSERT_FALSE_MSG(IM_IS_JPEG(arg_img),
|
||||
"Operation not supported on JPEG");
|
||||
|
||||
int ksize = mp_obj_get_int(args[1]);
|
||||
PY_ASSERT_TRUE_MSG(ksize >= 0, "Kernel Size must be >= 0");
|
||||
imlib_erode(arg_img, ksize,
|
||||
py_helper_lookup_int(kw_args,
|
||||
MP_OBJ_NEW_QSTR(MP_QSTR_threshold), ((ksize*2)+1)*((ksize*2)+1)));
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_dilate(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
{
|
||||
image_t *arg_img = py_image_cobj(args[0]);
|
||||
PY_ASSERT_FALSE_MSG(IM_IS_JPEG(arg_img),
|
||||
"Operation not supported on JPEG");
|
||||
|
||||
int ksize = mp_obj_get_int(args[1]);
|
||||
PY_ASSERT_TRUE_MSG(ksize >= 0, "Kernel Size must be >= 0");
|
||||
imlib_dilate(arg_img, ksize,
|
||||
py_helper_lookup_int(kw_args,
|
||||
MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 1));
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_negate(mp_obj_t img_obj)
|
||||
{
|
||||
image_t *arg_img = py_image_cobj(img_obj);
|
||||
@ -845,32 +873,6 @@ static mp_obj_t py_image_compress(mp_obj_t image_obj, mp_obj_t quality)
|
||||
return py_image_from_struct(&cimage);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_find_blobs(mp_obj_t image_obj)
|
||||
{
|
||||
// Get image pointer
|
||||
@ -1103,6 +1105,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_pixels_obj, 1, py_image_pixels);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_centroid_obj, 1, py_image_centroid);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_orientation_radians_obj, 1, py_image_orientation_radians);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_orientation_degrees_obj, 1, py_image_orientation_degrees);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_erode_obj, 2, py_image_erode);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_dilate_obj, 2, py_image_dilate);
|
||||
/* Background Subtraction (Frame Differencing) functions */
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_negate_obj, py_image_negate);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_difference_obj, py_image_difference);
|
||||
@ -1116,8 +1120,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_histeq_obj, py_image_histeq);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_median_obj, 1, py_image_median);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_threshold_obj, py_image_threshold);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_rainbow_obj, py_image_rainbow);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_erode_obj, py_image_erode);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_dilate_obj, py_image_dilate);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_compress_obj, py_image_compress);
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_find_blobs_obj, py_image_find_blobs);
|
||||
@ -1157,6 +1159,8 @@ static const mp_map_elem_t locals_dict_table[] = {
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_centroid), (mp_obj_t)&py_image_centroid_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_orientation_radians), (mp_obj_t)&py_image_orientation_radians_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_orientation_degrees), (mp_obj_t)&py_image_orientation_degrees_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_erode), (mp_obj_t)&py_image_erode_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_dilate), (mp_obj_t)&py_image_dilate_obj},
|
||||
/* Background Subtraction (Frame Differencing) functions */
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_negate), (mp_obj_t)&py_image_negate_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_difference), (mp_obj_t)&py_image_difference_obj},
|
||||
@ -1170,10 +1174,7 @@ static const mp_map_elem_t locals_dict_table[] = {
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_median), (mp_obj_t)&py_image_median_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_threshold), (mp_obj_t)&py_image_threshold_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_rainbow), (mp_obj_t)&py_image_rainbow_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_erode), (mp_obj_t)&py_image_erode_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_dilate), (mp_obj_t)&py_image_dilate_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_compress), (mp_obj_t)&py_image_compress_obj},
|
||||
|
||||
/* objects/feature detection */
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_find_blobs), (mp_obj_t)&py_image_find_blobs_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_find_template), (mp_obj_t)&py_image_find_template_obj},
|
||||
|
||||
24
usr/tests/test_erode_and_dilate.py
Normal file
24
usr/tests/test_erode_and_dilate.py
Normal file
@ -0,0 +1,24 @@
|
||||
import pyb, sensor, image, math
|
||||
sensor.reset()
|
||||
sensor.set_framesize(sensor.QVGA)
|
||||
grayscale_thres = (170, 255)
|
||||
rgb565_thres = (70, 100, -128, 127, -128, 127)
|
||||
while(True):
|
||||
sensor.set_pixformat(sensor.GRAYSCALE)
|
||||
for i in range(100):
|
||||
img = sensor.snapshot()
|
||||
img.binary([grayscale_thres])
|
||||
img.erode(2)
|
||||
for i in range(100):
|
||||
img = sensor.snapshot()
|
||||
img.binary([grayscale_thres])
|
||||
img.dilate(2)
|
||||
sensor.set_pixformat(sensor.RGB565)
|
||||
for i in range(100):
|
||||
img = sensor.snapshot()
|
||||
img.binary([rgb565_thres])
|
||||
img.erode(2)
|
||||
for i in range(100):
|
||||
img = sensor.snapshot()
|
||||
img.binary([rgb565_thres])
|
||||
img.dilate(2)
|
||||
Loading…
Reference in New Issue
Block a user