mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Add adaptive thresholding to filters.
I still need to go back and optimizing and cleanup the code. I just wanted to get the feature in first.
This commit is contained in:
parent
7cec96a9db
commit
cbbead0785
@ -1130,10 +1130,11 @@ int imlib_image_mean(image_t *src); // grayscale only
|
||||
int imlib_image_std(image_t *src); // grayscale only
|
||||
|
||||
/* Image Filtering */
|
||||
void imlib_midpoint_filter(image_t *img, const int ksize, const int bias);
|
||||
void imlib_mean_filter(image_t *img, const int ksize);
|
||||
void imlib_mode_filter(image_t *img, const int ksize);
|
||||
void imlib_median_filter(image_t *img, const int ksize, const int percentile);
|
||||
void imlib_midpoint_filter(image_t *img, const int ksize, const int bias, bool threshold, int offset, bool invert);
|
||||
void imlib_mean_filter(image_t *img, const int ksize, bool threshold, int offset, bool invert);
|
||||
void imlib_mode_filter(image_t *img, const int ksize, bool threshold, int offset, bool invert);
|
||||
void imlib_median_filter(image_t *img, const int ksize, const int percentile, bool threshold, int offset, bool invert);
|
||||
void imlib_histeq(image_t *img);
|
||||
void imlib_mask_ellipse(image_t *img);
|
||||
|
||||
/* Template Matching */
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
// ...
|
||||
// krn_s == n -> ((n*2)+1)x((n*2)+1) kernel
|
||||
|
||||
void imlib_mean_filter(image_t *img, const int ksize)
|
||||
void imlib_mean_filter(image_t *img, const int ksize, bool threshold, int offset, bool invert)
|
||||
{
|
||||
int n = ((ksize*2)+1)*((ksize*2)+1);
|
||||
int brows = ksize + 1;
|
||||
@ -33,7 +33,8 @@ void imlib_mean_filter(image_t *img, const int ksize)
|
||||
}
|
||||
}
|
||||
// We're writing into the buffer like if it were a window.
|
||||
buffer[((y%brows)*img->w)+x] = acc/n;
|
||||
uint8_t pixel = acc/n;
|
||||
buffer[((y%brows)*img->w)+x] = (!threshold) ? pixel : ((((pixel-offset)<IM_GET_GS_PIXEL(img, x, y))^invert) ? 255 : 0);
|
||||
}
|
||||
if (y>=ksize) {
|
||||
memcpy(img->pixels+((y-ksize)*img->w),
|
||||
@ -63,7 +64,8 @@ void imlib_mean_filter(image_t *img, const int ksize)
|
||||
}
|
||||
}
|
||||
// We're writing into the buffer like if it were a window.
|
||||
((uint16_t *) buffer)[((y%brows)*img->w)+x] = IM_RGB565(r_acc/n, g_acc/n, b_acc/n);
|
||||
uint16_t pixel = IM_RGB565(r_acc/n, g_acc/n, b_acc/n);
|
||||
((uint16_t *) buffer)[((y%brows)*img->w)+x] = (!threshold) ? pixel : ((((COLOR_RGB565_TO_Y(pixel)-offset)<COLOR_RGB565_TO_Y(IM_GET_RGB565_PIXEL(img, x, y)))^invert) ? 65535 : 0);
|
||||
}
|
||||
if (y>=ksize) {
|
||||
memcpy(((uint16_t *) img->pixels)+((y-ksize)*img->w),
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
#include "fb_alloc.h"
|
||||
#include "fsort.h"
|
||||
|
||||
void imlib_median_filter(image_t *img, const int ksize, const int percentile)
|
||||
void imlib_median_filter(image_t *img, const int ksize, const int percentile, bool threshold, int offset, bool invert)
|
||||
{
|
||||
int n = ((ksize*2)+1)*((ksize*2)+1);
|
||||
int brows = ksize + 1;
|
||||
@ -34,7 +34,8 @@ void imlib_median_filter(image_t *img, const int ksize, const int percentile)
|
||||
fsort(data, n);
|
||||
int median = data[percentile];
|
||||
// We're writing into the buffer like if it were a window.
|
||||
buffer[((y%brows)*img->w)+x] = median;
|
||||
uint8_t pixel = median;
|
||||
buffer[((y%brows)*img->w)+x] = (!threshold) ? pixel : ((((pixel-offset)<IM_GET_GS_PIXEL(img, x, y))^invert) ? 255 : 0);
|
||||
}
|
||||
if (y>=ksize) {
|
||||
memcpy(img->pixels+((y-ksize)*img->w),
|
||||
@ -77,7 +78,8 @@ void imlib_median_filter(image_t *img, const int ksize, const int percentile)
|
||||
int g_median = g_data[percentile];
|
||||
int b_median = b_data[percentile];
|
||||
// We're writing into the buffer like if it were a window.
|
||||
((uint16_t *) buffer)[((y%brows)*img->w)+x] = IM_RGB565(r_median, g_median, b_median);
|
||||
uint16_t pixel = IM_RGB565(r_median, g_median, b_median);
|
||||
((uint16_t *) buffer)[((y%brows)*img->w)+x] = (!threshold) ? pixel : ((((COLOR_RGB565_TO_Y(pixel)-offset)<COLOR_RGB565_TO_Y(IM_GET_RGB565_PIXEL(img, x, y)))^invert) ? 65535 : 0);
|
||||
}
|
||||
if (y>=ksize) {
|
||||
memcpy(((uint16_t *) img->pixels)+((y-ksize)*img->w),
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
// 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)
|
||||
void imlib_midpoint_filter(image_t *img, const int ksize, const int bias, bool threshold, int offset, bool invert)
|
||||
{
|
||||
int min_bias = (256-bias);
|
||||
int max_bias = bias;
|
||||
@ -37,8 +37,8 @@ void imlib_midpoint_filter(image_t *img, const int ksize, const int bias)
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
int pixel = ((min*min_bias)+(max*max_bias))>>8;
|
||||
buffer[((y%brows)*img->w)+x] = (!threshold) ? pixel : ((((pixel-offset)<IM_GET_GS_PIXEL(img, x, y))^invert) ? 255 : 0);
|
||||
}
|
||||
if (y>=ksize) {
|
||||
memcpy(img->pixels+((y-ksize)*img->w),
|
||||
@ -74,10 +74,10 @@ void imlib_midpoint_filter(image_t *img, const int ksize, const int bias)
|
||||
}
|
||||
}
|
||||
// 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,
|
||||
uint16_t pixel = 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);
|
||||
((uint16_t *) buffer)[((y%brows)*img->w)+x] = (!threshold) ? pixel : ((((COLOR_RGB565_TO_Y(pixel)-offset)<COLOR_RGB565_TO_Y(IM_GET_RGB565_PIXEL(img, x, y)))^invert) ? 65535 : 0);
|
||||
}
|
||||
if (y>=ksize) {
|
||||
memcpy(((uint16_t *) img->pixels)+((y-ksize)*img->w),
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
// ...
|
||||
// krn_s == n -> ((n*2)+1)x((n*2)+1) kernel
|
||||
|
||||
void imlib_mode_filter(image_t *img, const int ksize)
|
||||
void imlib_mode_filter(image_t *img, const int ksize, bool threshold, int offset, bool invert)
|
||||
{
|
||||
int brows = ksize + 1;
|
||||
uint8_t *buffer = fb_alloc(img->w * brows * img->bpp);
|
||||
@ -38,7 +38,8 @@ void imlib_mode_filter(image_t *img, const int ksize)
|
||||
}
|
||||
}
|
||||
// We're writing into the buffer like if it were a window.
|
||||
buffer[((y%brows)*img->w)+x] = mode;
|
||||
uint8_t pixel = mode;
|
||||
buffer[((y%brows)*img->w)+x] = (!threshold) ? pixel : ((((pixel-offset)<IM_GET_GS_PIXEL(img, x, y))^invert) ? 255 : 0);
|
||||
}
|
||||
if (y>=ksize) {
|
||||
memcpy(img->pixels+((y-ksize)*img->w),
|
||||
@ -90,7 +91,8 @@ void imlib_mode_filter(image_t *img, const int ksize)
|
||||
}
|
||||
}
|
||||
// We're writing into the buffer like if it were a window.
|
||||
((uint16_t *) buffer)[((y%brows)*img->w)+x] = IM_RGB565(r_mode, g_mode, b_mode);
|
||||
uint16_t pixel = IM_RGB565(r_mode, g_mode, b_mode);
|
||||
((uint16_t *) buffer)[((y%brows)*img->w)+x] = (!threshold) ? pixel : ((((COLOR_RGB565_TO_Y(pixel)-offset)<COLOR_RGB565_TO_Y(IM_GET_RGB565_PIXEL(img, x, y)))^invert) ? 65535 : 0);
|
||||
}
|
||||
if (y>=ksize) {
|
||||
memcpy(((uint16_t *) img->pixels)+((y-ksize)*img->w),
|
||||
|
||||
@ -1206,33 +1206,45 @@ static mp_obj_t py_image_midpoint(uint n_args, const mp_obj_t *args, mp_map_t *k
|
||||
int arg_ksize = mp_obj_get_int(args[1]);
|
||||
PY_ASSERT_TRUE_MSG(arg_ksize >= 0, "Kernel Size must be >= 0");
|
||||
|
||||
int arg_threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false);
|
||||
int arg_offset = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0);
|
||||
int arg_invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false);
|
||||
|
||||
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));
|
||||
imlib_midpoint_filter(arg_img, arg_ksize, IM_MIN(IM_MAX(bias, 0), 256), arg_threshold, arg_offset, arg_invert);
|
||||
return args[0];
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_mean(mp_obj_t img_obj, mp_obj_t k_obj)
|
||||
static mp_obj_t py_image_mean(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
{
|
||||
image_t *arg_img = py_image_cobj(img_obj);
|
||||
image_t *arg_img = py_image_cobj(args[0]);
|
||||
PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported.");
|
||||
|
||||
int arg_ksize = mp_obj_get_int(k_obj);
|
||||
int arg_ksize = mp_obj_get_int(args[1]);
|
||||
PY_ASSERT_TRUE_MSG(arg_ksize >= 0, "Kernel Size must be >= 0");
|
||||
|
||||
imlib_mean_filter(arg_img, arg_ksize);
|
||||
return img_obj;
|
||||
int arg_threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false);
|
||||
int arg_offset = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0);
|
||||
int arg_invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false);
|
||||
|
||||
imlib_mean_filter(arg_img, arg_ksize, arg_threshold, arg_offset, arg_invert);
|
||||
return args[0];
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_mode(mp_obj_t img_obj, mp_obj_t k_obj)
|
||||
static mp_obj_t py_image_mode(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
{
|
||||
image_t *arg_img = py_image_cobj(img_obj);
|
||||
image_t *arg_img = py_image_cobj(args[0]);
|
||||
PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported.");
|
||||
|
||||
int arg_ksize = mp_obj_get_int(k_obj);
|
||||
int arg_ksize = mp_obj_get_int(args[1]);
|
||||
PY_ASSERT_TRUE_MSG(arg_ksize >= 0, "Kernel Size must be >= 0");
|
||||
|
||||
imlib_mode_filter(arg_img, arg_ksize);
|
||||
return img_obj;
|
||||
int arg_threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false);
|
||||
int arg_offset = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0);
|
||||
int arg_invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false);
|
||||
|
||||
imlib_mode_filter(arg_img, arg_ksize, arg_threshold, arg_offset, arg_invert);
|
||||
return args[0];
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_median(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
@ -1244,9 +1256,13 @@ static mp_obj_t py_image_median(uint n_args, const mp_obj_t *args, mp_map_t *kw_
|
||||
PY_ASSERT_TRUE_MSG(arg_ksize >= 0, "Kernel Size must be >= 0");
|
||||
PY_ASSERT_TRUE_MSG(arg_ksize <= 2, "Kernel Size must be <= 2");
|
||||
|
||||
int arg_threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false);
|
||||
int arg_offset = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0);
|
||||
int arg_invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false);
|
||||
|
||||
int n = ((arg_ksize*2)+1)*((arg_ksize*2)+1);
|
||||
int percentile = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_percentile), 0.5) * n;
|
||||
imlib_median_filter(arg_img, arg_ksize, IM_MIN(IM_MAX(percentile, 0), n-1));
|
||||
imlib_median_filter(arg_img, arg_ksize, IM_MIN(IM_MAX(percentile, 0), n-1), arg_threshold, arg_offset, arg_invert);
|
||||
return args[0];
|
||||
}
|
||||
|
||||
@ -4000,8 +4016,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_blend_obj, 2, py_image_blend);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_morph_obj, 3, py_image_morph);
|
||||
/* Image Filtering */
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_obj, 2, py_image_midpoint);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_mean_obj, py_image_mean);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_mode_obj, py_image_mode);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mean_obj, 2, py_image_mean);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mode_obj, 2, py_image_mode);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_median_obj, 2, py_image_median);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_gaussian_obj, 1, py_image_gaussian);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_chrominvar_obj, py_image_chrominvar);
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
# Mean Adaptive Threshold Filter Example
|
||||
#
|
||||
# This example shows off mean filtering with adaptive thresholding.
|
||||
# When mean(threshold=True) the mean() method adaptive thresholds the image
|
||||
# by comparing the mean of the pixels around a pixel, minus an offset, with that pixel.
|
||||
|
||||
import sensor, image, time
|
||||
|
||||
sensor.reset() # Initialize the camera sensor.
|
||||
sensor.set_pixformat(sensor.RGB565) # or sensor.GRAYSCALE
|
||||
sensor.set_framesize(sensor.QQVGA) # or sensor.QVGA (or others)
|
||||
sensor.skip_frames(time = 2000) # Let new settings take affect.
|
||||
clock = time.clock() # Tracks FPS.
|
||||
|
||||
while(True):
|
||||
clock.tick() # Track elapsed milliseconds between snapshots().
|
||||
img = sensor.snapshot() # Take a picture and return the image.
|
||||
|
||||
# The first argument is the kernel size. N coresponds to a ((N*2)+1)^2
|
||||
# kernel size. E.g. 1 == 3x3 kernel, 2 == 5x5 kernel, etc. Note: You
|
||||
# shouldn't ever need to use a value bigger than 2.
|
||||
img.mean(1, threshold=True, offset=5, invert=True)
|
||||
|
||||
print(clock.fps()) # Note: Your OpenMV Cam runs about half as fast while
|
||||
# connected to your computer. The FPS should increase once disconnected.
|
||||
@ -0,0 +1,27 @@
|
||||
# Median Adaptive Threshold Filter Example
|
||||
#
|
||||
# This example shows off median filtering with adaptive thresholding.
|
||||
# When median(threshold=True) the median() method adaptive thresholds the image
|
||||
# by comparing the median of the pixels around a pixel, minus an offset, with that pixel.
|
||||
|
||||
import sensor, image, time
|
||||
|
||||
sensor.reset() # Initialize the camera sensor.
|
||||
sensor.set_pixformat(sensor.RGB565) # or sensor.GRAYSCALE
|
||||
sensor.set_framesize(sensor.QQVGA) # or sensor.QVGA (or others)
|
||||
sensor.skip_frames(time = 2000) # Let new settings take affect.
|
||||
clock = time.clock() # Tracks FPS.
|
||||
|
||||
while(True):
|
||||
clock.tick() # Track elapsed milliseconds between snapshots().
|
||||
img = sensor.snapshot() # Take a picture and return the image.
|
||||
|
||||
# The first argument to the median filter is the kernel size, it can be
|
||||
# either 0, 1, or 2 for a 1x1, 3x3, or 5x5 kernel respectively. The second
|
||||
# argument "percentile" is the percentile number to choose from the NxN
|
||||
# neighborhood. 0.5 is the median, 0.25 is the lower quartile, and 0.75
|
||||
# would be the upper quartile.
|
||||
img.median(1, percentile=0.5, threshold=True, offset=5, invert=True)
|
||||
|
||||
print(clock.fps()) # Note: Your OpenMV Cam runs about half as fast while
|
||||
# connected to your computer. The FPS should increase once disconnected.
|
||||
@ -0,0 +1,28 @@
|
||||
# Midpoint Adaptive Threshold Filter Example
|
||||
#
|
||||
# This example shows off midpoint filtering with adaptive thresholding.
|
||||
# When midpoint(threshold=True) the midpoint() method adaptive thresholds the image
|
||||
# by comparing the midpoint of the pixels around a pixel, minus an offset, with that pixel.
|
||||
|
||||
import sensor, image, time
|
||||
|
||||
sensor.reset() # Initialize the camera sensor.
|
||||
sensor.set_pixformat(sensor.RGB565) # or sensor.GRAYSCALE
|
||||
sensor.set_framesize(sensor.QQVGA) # or sensor.QVGA (or others)
|
||||
sensor.skip_frames(time = 2000) # Let new settings take affect.
|
||||
clock = time.clock() # Tracks FPS.
|
||||
|
||||
while(True):
|
||||
clock.tick() # Track elapsed milliseconds between snapshots().
|
||||
img = sensor.snapshot() # Take a picture and return the image.
|
||||
|
||||
# The first argument is the kernel size. N coresponds to a ((N*2)+1)^2
|
||||
# kernel size. E.g. 1 == 3x3 kernel, 2 == 5x5 kernel, etc. Note: You
|
||||
# shouldn't ever need to use a value bigger than 2. The "bias" argument
|
||||
# lets you select between min and max blending. 0.5 == midpoint filter,
|
||||
# 0.0 == min filter, and 1.0 == max filter. Note that the min filter
|
||||
# makes images darker while the max filter makes images lighter.
|
||||
img.midpoint(1, bias=0.5, threshold=True, offset=5, invert=True)
|
||||
|
||||
print(clock.fps()) # Note: Your OpenMV Cam runs about half as fast while
|
||||
# connected to your computer. The FPS should increase once disconnected.
|
||||
@ -0,0 +1,25 @@
|
||||
# Mode Adaptive Threshold Filter Example
|
||||
#
|
||||
# This example shows off mode filtering with adaptive thresholding.
|
||||
# When mode(threshold=True) the mode() method adaptive thresholds the image
|
||||
# by comparing the mode of the pixels around a pixel, minus an offset, with that pixel.
|
||||
# Avoid using the mode filter on RGB565 images. It will cause artifacts on image edges...
|
||||
|
||||
import sensor, image, time
|
||||
|
||||
sensor.reset() # Initialize the camera sensor.
|
||||
sensor.set_pixformat(sensor.GRAYSCALE) # or sensor.RGB565
|
||||
sensor.set_framesize(sensor.QQVGA) # or sensor.QVGA (or others)
|
||||
sensor.skip_frames(time = 2000) # Let new settings take affect.
|
||||
clock = time.clock() # Tracks FPS.
|
||||
|
||||
while(True):
|
||||
clock.tick() # Track elapsed milliseconds between snapshots().
|
||||
img = sensor.snapshot() # Take a picture and return the image.
|
||||
|
||||
# The only argument to the median filter is the kernel size, it can be
|
||||
# either 0, 1, or 2 for a 1x1, 3x3, or 5x5 kernel respectively.
|
||||
img.mode(1, threshold=True, offset=5, invert=True)
|
||||
|
||||
print(clock.fps()) # Note: Your OpenMV Cam runs about half as fast while
|
||||
# connected to your computer. The FPS should increase once disconnected.
|
||||
Loading…
Reference in New Issue
Block a user