Merge pull request #112 from kwagyeman/master

Add mean, median, and mode filters.
This commit is contained in:
Ibrahim Abd Elkader 2016-04-05 23:22:23 +02:00
commit 749cd96e0c
10 changed files with 647 additions and 177 deletions

View File

@ -129,6 +129,7 @@ endif
OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/img/,\
blob.o \
fmath.o \
fsort.o \
haar.o \
imlib.o \
stats.o \
@ -141,8 +142,10 @@ OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/img/,\
yuv_tab.o \
rainbow_tab.o \
rgb2rgb_tab.o \
median.o \
midpoint.o \
mean.o \
mode.o \
median.o \
point.o \
rectangle.o \
bmp.o \

View File

@ -29,6 +29,7 @@ endif
SRCS += $(addprefix img/, \
blob.c \
fmath.c \
fsort.c \
haar.c \
imlib.c \
stats.c \
@ -41,8 +42,10 @@ SRCS += $(addprefix img/, \
yuv_tab.c \
rainbow_tab.c \
rgb2rgb_tab.c \
median.c \
midpoint.c \
mean.c \
mode.c \
median.c \
point.c \
rectangle.c \
bmp.c \

303
src/omv/img/fsort.c Normal file
View File

@ -0,0 +1,303 @@
/*
* 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.
*
* Fast 9 and 25 bin sort.
*
*/
#include "mdefs.h"
#include "fsort.h"
// http://pages.ripco.net/~jgamble/nw.html
ALWAYS_INLINE static void cmpswp(uint8_t *a, uint8_t *b)
{
if ((*b) < (*a)) {
uint8_t tmp = *a;
*a = *b;
*b = tmp;
}
}
// Network for N=9, using Best Known Arrangement.
// There are 25 comparators in this network,
// grouped into 9 parallel operations.
// [[0,1],[3,4],[6,7]]
// [[1,2],[4,5],[7,8]]
// [[0,1],[3,4],[6,7],[2,5]]
// [[0,3],[1,4],[5,8]]
// [[3,6],[4,7],[2,5]]
// [[0,3],[1,4],[5,7],[2,6]]
// [[1,3],[4,6]]
// [[2,4],[5,6]]
// [[2,3]]
// This is graphed in 17 columns.
static void fsort9(uint8_t *data)
{
cmpswp(data+0, data+1);
cmpswp(data+3, data+4);
cmpswp(data+6, data+7);
cmpswp(data+1, data+2);
cmpswp(data+4, data+5);
cmpswp(data+7, data+8);
cmpswp(data+0, data+1);
cmpswp(data+3, data+4);
cmpswp(data+6, data+7);
cmpswp(data+2, data+5);
cmpswp(data+0, data+3);
cmpswp(data+1, data+4);
cmpswp(data+5, data+8);
cmpswp(data+3, data+6);
cmpswp(data+4, data+7);
cmpswp(data+2, data+5);
cmpswp(data+0, data+3);
cmpswp(data+1, data+4);
cmpswp(data+5, data+7);
cmpswp(data+2, data+6);
cmpswp(data+1, data+3);
cmpswp(data+4, data+6);
cmpswp(data+2, data+4);
cmpswp(data+5, data+6);
cmpswp(data+2, data+3);
}
// Network for N=25, using Bose-Nelson Algorithm.
// There are 154 comparators in this network,
// grouped into 27 parallel operations.
// [[1,2],[4,5],[7,8],[10,11],[13,14],[16,17],[19,20],[21,22],[23,24]]
// [[0,2],[3,5],[6,8],[9,11],[12,14],[15,17],[18,20],[21,23],[22,24]]
// [[0,1],[3,4],[2,5],[6,7],[9,10],[8,11],[12,13],[15,16],[14,17],[18,19],[22,23],[20,24]]
// [[0,3],[1,4],[6,9],[7,10],[5,11],[12,15],[13,16],[18,22],[19,23],[17,24]]
// [[2,4],[1,3],[8,10],[7,9],[0,6],[14,16],[13,15],[18,21],[20,23],[11,24]]
// [[2,3],[8,9],[1,7],[4,10],[14,15],[19,21],[20,22],[16,23]]
// [[2,8],[1,6],[3,9],[5,10],[20,21],[12,19],[15,22],[17,23]]
// [[2,7],[4,9],[12,18],[13,20],[14,21],[16,22],[10,23]]
// [[2,6],[5,9],[4,7],[14,20],[13,18],[17,22],[11,23]]
// [[3,6],[5,8],[14,19],[16,20],[17,21],[0,13],[9,22]]
// [[5,7],[4,6],[14,18],[15,19],[17,20],[0,12],[8,21],[10,22]]
// [[5,6],[15,18],[17,19],[1,14],[7,20],[11,22]]
// [[16,18],[2,15],[1,12],[6,19],[8,20],[11,21]]
// [[17,18],[2,14],[3,16],[7,19],[10,20]]
// [[2,13],[4,17],[5,18],[8,19],[11,20]]
// [[2,12],[5,17],[4,16],[3,13],[9,19]]
// [[5,16],[3,12],[4,14],[10,19]]
// [[5,15],[4,12],[11,19],[9,16],[10,17]]
// [[5,14],[8,15],[11,18],[10,16]]
// [[5,13],[7,14],[11,17]]
// [[5,12],[6,13],[8,14],[11,16]]
// [[6,12],[8,13],[10,14],[11,15]]
// [[7,12],[9,13],[11,14]]
// [[8,12],[11,13]]
// [[9,12]]
// [[10,12]]
// [[11,12]]
// This is graphed in 89 columns.
static void fsort25(uint8_t *data)
{
cmpswp(data+1, data+2);
cmpswp(data+4, data+5);
cmpswp(data+7, data+8);
cmpswp(data+10, data+11);
cmpswp(data+13, data+14);
cmpswp(data+16, data+17);
cmpswp(data+19, data+20);
cmpswp(data+21, data+22);
cmpswp(data+23, data+24);
cmpswp(data+0, data+2);
cmpswp(data+3, data+5);
cmpswp(data+6, data+8);
cmpswp(data+9, data+11);
cmpswp(data+12, data+14);
cmpswp(data+15, data+17);
cmpswp(data+18, data+20);
cmpswp(data+21, data+23);
cmpswp(data+22, data+24);
cmpswp(data+0, data+1);
cmpswp(data+3, data+4);
cmpswp(data+2, data+5);
cmpswp(data+6, data+7);
cmpswp(data+9, data+10);
cmpswp(data+8, data+11);
cmpswp(data+12, data+13);
cmpswp(data+15, data+16);
cmpswp(data+14, data+17);
cmpswp(data+18, data+19);
cmpswp(data+22, data+23);
cmpswp(data+20, data+24);
cmpswp(data+0, data+3);
cmpswp(data+1, data+4);
cmpswp(data+6, data+9);
cmpswp(data+7, data+10);
cmpswp(data+5, data+11);
cmpswp(data+12, data+15);
cmpswp(data+13, data+16);
cmpswp(data+18, data+22);
cmpswp(data+19, data+23);
cmpswp(data+17, data+24);
cmpswp(data+2, data+4);
cmpswp(data+1, data+3);
cmpswp(data+8, data+10);
cmpswp(data+7, data+9);
cmpswp(data+0, data+6);
cmpswp(data+14, data+16);
cmpswp(data+13, data+15);
cmpswp(data+18, data+21);
cmpswp(data+20, data+23);
cmpswp(data+11, data+24);
cmpswp(data+2, data+3);
cmpswp(data+8, data+9);
cmpswp(data+1, data+7);
cmpswp(data+4, data+10);
cmpswp(data+14, data+15);
cmpswp(data+19, data+21);
cmpswp(data+20, data+22);
cmpswp(data+16, data+23);
cmpswp(data+2, data+8);
cmpswp(data+1, data+6);
cmpswp(data+3, data+9);
cmpswp(data+5, data+10);
cmpswp(data+20, data+21);
cmpswp(data+12, data+19);
cmpswp(data+15, data+22);
cmpswp(data+17, data+23);
cmpswp(data+2, data+7);
cmpswp(data+4, data+9);
cmpswp(data+12, data+18);
cmpswp(data+13, data+20);
cmpswp(data+14, data+21);
cmpswp(data+16, data+22);
cmpswp(data+10, data+23);
cmpswp(data+2, data+6);
cmpswp(data+5, data+9);
cmpswp(data+4, data+7);
cmpswp(data+14, data+20);
cmpswp(data+13, data+18);
cmpswp(data+17, data+22);
cmpswp(data+11, data+23);
cmpswp(data+3, data+6);
cmpswp(data+5, data+8);
cmpswp(data+14, data+19);
cmpswp(data+16, data+20);
cmpswp(data+17, data+21);
cmpswp(data+0, data+13);
cmpswp(data+9, data+22);
cmpswp(data+5, data+7);
cmpswp(data+4, data+6);
cmpswp(data+14, data+18);
cmpswp(data+15, data+19);
cmpswp(data+17, data+20);
cmpswp(data+0, data+12);
cmpswp(data+8, data+21);
cmpswp(data+10, data+22);
cmpswp(data+5, data+6);
cmpswp(data+15, data+18);
cmpswp(data+17, data+19);
cmpswp(data+1, data+14);
cmpswp(data+7, data+20);
cmpswp(data+11, data+22);
cmpswp(data+16, data+18);
cmpswp(data+2, data+15);
cmpswp(data+1, data+12);
cmpswp(data+6, data+19);
cmpswp(data+8, data+20);
cmpswp(data+11, data+21);
cmpswp(data+17, data+18);
cmpswp(data+2, data+14);
cmpswp(data+3, data+16);
cmpswp(data+7, data+19);
cmpswp(data+10, data+20);
cmpswp(data+2, data+13);
cmpswp(data+4, data+17);
cmpswp(data+5, data+18);
cmpswp(data+8, data+19);
cmpswp(data+11, data+20);
cmpswp(data+2, data+12);
cmpswp(data+5, data+17);
cmpswp(data+4, data+16);
cmpswp(data+3, data+13);
cmpswp(data+9, data+19);
cmpswp(data+5, data+16);
cmpswp(data+3, data+12);
cmpswp(data+4, data+14);
cmpswp(data+10, data+19);
cmpswp(data+5, data+15);
cmpswp(data+4, data+12);
cmpswp(data+11, data+19);
cmpswp(data+9, data+16);
cmpswp(data+10, data+17);
cmpswp(data+5, data+14);
cmpswp(data+8, data+15);
cmpswp(data+11, data+18);
cmpswp(data+10, data+16);
cmpswp(data+5, data+13);
cmpswp(data+7, data+14);
cmpswp(data+11, data+17);
cmpswp(data+5, data+12);
cmpswp(data+6, data+13);
cmpswp(data+8, data+14);
cmpswp(data+11, data+16);
cmpswp(data+6, data+12);
cmpswp(data+8, data+13);
cmpswp(data+10, data+14);
cmpswp(data+11, data+15);
cmpswp(data+7, data+12);
cmpswp(data+9, data+13);
cmpswp(data+11, data+14);
cmpswp(data+8, data+12);
cmpswp(data+11, data+13);
cmpswp(data+9, data+12);
cmpswp(data+10, data+12);
cmpswp(data+11, data+12);
}
void fsort(uint8_t *data, int n)
{
switch(n) {
case 1: return;
case 9: fsort9(data); return;
case 25: fsort25(data); return;
default: return;
}
}

13
src/omv/img/fsort.h Normal file
View File

@ -0,0 +1,13 @@
/*
* 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.
*
* Fast 9 and 25 bin sort.
*
*/
#ifndef __FSORT_H__
#define __FSORT_H__
#include <stdint.h>
void fsort(uint8_t *data, int n);
#endif /* __FSORT_H__ */

View File

@ -462,7 +462,9 @@ 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);
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);
/* Clustering functions */
array_t *cluster_kmeans(array_t *points, int k);

