mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Merge pull request #328 from kwagyeman/master
More image filtering stuff
This commit is contained in:
commit
11a9610902
@ -13,6 +13,26 @@ void imlib_binary(image_t *img, list_t *thresholds, bool invert, bool zero)
|
|||||||
|
|
||||||
switch(img->bpp) {
|
switch(img->bpp) {
|
||||||
case IMAGE_BPP_BINARY: {
|
case IMAGE_BPP_BINARY: {
|
||||||
|
if (!zero) {
|
||||||
|
for (uint32_t *start = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, 0),
|
||||||
|
*end = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, img->h);
|
||||||
|
start < end; start++) {
|
||||||
|
for (int i = 0; i < UINT32_T_BITS; i++) {
|
||||||
|
IMAGE_PUT_BINARY_PIXEL_FAST(start, i,
|
||||||
|
COLOR_THRESHOLD_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(start, i), &lnk_data, invert)
|
||||||
|
? COLOR_BINARY_MAX : COLOR_BINARY_MIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (uint32_t *start = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, 0),
|
||||||
|
*end = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, img->h);
|
||||||
|
start < end; start++) {
|
||||||
|
for (int i = 0; i < UINT32_T_BITS; i++) {
|
||||||
|
if (COLOR_THRESHOLD_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(start, i), &lnk_data, invert))
|
||||||
|
IMAGE_PUT_BINARY_PIXEL_FAST(start, i, COLOR_BINARY_MIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IMAGE_BPP_GRAYSCALE: {
|
case IMAGE_BPP_GRAYSCALE: {
|
||||||
@ -27,8 +47,8 @@ void imlib_binary(image_t *img, list_t *thresholds, bool invert, bool zero)
|
|||||||
for (uint8_t *start = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, 0),
|
for (uint8_t *start = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, 0),
|
||||||
*end = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, img->h);
|
*end = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, img->h);
|
||||||
start < end; start++) {
|
start < end; start++) {
|
||||||
if (COLOR_THRESHOLD_GRAYSCALE(*start, &lnk_data, invert)) *start =
|
if (COLOR_THRESHOLD_GRAYSCALE(*start, &lnk_data, invert))
|
||||||
COLOR_GRAYSCALE_BINARY_MIN;
|
*start = COLOR_GRAYSCALE_BINARY_MIN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -45,8 +65,8 @@ void imlib_binary(image_t *img, list_t *thresholds, bool invert, bool zero)
|
|||||||
for (uint16_t *start = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, 0),
|
for (uint16_t *start = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, 0),
|
||||||
*end = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, img->h);
|
*end = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, img->h);
|
||||||
start < end; start++) {
|
start < end; start++) {
|
||||||
if (COLOR_THRESHOLD_RGB565(*start, &lnk_data, invert)) *start =
|
if (COLOR_THRESHOLD_RGB565(*start, &lnk_data, invert))
|
||||||
COLOR_RGB565_BINARY_MIN;
|
*start = COLOR_RGB565_BINARY_MIN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -711,3 +731,41 @@ void imlib_dilate(image_t *img, int ksize, int threshold, image_t *mask)
|
|||||||
// Dilate normally requires one pixel to be 1.
|
// Dilate normally requires one pixel to be 1.
|
||||||
imlib_erode_dilate(img, ksize, threshold, 1, mask);
|
imlib_erode_dilate(img, ksize, threshold, 1, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void imlib_open(image_t *img, int ksize, int threshold, image_t *mask)
|
||||||
|
{
|
||||||
|
imlib_erode(img, ksize, (((ksize*2)+1)*((ksize*2)+1))-1 - threshold, mask);
|
||||||
|
imlib_dilate(img, ksize, 0 + threshold, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void imlib_close(image_t *img, int ksize, int threshold, image_t *mask)
|
||||||
|
{
|
||||||
|
imlib_dilate(img, ksize, 0 + threshold, mask);
|
||||||
|
imlib_erode(img, ksize, (((ksize*2)+1)*((ksize*2)+1))-1 - threshold, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void imlib_top_hat(image_t *img, int ksize, int threshold, image_t *mask)
|
||||||
|
{
|
||||||
|
image_t temp;
|
||||||
|
temp.w = img->w;
|
||||||
|
temp.h = img->h;
|
||||||
|
temp.bpp = img->bpp;
|
||||||
|
temp.data = fb_alloc(image_size(img));
|
||||||
|
memcpy(temp.data, img->data, image_size(img));
|
||||||
|
imlib_open(&temp, ksize, threshold, mask);
|
||||||
|
imlib_difference(img, NULL, &temp, 0, mask);
|
||||||
|
fb_free();
|
||||||
|
}
|
||||||
|
|
||||||
|
void imlib_black_hat(image_t *img, int ksize, int threshold, image_t *mask)
|
||||||
|
{
|
||||||
|
image_t temp;
|
||||||
|
temp.w = img->w;
|
||||||
|
temp.h = img->h;
|
||||||
|
temp.bpp = img->bpp;
|
||||||
|
temp.data = fb_alloc(image_size(img));
|
||||||
|
memcpy(temp.data, img->data, image_size(img));
|
||||||
|
imlib_close(&temp, ksize, threshold, mask);
|
||||||
|
imlib_difference(img, NULL, &temp, 0, mask);
|
||||||
|
fb_free();
|
||||||
|
}
|
||||||
|
|||||||
@ -10,7 +10,28 @@ void imlib_histeq(image_t *img)
|
|||||||
{
|
{
|
||||||
switch(img->bpp) {
|
switch(img->bpp) {
|
||||||
case IMAGE_BPP_BINARY: {
|
case IMAGE_BPP_BINARY: {
|
||||||
// Can't run this on a binary image.
|
int a = img->w * img->h;
|
||||||
|
float s = (COLOR_BINARY_MAX-COLOR_BINARY_MIN) / ((float) a);
|
||||||
|
uint32_t *hist = fb_alloc0((COLOR_BINARY_MAX-COLOR_BINARY_MIN+1)*sizeof(uint32_t));
|
||||||
|
uint32_t *pixels = (uint32_t *) img->data;
|
||||||
|
|
||||||
|
// Compute the image histogram
|
||||||
|
for (int i=0; i<a; i++) {
|
||||||
|
hist[pixels[i]-COLOR_BINARY_MIN] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the CDF
|
||||||
|
for (int i=0, sum=0; i<(COLOR_BINARY_MAX-COLOR_BINARY_MIN+1); i++) {
|
||||||
|
sum += hist[i];
|
||||||
|
hist[i] = sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<a; i++) {
|
||||||
|
int pixel = pixels[i];
|
||||||
|
pixels[i] = (s * hist[pixel-COLOR_BINARY_MIN]) + COLOR_BINARY_MIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_free();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IMAGE_BPP_GRAYSCALE: {
|
case IMAGE_BPP_GRAYSCALE: {
|
||||||
@ -88,7 +109,58 @@ void imlib_mean_filter(image_t *img, const int ksize, bool threshold, int offset
|
|||||||
|
|
||||||
switch(img->bpp) {
|
switch(img->bpp) {
|
||||||
case IMAGE_BPP_BINARY: {
|
case IMAGE_BPP_BINARY: {
|
||||||
// Can't run this on a binary image.
|
buf.data = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img) * brows);
|
||||||
|
|
||||||
|
for (int y = 0, yy = img->h; y < yy; y++) {
|
||||||
|
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y);
|
||||||
|
uint32_t *buf_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows));
|
||||||
|
|
||||||
|
for (int x = 0, xx = img->w; x < xx; x++) {
|
||||||
|
if (mask && (!image_get_mask_pixel(mask, x, y))) {
|
||||||
|
IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x));
|
||||||
|
continue; // Short circuit.
|
||||||
|
}
|
||||||
|
|
||||||
|
int acc = 0;
|
||||||
|
|
||||||
|
for (int j = -ksize; j <= ksize; j++) {
|
||||||
|
uint32_t *k_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img,
|
||||||
|
IM_MIN(IM_MAX(y + j, 0), (img->h - 1)));
|
||||||
|
|
||||||
|
for (int k = -ksize; k <= ksize; k++) {
|
||||||
|
acc += IMAGE_GET_BINARY_PIXEL_FAST(k_row_ptr,
|
||||||
|
IM_MIN(IM_MAX(x + k, 0), (img->w - 1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int pixel = fast_roundf(acc * over_n);
|
||||||
|
|
||||||
|
if (threshold) {
|
||||||
|
if (((pixel - offset) < IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)) ^ invert) {
|
||||||
|
pixel = COLOR_BINARY_MAX;
|
||||||
|
} else {
|
||||||
|
pixel = COLOR_BINARY_MIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y >= ksize) { // Transfer buffer lines...
|
||||||
|
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, (y - ksize)),
|
||||||
|
IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
|
||||||
|
IMAGE_BINARY_LINE_LEN_BYTES(img));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy any remaining lines from the buffer image...
|
||||||
|
for (int y = img->h - ksize, yy = img->h; y < yy; y++) {
|
||||||
|
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y),
|
||||||
|
IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)),
|
||||||
|
IMAGE_BINARY_LINE_LEN_BYTES(img));
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_free();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IMAGE_BPP_GRAYSCALE: {
|
case IMAGE_BPP_GRAYSCALE: {
|
||||||
@ -224,7 +296,62 @@ void imlib_median_filter(image_t *img, const int ksize, float percentile, bool t
|
|||||||
|
|
||||||
switch(img->bpp) {
|
switch(img->bpp) {
|
||||||
case IMAGE_BPP_BINARY: {
|
case IMAGE_BPP_BINARY: {
|
||||||
// Can't run this on a binary image.
|
buf.data = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img) * brows);
|
||||||
|
int *data = fb_alloc(n*sizeof(int));
|
||||||
|
|
||||||
|
for (int y = 0, yy = img->h; y < yy; y++) {
|
||||||
|
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y);
|
||||||
|
uint32_t *buf_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows));
|
||||||
|
|
||||||
|
for (int x = 0, xx = img->w; x < xx; x++) {
|
||||||
|
if (mask && (!image_get_mask_pixel(mask, x, y))) {
|
||||||
|
IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x));
|
||||||
|
continue; // Short circuit.
|
||||||
|
}
|
||||||
|
|
||||||
|
int *data_ptr = data;
|
||||||
|
|
||||||
|
for (int j = -ksize; j <= ksize; j++) {
|
||||||
|
uint32_t *k_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img,
|
||||||
|
IM_MIN(IM_MAX(y + j, 0), (img->h - 1)));
|
||||||
|
|
||||||
|
for (int k = -ksize; k <= ksize; k++) {
|
||||||
|
*data_ptr++ = IMAGE_GET_BINARY_PIXEL_FAST(k_row_ptr,
|
||||||
|
IM_MIN(IM_MAX(x + k, 0), (img->w - 1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fsort(data, n);
|
||||||
|
|
||||||
|
int pixel = data[int_percentile];
|
||||||
|
|
||||||
|
if (threshold) {
|
||||||
|
if (((pixel - offset) < IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)) ^ invert) {
|
||||||
|
pixel = COLOR_BINARY_MAX;
|
||||||
|
} else {
|
||||||
|
pixel = COLOR_BINARY_MIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y >= ksize) { // Transfer buffer lines...
|
||||||
|
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, (y - ksize)),
|
||||||
|
IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
|
||||||
|
IMAGE_BINARY_LINE_LEN_BYTES(img));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy any remaining lines from the buffer image...
|
||||||
|
for (int y = img->h - ksize, yy = img->h; y < yy; y++) {
|
||||||
|
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y),
|
||||||
|
IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)),
|
||||||
|
IMAGE_BINARY_LINE_LEN_BYTES(img));
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_free();
|
||||||
|
fb_free();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IMAGE_BPP_GRAYSCALE: {
|
case IMAGE_BPP_GRAYSCALE: {
|
||||||
@ -372,7 +499,68 @@ void imlib_mode_filter(image_t *img, const int ksize, bool threshold, int offset
|
|||||||
|
|
||||||
switch(img->bpp) {
|
switch(img->bpp) {
|
||||||
case IMAGE_BPP_BINARY: {
|
case IMAGE_BPP_BINARY: {
|
||||||
// Can't run this on a binary image.
|
buf.data = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img) * brows);
|
||||||
|
int *bins = fb_alloc((COLOR_BINARY_MAX-COLOR_BINARY_MIN+1)*sizeof(int));
|
||||||
|
|
||||||
|
for (int y = 0, yy = img->h; y < yy; y++) {
|
||||||
|
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y);
|
||||||
|
uint32_t *buf_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows));
|
||||||
|
|
||||||
|
for (int x = 0, xx = img->w; x < xx; x++) {
|
||||||
|
if (mask && (!image_get_mask_pixel(mask, x, y))) {
|
||||||
|
IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x));
|
||||||
|
continue; // Short circuit.
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(bins, 0, (COLOR_BINARY_MAX-COLOR_BINARY_MIN+1)*sizeof(int));
|
||||||
|
|
||||||
|
int mcount = 0, mode = 0;
|
||||||
|
|
||||||
|
for (int j = -ksize; j <= ksize; j++) {
|
||||||
|
uint32_t *k_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img,
|
||||||
|
IM_MIN(IM_MAX(y + j, 0), (img->h - 1)));
|
||||||
|
|
||||||
|
for (int k = -ksize; k <= ksize; k++) {
|
||||||
|
int pixel = IMAGE_GET_BINARY_PIXEL_FAST(k_row_ptr,
|
||||||
|
IM_MIN(IM_MAX(x + k, 0), (img->w - 1)));
|
||||||
|
bins[pixel]++;
|
||||||
|
|
||||||
|
if (bins[pixel] > mcount) {
|
||||||
|
mcount = bins[pixel];
|
||||||
|
mode = pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int pixel = mode;
|
||||||
|
|
||||||
|
if (threshold) {
|
||||||
|
if (((pixel - offset) < IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)) ^ invert) {
|
||||||
|
pixel = COLOR_BINARY_MAX;
|
||||||
|
} else {
|
||||||
|
pixel = COLOR_BINARY_MIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y >= ksize) { // Transfer buffer lines...
|
||||||
|
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, (y - ksize)),
|
||||||
|
IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
|
||||||
|
IMAGE_BINARY_LINE_LEN_BYTES(img));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy any remaining lines from the buffer image...
|
||||||
|
for (int y = img->h - ksize, yy = img->h; y < yy; y++) {
|
||||||
|
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y),
|
||||||
|
IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)),
|
||||||
|
IMAGE_BINARY_LINE_LEN_BYTES(img));
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_free();
|
||||||
|
fb_free();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IMAGE_BPP_GRAYSCALE: {
|
case IMAGE_BPP_GRAYSCALE: {
|
||||||
@ -546,7 +734,60 @@ void imlib_midpoint_filter(image_t *img, const int ksize, float bias, bool thres
|
|||||||
|
|
||||||
switch(img->bpp) {
|
switch(img->bpp) {
|
||||||
case IMAGE_BPP_BINARY: {
|
case IMAGE_BPP_BINARY: {
|
||||||
// Can't run this on a binary image.
|
buf.data = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img) * brows);
|
||||||
|
|
||||||
|
for (int y = 0, yy = img->h; y < yy; y++) {
|
||||||
|
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y);
|
||||||
|
uint32_t *buf_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows));
|
||||||
|
|
||||||
|
for (int x = 0, xx = img->w; x < xx; x++) {
|
||||||
|
if (mask && (!image_get_mask_pixel(mask, x, y))) {
|
||||||
|
IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x));
|
||||||
|
continue; // Short circuit.
|
||||||
|
}
|
||||||
|
|
||||||
|
int min = COLOR_BINARY_MAX, max = COLOR_BINARY_MIN;
|
||||||
|
|
||||||
|
for (int j = -ksize; j <= ksize; j++) {
|
||||||
|
uint32_t *k_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img,
|
||||||
|
IM_MIN(IM_MAX(y + j, 0), (img->h - 1)));
|
||||||
|
|
||||||
|
for (int k = -ksize; k <= ksize; k++) {
|
||||||
|
int pixel = IMAGE_GET_BINARY_PIXEL_FAST(k_row_ptr,
|
||||||
|
IM_MIN(IM_MAX(x + k, 0), (img->w - 1)));
|
||||||
|
min = IM_MIN(min, pixel);
|
||||||
|
max = IM_MAX(max, pixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int pixel = fast_roundf((min*min_bias)+(max*max_bias));
|
||||||
|
|
||||||
|
if (threshold) {
|
||||||
|
if (((pixel - offset) < IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)) ^ invert) {
|
||||||
|
pixel = COLOR_BINARY_MAX;
|
||||||
|
} else {
|
||||||
|
pixel = COLOR_BINARY_MIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y >= ksize) { // Transfer buffer lines...
|
||||||
|
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, (y - ksize)),
|
||||||
|
IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
|
||||||
|
IMAGE_BINARY_LINE_LEN_BYTES(img));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy any remaining lines from the buffer image...
|
||||||
|
for (int y = img->h - ksize, yy = img->h; y < yy; y++) {
|
||||||
|
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y),
|
||||||
|
IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)),
|
||||||
|
IMAGE_BINARY_LINE_LEN_BYTES(img));
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_free();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IMAGE_BPP_GRAYSCALE: {
|
case IMAGE_BPP_GRAYSCALE: {
|
||||||
@ -692,7 +933,58 @@ void imlib_morph(image_t *img, const int ksize, const int *krn, const float m, c
|
|||||||
|
|
||||||
switch(img->bpp) {
|
switch(img->bpp) {
|
||||||
case IMAGE_BPP_BINARY: {
|
case IMAGE_BPP_BINARY: {
|
||||||
// Can't run this on a binary image.
|
buf.data = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img) * brows);
|
||||||
|
|
||||||
|
for (int y = 0, yy = img->h; y < yy; y++) {
|
||||||
|
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y);
|
||||||
|
uint32_t *buf_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows));
|
||||||
|
|
||||||
|
for (int x = 0, xx = img->w; x < xx; x++) {
|
||||||
|
if (mask && (!image_get_mask_pixel(mask, x, y))) {
|
||||||
|
IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x));
|
||||||
|
continue; // Short circuit.
|
||||||
|
}
|
||||||
|
|
||||||
|
int acc = 0, ptr = 0;
|
||||||
|
|
||||||
|
for (int j = -ksize; j <= ksize; j++) {
|
||||||
|
uint32_t *k_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img,
|
||||||
|
IM_MIN(IM_MAX(y + j, 0), (img->h - 1)));
|
||||||
|
|
||||||
|
for (int k = -ksize; k <= ksize; k++) {
|
||||||
|
acc += krn[ptr++] * IMAGE_GET_BINARY_PIXEL_FAST(k_row_ptr,
|
||||||
|
IM_MIN(IM_MAX(x + k, 0), (img->w - 1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int pixel = IM_MAX(IM_MIN(fast_roundf(acc * m) + b, COLOR_BINARY_MAX), COLOR_BINARY_MIN);
|
||||||
|
|
||||||
|
if (threshold) {
|
||||||
|
if (((pixel - offset) < IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)) ^ invert) {
|
||||||
|
pixel = COLOR_BINARY_MAX;
|
||||||
|
} else {
|
||||||
|
pixel = COLOR_BINARY_MIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y >= ksize) { // Transfer buffer lines...
|
||||||
|
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, (y - ksize)),
|
||||||
|
IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
|
||||||
|
IMAGE_BINARY_LINE_LEN_BYTES(img));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy any remaining lines from the buffer image...
|
||||||
|
for (int y = img->h - ksize, yy = img->h; y < yy; y++) {
|
||||||
|
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y),
|
||||||
|
IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)),
|
||||||
|
IMAGE_BINARY_LINE_LEN_BYTES(img));
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_free();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IMAGE_BPP_GRAYSCALE: {
|
case IMAGE_BPP_GRAYSCALE: {
|
||||||
@ -815,3 +1107,285 @@ void imlib_morph(image_t *img, const int ksize, const int *krn, const float m, c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static float gaussian(int x, float sigma)
|
||||||
|
{
|
||||||
|
return fast_expf((x * x) / (-2.0f * sigma * sigma)) / (sigma * 2.506628f); // sqrt(2 * PI)
|
||||||
|
}
|
||||||
|
|
||||||
|
static float distance(int x, int y)
|
||||||
|
{
|
||||||
|
return fast_sqrtf((x * x) + (y * y));
|
||||||
|
}
|
||||||
|
|
||||||
|
void imlib_bilateral_filter(image_t *img, const int ksize, float color_sigma, float space_sigma, bool threshold, int offset, bool invert, image_t *mask)
|
||||||
|
{
|
||||||
|
int brows = ksize + 1;
|
||||||
|
image_t buf;
|
||||||
|
buf.w = img->w;
|
||||||
|
buf.h = brows;
|
||||||
|
buf.bpp = img->bpp;
|
||||||
|
|
||||||
|
switch(img->bpp) {
|
||||||
|
case IMAGE_BPP_BINARY: {
|
||||||
|
buf.data = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img) * brows);
|
||||||
|
|
||||||
|
float *gi_lut = fb_alloc((COLOR_BINARY_MAX - COLOR_BINARY_MIN + 1) * sizeof(float));
|
||||||
|
|
||||||
|
for (int i = COLOR_BINARY_MIN; i <= COLOR_BINARY_MAX; i++) {
|
||||||
|
gi_lut[i] = gaussian(i, color_sigma);
|
||||||
|
}
|
||||||
|
|
||||||
|
int n = (ksize * 2) + 1;
|
||||||
|
float *gs_lut = fb_alloc(n * n * sizeof(float));
|
||||||
|
|
||||||
|
for (int y = -ksize; y <= ksize; y++) {
|
||||||
|
for (int x = -ksize; x <= ksize; x++) {
|
||||||
|
gs_lut[(n * (y + ksize)) + (x + ksize)] = gaussian(distance(x, y), space_sigma);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = 0, yy = img->h; y < yy; y++) {
|
||||||
|
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y);
|
||||||
|
uint32_t *buf_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows));
|
||||||
|
|
||||||
|
for (int x = 0, xx = img->w; x < xx; x++) {
|
||||||
|
if (mask && (!image_get_mask_pixel(mask, x, y))) {
|
||||||
|
IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x));
|
||||||
|
continue; // Short circuit.
|
||||||
|
}
|
||||||
|
|
||||||
|
int this_pixel = IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x);
|
||||||
|
float i_acc = 0, w_acc = 0;
|
||||||
|
|
||||||
|
for (int j = -ksize; j <= ksize; j++) {
|
||||||
|
uint32_t *k_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img,
|
||||||
|
IM_MIN(IM_MAX(y + j, 0), (img->h - 1)));
|
||||||
|
|
||||||
|
for (int k = -ksize; k <= ksize; k++) {
|
||||||
|
int pixel = IMAGE_GET_BINARY_PIXEL_FAST(k_row_ptr,
|
||||||
|
IM_MIN(IM_MAX(x + k, 0), (img->w - 1)));
|
||||||
|
float w = gi_lut[abs(this_pixel - pixel)] * gs_lut[(n * (j + ksize)) + (k + ksize)];
|
||||||
|
i_acc += pixel * w;
|
||||||
|
w_acc += w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int pixel = fast_roundf(IM_MIN(IM_DIV(i_acc, w_acc), COLOR_BINARY_MAX));
|
||||||
|
|
||||||
|
if (threshold) {
|
||||||
|
if (((pixel - offset) < IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)) ^ invert) {
|
||||||
|
pixel = COLOR_BINARY_MAX;
|
||||||
|
} else {
|
||||||
|
pixel = COLOR_BINARY_MIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y >= ksize) { // Transfer buffer lines...
|
||||||
|
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, (y - ksize)),
|
||||||
|
IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
|
||||||
|
IMAGE_BINARY_LINE_LEN_BYTES(img));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy any remaining lines from the buffer image...
|
||||||
|
for (int y = img->h - ksize, yy = img->h; y < yy; y++) {
|
||||||
|
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y),
|
||||||
|
IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)),
|
||||||
|
IMAGE_BINARY_LINE_LEN_BYTES(img));
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_free();
|
||||||
|
fb_free();
|
||||||
|
fb_free();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IMAGE_BPP_GRAYSCALE: {
|
||||||
|
buf.data = fb_alloc(IMAGE_GRAYSCALE_LINE_LEN_BYTES(img) * brows);
|
||||||
|
|
||||||
|
float *gi_lut = fb_alloc((COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN + 1) * sizeof(float));
|
||||||
|
|
||||||
|
for (int i = COLOR_GRAYSCALE_MIN; i <= COLOR_GRAYSCALE_MAX; i++) {
|
||||||
|
gi_lut[i] = gaussian(i, color_sigma);
|
||||||
|
}
|
||||||
|
|
||||||
|
int n = (ksize * 2) + 1;
|
||||||
|
float *gs_lut = fb_alloc(n * n * sizeof(float));
|
||||||
|
|
||||||
|
for (int y = -ksize; y <= ksize; y++) {
|
||||||
|
for (int x = -ksize; x <= ksize; x++) {
|
||||||
|
gs_lut[(n * (y + ksize)) + (x + ksize)] = gaussian(distance(x, y), space_sigma);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = 0, yy = img->h; y < yy; y++) {
|
||||||
|
uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y);
|
||||||
|
uint8_t *buf_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows));
|
||||||
|
|
||||||
|
for (int x = 0, xx = img->w; x < xx; x++) {
|
||||||
|
if (mask && (!image_get_mask_pixel(mask, x, y))) {
|
||||||
|
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x));
|
||||||
|
continue; // Short circuit.
|
||||||
|
}
|
||||||
|
|
||||||
|
int this_pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x);
|
||||||
|
float i_acc = 0, w_acc = 0;
|
||||||
|
|
||||||
|
for (int j = -ksize; j <= ksize; j++) {
|
||||||
|
uint8_t *k_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img,
|
||||||
|
IM_MIN(IM_MAX(y + j, 0), (img->h - 1)));
|
||||||
|
|
||||||
|
for (int k = -ksize; k <= ksize; k++) {
|
||||||
|
int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(k_row_ptr,
|
||||||
|
IM_MIN(IM_MAX(x + k, 0), (img->w - 1)));
|
||||||
|
float w = gi_lut[abs(this_pixel - pixel)] * gs_lut[(n * (j + ksize)) + (k + ksize)];
|
||||||
|
i_acc += pixel * w;
|
||||||
|
w_acc += w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int pixel = fast_roundf(IM_MIN(IM_DIV(i_acc, w_acc), COLOR_GRAYSCALE_MAX));
|
||||||
|
|
||||||
|
if (threshold) {
|
||||||
|
if (((pixel - offset) < IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)) ^ invert) {
|
||||||
|
pixel = COLOR_GRAYSCALE_BINARY_MAX;
|
||||||
|
} else {
|
||||||
|
pixel = COLOR_GRAYSCALE_BINARY_MIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y >= ksize) { // Transfer buffer lines...
|
||||||
|
memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, (y - ksize)),
|
||||||
|
IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
|
||||||
|
IMAGE_GRAYSCALE_LINE_LEN_BYTES(img));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy any remaining lines from the buffer image...
|
||||||
|
for (int y = img->h - ksize, yy = img->h; y < yy; y++) {
|
||||||
|
memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y),
|
||||||
|
IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)),
|
||||||
|
IMAGE_GRAYSCALE_LINE_LEN_BYTES(img));
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_free();
|
||||||
|
fb_free();
|
||||||
|
fb_free();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IMAGE_BPP_RGB565: {
|
||||||
|
buf.data = fb_alloc(IMAGE_RGB565_LINE_LEN_BYTES(img) * brows);
|
||||||
|
|
||||||
|
float *r_gi_lut = fb_alloc((COLOR_R5_MAX - COLOR_R5_MIN + 1) * sizeof(float));
|
||||||
|
float *g_gi_lut = fb_alloc((COLOR_G6_MAX - COLOR_G6_MIN + 1) * sizeof(float));
|
||||||
|
float *b_gi_lut = fb_alloc((COLOR_B5_MAX - COLOR_B5_MIN + 1) * sizeof(float));
|
||||||
|
|
||||||
|
for (int i = COLOR_R5_MIN; i <= COLOR_R5_MAX; i++) {
|
||||||
|
r_gi_lut[i] = gaussian(i, color_sigma);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = COLOR_G6_MIN; i <= COLOR_G6_MAX; i++) {
|
||||||
|
g_gi_lut[i] = gaussian(i, color_sigma);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = COLOR_B5_MIN; i <= COLOR_B5_MAX; i++) {
|
||||||
|
b_gi_lut[i] = gaussian(i, color_sigma);
|
||||||
|
}
|
||||||
|
|
||||||
|
int n = (ksize * 2) + 1;
|
||||||
|
float *gs_lut = fb_alloc(n * n * sizeof(float));
|
||||||
|
|
||||||
|
for (int y = -ksize; y <= ksize; y++) {
|
||||||
|
for (int x = -ksize; x <= ksize; x++) {
|
||||||
|
gs_lut[(n * (y + ksize)) + (x + ksize)] = gaussian(distance(x, y), space_sigma);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = 0, yy = img->h; y < yy; y++) {
|
||||||
|
uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);
|
||||||
|
uint16_t *buf_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows));
|
||||||
|
|
||||||
|
for (int x = 0, xx = img->w; x < xx; x++) {
|
||||||
|
if (mask && (!image_get_mask_pixel(mask, x, y))) {
|
||||||
|
IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x));
|
||||||
|
continue; // Short circuit.
|
||||||
|
}
|
||||||
|
|
||||||
|
int this_pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x);
|
||||||
|
int r_this_pixel = COLOR_RGB565_TO_R5(this_pixel);
|
||||||
|
int g_this_pixel = COLOR_RGB565_TO_G6(this_pixel);
|
||||||
|
int b_this_pixel = COLOR_RGB565_TO_B5(this_pixel);
|
||||||
|
float r_i_acc = 0, r_w_acc = 0;
|
||||||
|
float g_i_acc = 0, g_w_acc = 0;
|
||||||
|
float b_i_acc = 0, b_w_acc = 0;
|
||||||
|
|
||||||
|
for (int j = -ksize; j <= ksize; j++) {
|
||||||
|
uint16_t *k_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img,
|
||||||
|
IM_MIN(IM_MAX(y + j, 0), (img->h - 1)));
|
||||||
|
|
||||||
|
for (int k = -ksize; k <= ksize; k++) {
|
||||||
|
int pixel = IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr,
|
||||||
|
IM_MIN(IM_MAX(x + k, 0), (img->w - 1)));
|
||||||
|
int r_pixel = COLOR_RGB565_TO_R5(pixel);
|
||||||
|
int g_pixel = COLOR_RGB565_TO_G6(pixel);
|
||||||
|
int b_pixel = COLOR_RGB565_TO_B5(pixel);
|
||||||
|
float gs = gs_lut[(n * (j + ksize)) + (k + ksize)];
|
||||||
|
float r_w = r_gi_lut[abs(r_this_pixel - r_pixel)] * gs;
|
||||||
|
float g_w = g_gi_lut[abs(g_this_pixel - g_pixel)] * gs;
|
||||||
|
float b_w = b_gi_lut[abs(b_this_pixel - b_pixel)] * gs;
|
||||||
|
r_i_acc += r_pixel * r_w;
|
||||||
|
r_w_acc += r_w;
|
||||||
|
g_i_acc += g_pixel * g_w;
|
||||||
|
g_w_acc += g_w;
|
||||||
|
b_i_acc += b_pixel * b_w;
|
||||||
|
b_w_acc += b_w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int pixel = COLOR_R5_G6_B5_TO_RGB565(fast_roundf(IM_MIN(IM_DIV(r_i_acc, r_w_acc), COLOR_R5_MAX)),
|
||||||
|
fast_roundf(IM_MIN(IM_DIV(g_i_acc, g_w_acc), COLOR_G6_MAX)),
|
||||||
|
fast_roundf(IM_MIN(IM_DIV(b_i_acc, b_w_acc), COLOR_B5_MAX)));
|
||||||
|
|
||||||
|
if (threshold) {
|
||||||
|
if (((COLOR_RGB565_TO_Y(pixel) - offset) < COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x))) ^ invert) {
|
||||||
|
pixel = COLOR_RGB565_BINARY_MAX;
|
||||||
|
} else {
|
||||||
|
pixel = COLOR_RGB565_BINARY_MIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y >= ksize) { // Transfer buffer lines...
|
||||||
|
memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, (y - ksize)),
|
||||||
|
IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
|
||||||
|
IMAGE_RGB565_LINE_LEN_BYTES(img));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy any remaining lines from the buffer image...
|
||||||
|
for (int y = img->h - ksize, yy = img->h; y < yy; y++) {
|
||||||
|
memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y),
|
||||||
|
IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)),
|
||||||
|
IMAGE_RGB565_LINE_LEN_BYTES(img));
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_free();
|
||||||
|
fb_free();
|
||||||
|
fb_free();
|
||||||
|
fb_free();
|
||||||
|
fb_free();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -127,7 +127,13 @@ typedef struct color_thresholds_list_lnk_data
|
|||||||
}
|
}
|
||||||
color_thresholds_list_lnk_data_t;
|
color_thresholds_list_lnk_data_t;
|
||||||
|
|
||||||
#define COLOR_THRESHOLD_BINARY(pixel, threshold, invert) ((pixel) ^ (invert))
|
#define COLOR_THRESHOLD_BINARY(pixel, threshold, invert) \
|
||||||
|
({ \
|
||||||
|
__typeof__ (pixel) _pixel = (pixel); \
|
||||||
|
__typeof__ (threshold) _threshold = (threshold); \
|
||||||
|
__typeof__ (invert) _invert = (invert); \
|
||||||
|
((_threshold->LMin <= _pixel) && (_pixel <= _threshold->LMax)) ^ _invert; \
|
||||||
|
})
|
||||||
|
|
||||||
#define COLOR_THRESHOLD_GRAYSCALE(pixel, threshold, invert) \
|
#define COLOR_THRESHOLD_GRAYSCALE(pixel, threshold, invert) \
|
||||||
({ \
|
({ \
|
||||||
@ -1222,6 +1228,10 @@ void imlib_b_xor(image_t *img, const char *path, image_t *other, int scalar, ima
|
|||||||
void imlib_b_xnor(image_t *img, const char *path, image_t *other, int scalar, image_t *mask);
|
void imlib_b_xnor(image_t *img, const char *path, image_t *other, int scalar, image_t *mask);
|
||||||
void imlib_erode(image_t *img, int ksize, int threshold, image_t *mask);
|
void imlib_erode(image_t *img, int ksize, int threshold, image_t *mask);
|
||||||
void imlib_dilate(image_t *img, int ksize, int threshold, image_t *mask);
|
void imlib_dilate(image_t *img, int ksize, int threshold, image_t *mask);
|
||||||
|
void imlib_open(image_t *img, int ksize, int threshold, image_t *mask);
|
||||||
|
void imlib_close(image_t *img, int ksize, int threshold, image_t *mask);
|
||||||
|
void imlib_top_hat(image_t *img, int ksize, int threshold, image_t *mask);
|
||||||
|
void imlib_black_hat(image_t *img, int ksize, int threshold, image_t *mask);
|
||||||
// Math Functions
|
// Math Functions
|
||||||
void imlib_negate(image_t *img);
|
void imlib_negate(image_t *img);
|
||||||
void imlib_replace(image_t *img, const char *path, image_t *other, int scalar, bool hmirror, bool vflip);
|
void imlib_replace(image_t *img, const char *path, image_t *other, int scalar, bool hmirror, bool vflip);
|
||||||
@ -1240,6 +1250,7 @@ void imlib_median_filter(image_t *img, const int ksize, float percentile, bool t
|
|||||||
void imlib_mode_filter(image_t *img, const int ksize, bool threshold, int offset, bool invert, image_t *mask);
|
void imlib_mode_filter(image_t *img, const int ksize, bool threshold, int offset, bool invert, image_t *mask);
|
||||||
void imlib_midpoint_filter(image_t *img, const int ksize, float bias, bool threshold, int offset, bool invert, image_t *mask);
|
void imlib_midpoint_filter(image_t *img, const int ksize, float bias, bool threshold, int offset, bool invert, image_t *mask);
|
||||||
void imlib_morph(image_t *img, const int ksize, const int *krn, const float m, const int b, bool threshold, int offset, bool invert, image_t *mask);
|
void imlib_morph(image_t *img, const int ksize, const int *krn, const float m, const int b, bool threshold, int offset, bool invert, image_t *mask);
|
||||||
|
void imlib_bilateral_filter(image_t *img, const int ksize, float color_sigma, float space_sigma, bool threshold, int offset, bool invert, image_t *mask);
|
||||||
// Image Correction
|
// Image Correction
|
||||||
void imlib_logpolar_int(image_t *dst, image_t *src, rectangle_t *roi, bool linear, bool reverse); // helper/internal
|
void imlib_logpolar_int(image_t *dst, image_t *src, rectangle_t *roi, bool linear, bool reverse); // helper/internal
|
||||||
void imlib_logpolar(image_t *img, bool linear, bool reverse);
|
void imlib_logpolar(image_t *img, bool linear, bool reverse);
|
||||||
|
|||||||
@ -1401,6 +1401,70 @@ STATIC mp_obj_t py_image_dilate(uint n_args, const mp_obj_t *args, mp_map_t *kw_
|
|||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_dilate_obj, 2, py_image_dilate);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_dilate_obj, 2, py_image_dilate);
|
||||||
|
|
||||||
|
STATIC mp_obj_t py_image_open(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||||
|
{
|
||||||
|
int arg_ksize =
|
||||||
|
py_helper_arg_to_ksize(args[1]);
|
||||||
|
int arg_threshold =
|
||||||
|
py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 0);
|
||||||
|
image_t *arg_msk =
|
||||||
|
py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args);
|
||||||
|
|
||||||
|
fb_alloc_mark();
|
||||||
|
imlib_open(py_helper_arg_to_image_mutable(args[0]), arg_ksize, arg_threshold, arg_msk);
|
||||||
|
fb_alloc_free_till_mark();
|
||||||
|
return args[0];
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_open_obj, 2, py_image_open);
|
||||||
|
|
||||||
|
STATIC mp_obj_t py_image_close(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||||
|
{
|
||||||
|
int arg_ksize =
|
||||||
|
py_helper_arg_to_ksize(args[1]);
|
||||||
|
int arg_threshold =
|
||||||
|
py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 0);
|
||||||
|
image_t *arg_msk =
|
||||||
|
py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args);
|
||||||
|
|
||||||
|
fb_alloc_mark();
|
||||||
|
imlib_close(py_helper_arg_to_image_mutable(args[0]), arg_ksize, arg_threshold, arg_msk);
|
||||||
|
fb_alloc_free_till_mark();
|
||||||
|
return args[0];
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_close_obj, 2, py_image_close);
|
||||||
|
|
||||||
|
STATIC mp_obj_t py_image_top_hat(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||||
|
{
|
||||||
|
int arg_ksize =
|
||||||
|
py_helper_arg_to_ksize(args[1]);
|
||||||
|
int arg_threshold =
|
||||||
|
py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 0);
|
||||||
|
image_t *arg_msk =
|
||||||
|
py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args);
|
||||||
|
|
||||||
|
fb_alloc_mark();
|
||||||
|
imlib_top_hat(py_helper_arg_to_image_mutable(args[0]), arg_ksize, arg_threshold, arg_msk);
|
||||||
|
fb_alloc_free_till_mark();
|
||||||
|
return args[0];
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_top_hat_obj, 2, py_image_top_hat);
|
||||||
|
|
||||||
|
STATIC mp_obj_t py_image_black_hat(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||||
|
{
|
||||||
|
int arg_ksize =
|
||||||
|
py_helper_arg_to_ksize(args[1]);
|
||||||
|
int arg_threshold =
|
||||||
|
py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 0);
|
||||||
|
image_t *arg_msk =
|
||||||
|
py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args);
|
||||||
|
|
||||||
|
fb_alloc_mark();
|
||||||
|
imlib_black_hat(py_helper_arg_to_image_mutable(args[0]), arg_ksize, arg_threshold, arg_msk);
|
||||||
|
fb_alloc_free_till_mark();
|
||||||
|
return args[0];
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_black_hat_obj, 2, py_image_black_hat);
|
||||||
|
|
||||||
///////////////
|
///////////////
|
||||||
// Math Methods
|
// Math Methods
|
||||||
///////////////
|
///////////////
|
||||||
@ -1917,6 +1981,34 @@ STATIC mp_obj_t py_image_laplacian(uint n_args, const mp_obj_t *args, mp_map_t *
|
|||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_laplacian_obj, 2, py_image_laplacian);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_laplacian_obj, 2, py_image_laplacian);
|
||||||
|
|
||||||
|
STATIC mp_obj_t py_image_bilateral(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]);
|
||||||
|
int arg_ksize =
|
||||||
|
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), 6);
|
||||||
|
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), 6);
|
||||||
|
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 =
|
||||||
|
py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0);
|
||||||
|
bool arg_invert =
|
||||||
|
py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false);
|
||||||
|
image_t *arg_msk =
|
||||||
|
py_helper_keyword_to_image_mutable_mask(n_args, args, 7, kw_args);
|
||||||
|
|
||||||
|
fb_alloc_mark();
|
||||||
|
imlib_bilateral_filter(arg_img, arg_ksize, arg_color_sigma, arg_space_sigma, arg_threshold, arg_offset, arg_invert, arg_msk);
|
||||||
|
fb_alloc_free_till_mark();
|
||||||
|
return args[0];
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_bilateral_obj, 2, py_image_bilateral);
|
||||||
|
|
||||||
/////////////////////////
|
/////////////////////////
|
||||||
// Shadow Removal Methods
|
// Shadow Removal Methods
|
||||||
/////////////////////////
|
/////////////////////////
|
||||||
@ -4819,6 +4911,10 @@ static const mp_rom_map_elem_t locals_dict_table[] = {
|
|||||||
{MP_ROM_QSTR(MP_QSTR_b_xnor), MP_ROM_PTR(&py_image_b_xnor_obj)},
|
{MP_ROM_QSTR(MP_QSTR_b_xnor), MP_ROM_PTR(&py_image_b_xnor_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_erode), MP_ROM_PTR(&py_image_erode_obj)},
|
{MP_ROM_QSTR(MP_QSTR_erode), MP_ROM_PTR(&py_image_erode_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_dilate), MP_ROM_PTR(&py_image_dilate_obj)},
|
{MP_ROM_QSTR(MP_QSTR_dilate), MP_ROM_PTR(&py_image_dilate_obj)},
|
||||||
|
{MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&py_image_open_obj)},
|
||||||
|
{MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&py_image_close_obj)},
|
||||||
|
{MP_ROM_QSTR(MP_QSTR_top_hat), MP_ROM_PTR(&py_image_top_hat_obj)},
|
||||||
|
{MP_ROM_QSTR(MP_QSTR_black_hat), MP_ROM_PTR(&py_image_black_hat_obj)},
|
||||||
/* Math Methods */
|
/* Math Methods */
|
||||||
{MP_ROM_QSTR(MP_QSTR_negate), MP_ROM_PTR(&py_image_negate_obj)},
|
{MP_ROM_QSTR(MP_QSTR_negate), MP_ROM_PTR(&py_image_negate_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&py_image_replace_obj)},
|
{MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&py_image_replace_obj)},
|
||||||
@ -4841,6 +4937,7 @@ static const mp_rom_map_elem_t locals_dict_table[] = {
|
|||||||
{MP_ROM_QSTR(MP_QSTR_gaussian), MP_ROM_PTR(&py_image_gaussian_obj)},
|
{MP_ROM_QSTR(MP_QSTR_gaussian), MP_ROM_PTR(&py_image_gaussian_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_gaussian_blur), MP_ROM_PTR(&py_image_gaussian_obj)},
|
{MP_ROM_QSTR(MP_QSTR_gaussian_blur), MP_ROM_PTR(&py_image_gaussian_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_laplacian), MP_ROM_PTR(&py_image_laplacian_obj)},
|
{MP_ROM_QSTR(MP_QSTR_laplacian), MP_ROM_PTR(&py_image_laplacian_obj)},
|
||||||
|
{MP_ROM_QSTR(MP_QSTR_bilateral), MP_ROM_PTR(&py_image_bilateral_obj)},
|
||||||
/* Shadow Removal Methods */
|
/* Shadow Removal Methods */
|
||||||
#ifdef IMLIB_ENABLE_REMOVE_SHADOWS
|
#ifdef IMLIB_ENABLE_REMOVE_SHADOWS
|
||||||
{MP_ROM_QSTR(MP_QSTR_remove_shadows), MP_ROM_PTR(&py_image_remove_shadows_obj)},
|
{MP_ROM_QSTR(MP_QSTR_remove_shadows), MP_ROM_PTR(&py_image_remove_shadows_obj)},
|
||||||
|
|||||||
@ -408,6 +408,26 @@ Q(dilate)
|
|||||||
// duplicate Q(threshold)
|
// duplicate Q(threshold)
|
||||||
// duplicate Q(mask)
|
// duplicate Q(mask)
|
||||||
|
|
||||||
|
// Open
|
||||||
|
// duplicate Q(open)
|
||||||
|
// duplicate Q(threshold)
|
||||||
|
// duplicate Q(mask)
|
||||||
|
|
||||||
|
// Close
|
||||||
|
// duplicate Q(close)
|
||||||
|
// duplicate Q(threshold)
|
||||||
|
// duplicate Q(mask)
|
||||||
|
|
||||||
|
// Top Hat
|
||||||
|
Q(top_hat)
|
||||||
|
// duplicate Q(threshold)
|
||||||
|
// duplicate Q(mask)
|
||||||
|
|
||||||
|
// Black Hat
|
||||||
|
Q(black_hat)
|
||||||
|
// duplicate Q(threshold)
|
||||||
|
// duplicate Q(mask)
|
||||||
|
|
||||||
// Negate
|
// Negate
|
||||||
Q(negate)
|
Q(negate)
|
||||||
|
|
||||||
@ -516,6 +536,15 @@ Q(sharpen)
|
|||||||
// duplicate Q(invert)
|
// duplicate Q(invert)
|
||||||
// duplicate Q(mask)
|
// duplicate Q(mask)
|
||||||
|
|
||||||
|
// Bilateral
|
||||||
|
Q(bilateral)
|
||||||
|
Q(color_sigma)
|
||||||
|
Q(space_sigma)
|
||||||
|
// duplicate Q(threshold)
|
||||||
|
// duplicate Q(offset)
|
||||||
|
// duplicate Q(invert)
|
||||||
|
// duplicate Q(mask)
|
||||||
|
|
||||||
// Shadow Removal
|
// Shadow Removal
|
||||||
Q(remove_shadows)
|
Q(remove_shadows)
|
||||||
|
|
||||||
|
|||||||
33
usr/examples/04-Image-Filters/color_bilateral_filter.py
Normal file
33
usr/examples/04-Image-Filters/color_bilateral_filter.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Color Bilteral Filter Example
|
||||||
|
#
|
||||||
|
# This example shows off using the bilateral filter on color images.
|
||||||
|
|
||||||
|
import sensor, image, time
|
||||||
|
|
||||||
|
sensor.reset() # Initialize the camera sensor.
|
||||||
|
sensor.set_pixformat(sensor.RGB565) # 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.
|
||||||
|
|
||||||
|
# color_sigma controls how close color wise pixels have to be to each other to be
|
||||||
|
# blured togheter. A smaller value means they have to be closer.
|
||||||
|
# A larger value is less strict.
|
||||||
|
|
||||||
|
# space_sigma controls how close space wise pixels have to be to each other to be
|
||||||
|
# blured togheter. A smaller value means they have to be closer.
|
||||||
|
# A larger value is less strict.
|
||||||
|
|
||||||
|
# Run the kernel on every pixel of the image.
|
||||||
|
img.bilateral(3, color_sigma=5, space_sigma=5)
|
||||||
|
|
||||||
|
# Note that the bilateral filter can introduce image defects if you set
|
||||||
|
# color_sigma/space_sigma to aggresively. Increase the sigma values until
|
||||||
|
# the defects go away if you see them.
|
||||||
|
|
||||||
|
print(clock.fps()) # Note: Your OpenMV Cam runs about half as fast while
|
||||||
|
# connected to your computer. The FPS should increase once disconnected.
|
||||||
33
usr/examples/04-Image-Filters/grayscale_bilateral_filter.py
Normal file
33
usr/examples/04-Image-Filters/grayscale_bilateral_filter.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Grayscale Bilteral Filter Example
|
||||||
|
#
|
||||||
|
# This example shows off using the bilateral filter on grayscale images.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
# color_sigma controls how close color wise pixels have to be to each other to be
|
||||||
|
# blured togheter. A smaller value means they have to be closer.
|
||||||
|
# A larger value is less strict.
|
||||||
|
|
||||||
|
# space_sigma controls how close space wise pixels have to be to each other to be
|
||||||
|
# blured togheter. A smaller value means they have to be closer.
|
||||||
|
# A larger value is less strict.
|
||||||
|
|
||||||
|
# Run the kernel on every pixel of the image.
|
||||||
|
img.bilateral(3, color_sigma=20, space_sigma=20)
|
||||||
|
|
||||||
|
# Note that the bilateral filter can introduce image defects if you set
|
||||||
|
# color_sigma/space_sigma to aggresively. Increase the sigma values until
|
||||||
|
# the defects go away if you see them.
|
||||||
|
|
||||||
|
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