Add Midpoint filter.

Has a bias value that allows you to control if its really a midpoint,
min, max filter, or something inbetween. Run at 160x120 or lower. 320x240
is slow (seems to be the case for all convoltions at that res).
This commit is contained in:
Kwabena W. Agyeman 2016-03-25 21:25:16 -04:00
parent b2e77e9dce
commit 978b4c12df
5 changed files with 121 additions and 3 deletions

View File

@ -139,6 +139,7 @@ OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/img/,\
rainbow_tab.o \
rgb2rgb_tab.o \
median.o \
midpoint.o \
point.o \
rectangle.o \
bmp.o \

View File

@ -42,6 +42,7 @@ SRCS += $(addprefix img/, \
rainbow_tab.c \
rgb2rgb_tab.c \
median.c \
midpoint.c \
point.c \
rectangle.c \
bmp.c \

View File

@ -460,13 +460,16 @@ void imlib_morph(image_t *img, const int ksize, const int8_t *krn, const float m
int32_t *imlib_histogram(image_t *img, rectangle_t *r);
void imlib_statistics(image_t *img, rectangle_t *r, statistics_t *out);
/* Image Filtering */
void imlib_midpoint_filter(image_t *img, const int ksize, const int bias);
void imlib_median_filter(image_t *src, int r);
/* Clustering functions */
array_t *cluster_kmeans(array_t *points, int k);
/* Image filtering functions */
int imlib_image_mean(struct image *src);
void imlib_histeq(struct image *src);
void imlib_median_filter(image_t *src, int r);
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);

95
src/omv/img/midpoint.c Normal file
View File

@ -0,0 +1,95 @@
/*
* This file is part of the OpenMV project.
* Copyright (c) 2013-2016 Kwabena W. Agyeman <kwagyeman@openmv.io>
* This work is licensed under the MIT license, see the file LICENSE for details.
*
* Min/Max/Midpoint Filtering.
*
*/
#include <string.h>
#include "imlib.h"
#include "fb_alloc.h"
// krn_s == 0 -> 1x1 kernel
// krn_s == 1 -> 3x3 kernel
// ...
// krn_s == n -> ((n*2)+1)x((n*2)+1) kernel
// bias == 0 to 256 -> 0.0 to 1.0 (0.0==min filter, 1.0==max filter)
void imlib_midpoint_filter(image_t *img, const int ksize, const int bias)
{
int min_bias = (256-bias);
int max_bias = bias;
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++) {
int min = 255, max = 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)) {
const uint8_t pixel = IM_GET_GS_PIXEL(img, x+k, y+j);
min = IM_MIN(min, pixel);
max = IM_MAX(max, pixel);
}
}
}
// We're writing into the buffer like if it were a window.
buffer[((y%brows)*img->w)+x] =
((min*min_bias)+(max*max_bias))>>8;
}
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++) {
int r_min = 255, r_max = 0;
int g_min = 255, g_max = 0;
int b_min = 255, b_max = 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)) {
const uint16_t pixel = IM_GET_RGB565_PIXEL(img, x+k, y+j);
int red = IM_R565(pixel);
int green = IM_G565(pixel);
int blue = IM_B565(pixel);
r_min = IM_MIN(r_min, red);
r_max = IM_MAX(r_max, red);
g_min = IM_MIN(g_min, green);
g_max = IM_MAX(g_max, green);
b_min = IM_MIN(b_min, blue);
b_max = IM_MAX(b_max, blue);
}
}
}
// We're writing into the buffer like if it were a window.
((uint16_t *) buffer)[((y%brows)*img->w)+x] =
IM_RGB565(((r_min*min_bias)+(r_max*max_bias))>>8,
((g_min*min_bias)+(g_max*max_bias))>>8,
((b_min*min_bias)+(b_max*max_bias))>>8);
}
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();
}

View File

@ -696,6 +696,20 @@ static mp_obj_t py_image_statistics(uint n_args, const mp_obj_t *args, mp_map_t
}
}
static mp_obj_t py_image_midpoint(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 arg_ksize = mp_obj_get_int(args[1]);
PY_ASSERT_TRUE_MSG(arg_ksize >= 0, "Kernel Size must be >= 0");
int bias = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bias), 0.5) * 256;
imlib_midpoint_filter(arg_img, arg_ksize, IM_MIN(IM_MAX(bias, 0), 256));
return mp_const_none;
}
static mp_obj_t py_image_scale(mp_obj_t image_obj, mp_obj_t size_obj)
{
int w,h;
@ -1182,6 +1196,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_difference_obj, py_image_difference);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_morph_obj, 3, py_image_morph);
/* Image Statistics */
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_statistics_obj, 1, py_image_statistics);
/* Image Filtering */
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_obj, 2, py_image_midpoint);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_median_obj, 1, py_image_median);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_scale_obj, py_image_scale);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_scaled_obj, py_image_scaled);
@ -1189,7 +1206,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_subimg_obj, py_image_subimg);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_blit_obj, py_image_blit);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_blend_obj, py_image_blend);
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_compress_obj, py_image_compress);
@ -1240,6 +1256,9 @@ static const mp_map_elem_t locals_dict_table[] = {
{MP_OBJ_NEW_QSTR(MP_QSTR_morph), (mp_obj_t)&py_image_morph_obj},
/* Image Statistics */
{MP_OBJ_NEW_QSTR(MP_QSTR_statistics), (mp_obj_t)&py_image_statistics_obj},
/* Image Filtering */
{MP_OBJ_NEW_QSTR(MP_QSTR_midpoint), (mp_obj_t)&py_image_midpoint_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_median), (mp_obj_t)&py_image_median_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_scale), (mp_obj_t)&py_image_scale_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_scaled), (mp_obj_t)&py_image_scaled_obj},
@ -1247,7 +1266,6 @@ static const mp_map_elem_t locals_dict_table[] = {
{MP_OBJ_NEW_QSTR(MP_QSTR_blit), (mp_obj_t)&py_image_blit_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_blend), (mp_obj_t)&py_image_blend_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_histeq), (mp_obj_t)&py_image_histeq_obj},
{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_compress), (mp_obj_t)&py_image_compress_obj},