81
src/omv/img/mean.c Normal file
View File

@ -0,0 +1,81 @@
/*
* 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.
*
* Mean 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
void imlib_mean_filter(image_t *img, const int ksize)
{
int n = ((ksize*2)+1)*((ksize*2)+1);
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 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)) {
const uint8_t pixel = IM_GET_GS_PIXEL(img, x+k, y+j);
acc += pixel;
}
}
}
// We're writing into the buffer like if it were a window.
buffer[((y%brows)*img->w)+x] = acc/n;
}
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_acc = 0;
int g_acc = 0;
int b_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)) {
const uint16_t pixel = IM_GET_RGB565_PIXEL(img, x+k, y+j);
r_acc += IM_R565(pixel);
g_acc += IM_G565(pixel);
b_acc += IM_B565(pixel);
}
}
}
// 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);
}
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

@ -3,176 +3,93 @@
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
* This work is licensed under the MIT license, see the file LICENSE for details.
*
* O(N) median_gs filter with histograms.
* Median filtering.
*
*/
#include <arm_math.h>
#include <string.h>
#include "imlib.h"
#include "fb_alloc.h"
#include "fsort.h"
typedef struct {
int n;
union {
int h[256];
struct {
int r[32];
int g[64];
int b[32];
};
};
} histo_t;
void del_pixels(image_t * im, int row, int col, int size, histo_t *h)
void imlib_median_filter(image_t *img, const int ksize, const int percentile)
{
if (im->bpp==1) {
for (int i = row - size; i <= row + size && i < im->h; i++) {
if (i < 0) continue;
h->h[im->pixels[i*im->w+col]]--;
h->n--;
int n = ((ksize*2)+1)*((ksize*2)+1);
int brows = ksize + 1;
uint8_t *buffer = fb_alloc(img->w * brows * img->bpp);
if (IM_IS_GS(img)) {
uint8_t data[n];
for (int y=0; y<img->h; y++) {
for (int x=0; x<img->w; x++) {
uint8_t *data_ptr = data;
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);
*data_ptr++ = pixel;
} else {
*data_ptr++ = 0;
}
}
}
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;
}
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 i = row - size; i <= row + size && i < im->h; i++) {
if (i < 0) continue;
uint16_t c = ((uint16_t*)im->pixels)[i*im->w+col];
h->r[IM_R565(c)]--;
h->g[IM_G565(c)]--;
h->b[IM_B565(c)]--;
h->n--;
uint8_t r_data[n];
uint8_t g_data[n];
uint8_t b_data[n];
for (int y=0; y<img->h; y++) {
for (int x=0; x<img->w; x++) {
uint8_t *r_data_ptr = r_data;
uint8_t *g_data_ptr = g_data;
uint8_t *b_data_ptr = b_data;
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);
*r_data_ptr++ = IM_R565(pixel);
*g_data_ptr++ = IM_G565(pixel);
*b_data_ptr++ = IM_B565(pixel);
} else {
*r_data_ptr++ = 0;
*g_data_ptr++ = 0;
*b_data_ptr++ = 0;
}
}
}
fsort(r_data, n);
fsort(g_data, n);
fsort(b_data, n);
int r_median = r_data[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);
}
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));
}
}
}
void add_pixels(image_t * im, int row, int col, int size, histo_t *h)
{
if (im->bpp==1) {
for (int i = row - size; i <= row + size && i < im->h; i++) {
if (i < 0) continue;
h->h[im->pixels[i*im->w+col]]++;
h->n++;
}
} else {
for (int i = row - size; i <= row + size && i < im->h; i++) {
if (i < 0) continue;
uint16_t c = ((uint16_t*)im->pixels)[i*im->w+col];
h->r[IM_R565(c)]++;
h->g[IM_G565(c)]++;
h->b[IM_B565(c)]++;
h->n++;
}
}
}
void init_histo(image_t *im, int row, int size, histo_t *h)
{
memset(h, 0, sizeof(histo_t));
for (int j = 0; j < size && j < im->w; j++) {
add_pixels(im, row, j, size, h);
}
}
uint8_t median_gs(histo_t *h)
{
int i, n;
for (i=0, n=h->n/2; (n -= h->h[i]) >0; i++) {
}
return i;
}
uint16_t median_rgb(histo_t *h)
{
int rx = h->n/2;
int gx = h->n/2;
int bx = h->n/2;
uint16_t r=0, g=0, b=0;
for (int i=0; (rx>0 || gx>0 || bx>0); i++) {
if (rx > 0) {
rx -= h->r[i];
r = i;
}
if (gx > 0) {
gx -= h->g[i];
g = i;
}
if (bx > 0) {
bx -= h->b[i];
b = i;
}
}
return IM_RGB565(r, g, b);
}
void median_filter_rgb(image_t *in, int size)
{
int k_rows = 24;
histo_t *h = fb_alloc(sizeof(*h));
uint16_t *dst = (uint16_t*) in->data;
uint16_t *data = fb_alloc(in->w * k_rows * sizeof(*data));
for (int row=0; row<in->h; row++) {
init_histo(in, row, size, h);
data[(row%k_rows)*in->w+size] = median_rgb(h);
for (int col=0; col<in->w; col++) {
del_pixels(in, row, col - size, size, h);
add_pixels(in, row, col + size, size, h);
data[(row%k_rows)*in->w+col] = median_rgb(h);
}
if ((row+1)%k_rows==0) {
memcpy(dst, data, (in->w*(k_rows-size)*2));
dst += (in->w*(k_rows-size));
}
if ((row>size && (row+1)%k_rows==size) || row+1==in->h){
memcpy(dst, data+in->w*(k_rows-size), (in->w*size*2));
dst += (in->w*size);
}
}
fb_free_all();
}
void median_filter_gs(image_t *in, int size)
{
int k_rows = 24;
histo_t *h = fb_alloc(sizeof(*h));
uint8_t *dst = (uint8_t*) in->data;
uint8_t *data = fb_alloc(in->w * k_rows * sizeof(*data));
for (int row=0; row<in->h; row++) {
init_histo(in, row, size, h);
data[(row%k_rows)*in->w+size] = median_gs(h);
for (int col=0; col<in->w; col++) {
del_pixels(in, row, col - size, size, h);
add_pixels(in, row, col + size, size, h);
data[(row%k_rows)*in->w+col] = median_gs(h);
}
if ((row+1)%k_rows==0) {
memcpy(dst, data, (in->w*(k_rows-size)));
dst += (in->w*(k_rows-size));
}
if ((row>size && (row+1)%k_rows==size) || row+1==in->h){
memcpy(dst, data+in->w*(k_rows-size), (in->w*size));
dst += (in->w*size);
}
}
fb_free_all();
}
void imlib_median_filter(image_t *in, int size)
{
if (in->bpp == 1) {
//median_filter_test(in, size);
median_filter_gs(in, size);
} else {
median_filter_rgb(in, size);
}
fb_free();
}

111
src/omv/img/mode.c Normal file
View File

@ -0,0 +1,111 @@
/*
* 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.
*
* Mode 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
void imlib_mode_filter(image_t *img, const int ksize)
{
int brows = ksize + 1;
uint8_t *buffer = fb_alloc(img->w * brows * img->bpp);
if (IM_IS_GS(img)) {
uint8_t *bins = fb_alloc(256);
for (int y=0; y<img->h; y++) {
for (int x=0; x<img->w; x++) {
memset(bins, 0, 256);
int mcount = 0, mode = 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);
bins[pixel]++;
if(bins[pixel] > mcount) {
mcount = bins[pixel];
mode = pixel;
}
}
}
}
// We're writing into the buffer like if it were a window.
buffer[((y%brows)*img->w)+x] = mode;
}
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));
}
fb_free();
} else {
uint8_t *r_bins = fb_alloc(32);
uint8_t *g_bins = fb_alloc(64);
uint8_t *b_bins = fb_alloc(32);
for (int y=0; y<img->h; y++) {
for (int x=0; x<img->w; x++) {
memset(r_bins, 0, 32);
memset(g_bins, 0, 64);
memset(b_bins, 0, 32);
int r_mcount = 0, r_mode = 0;
int g_mcount = 0, g_mode = 0;
int b_mcount = 0, b_mode = 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_bins[red]++;
if(r_bins[red] > r_mcount) {
r_mcount = r_bins[red];
r_mode = red;
}
g_bins[green]++;
if(g_bins[green] > g_mcount) {
g_mcount = g_bins[green];
g_mode = green;
}
b_bins[blue]++;
if(b_bins[blue] > b_mcount) {
b_mcount = b_bins[blue];
b_mode = blue;
}
}
}
}
// 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);
}
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();
fb_free();
fb_free();
}
fb_free();
}

View File

@ -710,6 +710,48 @@ static mp_obj_t py_image_midpoint(uint n_args, const mp_obj_t *args, mp_map_t *k
return mp_const_none;
}
static mp_obj_t py_image_mean(mp_obj_t img_obj, mp_obj_t k_obj)
{
image_t *arg_img = py_image_cobj(img_obj);
PY_ASSERT_FALSE_MSG(IM_IS_JPEG(arg_img),
"Operation not supported on JPEG");
int arg_ksize = mp_obj_get_int(k_obj);
PY_ASSERT_TRUE_MSG(arg_ksize >= 0, "Kernel Size must be >= 0");
imlib_mean_filter(arg_img, arg_ksize);
return mp_const_none;
}
static mp_obj_t py_image_mode(mp_obj_t img_obj, mp_obj_t k_obj)
{
image_t *arg_img = py_image_cobj(img_obj);
PY_ASSERT_FALSE_MSG(IM_IS_JPEG(arg_img),
"Operation not supported on JPEG");
int arg_ksize = mp_obj_get_int(k_obj);
PY_ASSERT_TRUE_MSG(arg_ksize >= 0, "Kernel Size must be >= 0");
imlib_mode_filter(arg_img, arg_ksize);
return mp_const_none;
}
static mp_obj_t py_image_median(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");
PY_ASSERT_TRUE_MSG(arg_ksize <= 2, "Kernel Size must be <= 2");
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));
return mp_const_none;
}
static mp_obj_t py_image_scale(mp_obj_t image_obj, mp_obj_t size_obj)
{
int w,h;
@ -860,17 +902,6 @@ static mp_obj_t py_image_histeq(mp_obj_t image_obj)
return mp_const_none;
}
static mp_obj_t py_image_median(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
// Read args
image_t *image = py_image_cobj(args[0]);
int ksize = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 1);
// Call median filter
imlib_median_filter(image, ksize);
return mp_const_none;
}
static mp_obj_t py_image_threshold(mp_obj_t image_obj, mp_obj_t color_list_obj, mp_obj_t threshold)
{
color_t *color;
@ -1198,7 +1229,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_morph_obj, 3, py_image_morph);
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_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_median_obj, 2, 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);
@ -1258,6 +1291,8 @@ static const mp_map_elem_t locals_dict_table[] = {
{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_mean), (mp_obj_t)&py_image_mean_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_mode), (mp_obj_t)&py_image_mode_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},

View File

@ -55,6 +55,8 @@ Q(difference)
Q(morph)
Q(statistics)
Q(midpoint)
Q(mean)
Q(mode)
Q(median)
Q(kp_desc)
Q(lbp_desc)