Merge pull request #92 from kwagyeman/master

Add color functions.
This commit is contained in:
Ibrahim Abd Elkader 2016-03-04 15:36:36 +02:00
commit 72f5b570da
4 changed files with 206 additions and 150 deletions

View File

@ -19,12 +19,81 @@
#include "font.h"
#include "fb_alloc.h"
/* XYZ lookup table */
// Gamma uncompress
extern const float xyz_table[256];
/* RGB565->LAB lookup */
/* Grayscale [0..255] to rainbox lookup */
// Grayscale to RGB565 conversion
extern const uint16_t rainbow_table[256];
// USE THE LUT FOR RGB->LAB CONVERSION - NOT THIS FUNCTION!
void imlib_rgb_to_lab(simple_color_t *rgb, simple_color_t *lab)
{
// https://en.wikipedia.org/wiki/SRGB -> Specification of the transformation
// https://en.wikipedia.org/wiki/Lab_color_space -> CIELAB-CIEXYZ conversions
float r_lin = xyz_table[rgb->red];
float g_lin = xyz_table[rgb->green];
float b_lin = xyz_table[rgb->blue];
float x = ((r_lin * 0.4124f) + (g_lin * 0.3576f) + (b_lin * 0.1805f)) / 095.047f;
float y = ((r_lin * 0.2126f) + (g_lin * 0.7152f) + (b_lin * 0.0722f)) / 100.000f;
float z = ((r_lin * 0.0193f) + (g_lin * 0.1192f) + (b_lin * 0.9505f)) / 108.883f;
x = (x>0.008856f) ? fast_cbrtf(x) : ((x * 7.787037f) + 0.137931f);
y = (y>0.008856f) ? fast_cbrtf(y) : ((y * 7.787037f) + 0.137931f);
z = (z>0.008856f) ? fast_cbrtf(z) : ((z * 7.787037f) + 0.137931f);
lab->L = ((int8_t) fast_roundf(116 * y)) - 16;
lab->A = ((int8_t) fast_roundf(500 * (x-y)));
lab->B = ((int8_t) fast_roundf(200 * (y-z)));
}
void imlib_lab_to_rgb(simple_color_t *lab, simple_color_t *rgb)
{
// https://en.wikipedia.org/wiki/Lab_color_space -> CIELAB-CIEXYZ conversions
// https://en.wikipedia.org/wiki/SRGB -> Specification of the transformation
float x = ((lab->L + 16) * 0.008621f) + (lab->A * 0.002f);
float y = ((lab->L + 16) * 0.008621f);
float z = ((lab->L + 16) * 0.008621f) - (lab->B * 0.005f);
x = ((x>0.206897f) ? (x*x*x) : ((0.128419f * x) - 0.017713f)) * 095.047f;
y = ((y>0.206897f) ? (y*y*y) : ((0.128419f * y) - 0.017713f)) * 100.000f;
z = ((z>0.206897f) ? (z*z*z) : ((0.128419f * z) - 0.017713f)) * 108.883f;
float r_lin = ((x * +3.2406f) + (y * -1.5372f) + (z * -0.4986f)) / 100.0f;
float g_lin = ((x * -0.9689f) + (y * +1.8758f) + (z * +0.0415f)) / 100.0f;
float b_lin = ((x * +0.0557f) + (y * -0.2040f) + (z * +1.0570f)) / 100.0f;
r_lin = (r_lin>0.0031308f) ? ((1.055f*powf(r_lin, 0.416666f))-0.055f) : (r_lin*12.92f);
g_lin = (g_lin>0.0031308f) ? ((1.055f*powf(g_lin, 0.416666f))-0.055f) : (g_lin*12.92f);
b_lin = (b_lin>0.0031308f) ? ((1.055f*powf(b_lin, 0.416666f))-0.055f) : (b_lin*12.92f);
rgb->red = IM_MAX(IM_MIN(fast_roundf(r_lin * 255), 255), 0);
rgb->green = IM_MAX(IM_MIN(fast_roundf(g_lin * 255), 255), 0);
rgb->blue = IM_MAX(IM_MIN(fast_roundf(b_lin * 255), 255), 0);
}
void imlib_rgb_to_grayscale(simple_color_t *rgb, simple_color_t *grayscale)
{
float r_lin = xyz_table[rgb->red];
float g_lin = xyz_table[rgb->green];
float b_lin = xyz_table[rgb->blue];
float y = ((r_lin * 0.2126f) + (g_lin * 0.7152f) + (b_lin * 0.0722f)) / 100.0f;
y = (y>0.0031308f) ? ((1.055f*powf(y, 0.416666f))-0.055f) : (y*12.92f);
grayscale->G = IM_MAX(IM_MIN(fast_roundf(y * 255), 255), 0);
}
// Just copy settings back.
void imlib_grayscale_to_rgb(simple_color_t *grayscale, simple_color_t *rgb)
{
rgb->red = grayscale->G;
rgb->green = grayscale->G;
rgb->blue = grayscale->G;
}
////////////////////////////////////////////////////////////////////////////////
static save_image_format_t imblib_parse_extension(image_t *img, const char *path)
{
size_t l = strlen(path);
@ -623,7 +692,8 @@ static void imlib_erode_dilate(image_t *img, int ksize, int threshold, int e_or_
}
}
}
buffer[buffer_idx] = (acc >= threshold) ? 0xFF : 0;
// Preserve original pixel value...
if (acc < threshold) buffer[buffer_idx] = 0;
}
if (y>=ksize) {
memcpy(img->pixels+((y-ksize)*img->w),
@ -657,7 +727,8 @@ static void imlib_erode_dilate(image_t *img, int ksize, int threshold, int e_or_
}
}
}
((uint16_t *) buffer)[buffer_idx] = (acc >= threshold) ? 0xFFFF : 0;
// Preserve original pixel value...
if (acc < threshold) ((uint16_t *) buffer)[buffer_idx] = 0;
}
if (y>=ksize) {
memcpy(((uint16_t *) img->pixels)+((y-ksize)*img->w),
@ -741,110 +812,6 @@ void imlib_difference(image_t *img, const char *path, image_t *other)
////////////////////////////////////////////////////////////////////////////////
uint32_t imlib_lab_distance(struct color *c0, struct color *c1)
{
uint32_t sum=0;
sum += (c0->L - c1->L) * (c0->L - c1->L);
sum += (c0->A - c1->A) * (c0->A - c1->A);
sum += (c0->B - c1->B) * (c0->B - c1->B);
return fast_sqrtf(sum);
}
uint32_t imlib_rgb_distance(struct color *c0, struct color *c1)
{
uint32_t sum=0;
sum += (c0->r - c1->r) * (c0->r - c1->r);
sum += (c0->g - c1->g) * (c0->g - c1->g);
sum += (c0->b - c1->b) * (c0->b - c1->b);
return fast_sqrtf(sum);
}
uint32_t imlib_hsv_distance(struct color *c0, struct color *c1)
{
uint32_t sum=0;
sum += (c0->h - c1->h) * (c0->h - c1->h);
sum += (c0->s - c1->s) * (c0->s - c1->s);
sum += (c0->v - c1->v) * (c0->v - c1->v);
return fast_sqrtf(sum);
}
void imlib_rgb_to_lab(struct color *rgb, struct color *lab)
{
float v[3];
float x,y,z;
const float c = 16.0f/ 116.0f;
v[0] = xyz_table[rgb->vec[0]];
v[1] = xyz_table[rgb->vec[1]];
v[2] = xyz_table[rgb->vec[2]];
x = (v[0] * 0.4124f + v[1] * 0.3576f + v[2] * 0.1805f) / 95.047f ;
y = (v[0] * 0.2126f + v[1] * 0.7152f + v[2] * 0.0722f) / 100.0f ;
z = (v[0] * 0.0193f + v[1] * 0.1192f + v[2] * 0.9505f) / 108.883f ;
x = (x>0.008856f)? fast_cbrtf(x) : (x * 7.787f) + c;
y = (y>0.008856f)? fast_cbrtf(y) : (y * 7.787f) + c;
z = (z>0.008856f)? fast_cbrtf(z) : (z * 7.787f) + c;
lab->L = (int8_t) (116.0f * y-16.0f);
lab->A = (int8_t) (500.0f * (x-y));
lab->B = (int8_t) (200.0f * (y-z));
}
void imlib_rgb_to_hsv(struct color *rgb, struct color *hsv)
{
int min;
int max;
int r,g,b;
int delta;
/* 0..100 */
r = rgb->r*100/255;
g = rgb->g*100/255;
b = rgb->b*100/255;
min = IM_MIN(r, IM_MIN(g, b));
max = IM_MAX(r, IM_MAX(g, b));
if (min == max) {
/* Black/gray/white */
hsv->h = 0;
hsv->s = 0;
hsv->v = min;
} else {
delta = max-min;
//scaled to avoid floats
if (r==max) {
hsv->h = (g-b)*100/delta;
} else if (g==max) {
hsv->h = 200 + (b-r)*100/delta;
} else {
hsv->h = 400 + (r-g)*100/delta;
}
hsv->h = hsv->h*60/100;
if (hsv->h<0) {
hsv->h+=360;
}
hsv->s = delta*100/max;
hsv->v = max;
}
}
/* converts a grayscale buffer to RGB565 to display on LCDs */
void imlib_grayscale_to_rgb565(struct image *image)
{
#if 0
int i;
for (i=0; i<(image->w * image->h * image->bpp); i++) {
uint8_t y = image->pixels[i];
uint8_t r = y*31/255;
uint8_t g = y*63/255;
uint8_t b = y*31/255;
//uint16_t rgb = (r << 11) | (g << 5) | b;
}
#endif
}
#ifdef OPENMV1
void imlib_threshold(image_t *src, image_t *dst, color_t *color, int color_size, int threshold)
{

View File

@ -222,21 +222,41 @@ typedef struct rectangle {
typedef struct simple_color {
uint8_t G;
int8_t L;
int8_t A;
int8_t B;
union
{
int8_t L;
uint8_t red; // RGB888 not RGB565
};
union
{
int8_t A;
uint8_t green; // RGB888 not RGB565
};
union
{
int8_t B;
uint8_t blue; // RGB888 not RGB565
};
}
simple_color_t;
typedef struct statistics {
uint8_t g_mean, l_mean, a_mean, b_mean;
uint8_t g_median, l_median, a_median, b_median;
uint8_t g_mode, l_mode, a_mode, b_mode;
uint8_t g_st_dev, l_st_dev, a_st_dev, b_st_dev;
uint8_t g_min, l_min, a_min, b_min;
uint8_t g_max, l_max, a_max, b_max;
uint8_t g_lower_q, l_lower_q, a_lower_q, b_lower_q;
uint8_t g_upper_q, l_upper_q, a_upper_q, b_upper_q;
uint8_t g_mean;
int8_t l_mean, a_mean, b_mean;
uint8_t g_median;
int8_t l_median, a_median, b_median;
uint8_t g_mode;
int8_t l_mode, a_mode, b_mode;
uint8_t g_st_dev;
int8_t l_st_dev, a_st_dev, b_st_dev;
uint8_t g_min;
int8_t l_min, a_min, b_min;
uint8_t g_max;
int8_t l_max, a_max, b_max;
uint8_t g_lower_q;
int8_t l_lower_q, a_lower_q, b_lower_q;
uint8_t g_upper_q;
int8_t l_upper_q, a_upper_q, b_upper_q;
} statistics_t;
typedef struct blob {
@ -386,6 +406,12 @@ typedef enum descriptor_type {
DESC_FREAK,
} descriptor_t;
/* Color space functions */
void imlib_rgb_to_lab(simple_color_t *rgb, simple_color_t *lab);
void imlib_lab_to_rgb(simple_color_t *lab, simple_color_t *rgb);
void imlib_rgb_to_grayscale(simple_color_t *rgb, simple_color_t *grayscale);
void imlib_grayscale_to_rgb(simple_color_t *grayscale, simple_color_t *rgb);
/* Image file functions */
void ppm_read_geometry(FIL *fp, image_t *img, const char *path, ppm_read_settings_t *rs);
void ppm_read_pixels(FIL *fp, image_t *img, int line_start, int line_end, ppm_read_settings_t *rs);
@ -449,21 +475,12 @@ void imlib_difference(image_t *img, const char *path, image_t *other);
void imlib_morph(image_t *img, const int ksize, const int8_t *krn, const float m, const int b);
/* Image Statistics */
uint32_t *imlib_histogram(image_t *img, rectangle_t *r);
int32_t *imlib_histogram(image_t *img, rectangle_t *r);
void imlib_statistics(image_t *img, rectangle_t *r, statistics_t *out);
/* Clustering functions */
array_t *cluster_kmeans(array_t *points, int k);
/* Dela E on RGB/HSV/LAB */
uint32_t imlib_lab_distance(struct color *c0, struct color *c1);
uint32_t imlib_rgb_distance(struct color *c0, struct color *c1);
uint32_t imlib_rgb_distance(struct color *c0, struct color *c1);
/* Color space conversion */
void imlib_rgb_to_lab(struct color *rgb, struct color *lab);
void imlib_rgb_to_hsv(struct color *rgb, struct color *hsv);
/* Image filtering functions */
int imlib_image_mean(struct image *src);
void imlib_histeq(struct image *src);

View File

@ -10,19 +10,19 @@
#include "imlib.h"
#include "fb_alloc.h"
uint32_t *imlib_histogram(image_t *img, rectangle_t *r)
int32_t *imlib_histogram(image_t *img, rectangle_t *r)
{
rectangle_t rect;
if (!rectangle_subimg(img, r, &rect)) {
return NULL;
}
uint32_t *histogram;
int32_t *histogram;
if (IM_IS_GS(img)) {
histogram = fb_alloc0(IM_G_HIST_SIZE * sizeof(uint32_t));
histogram = fb_alloc0(IM_G_HIST_SIZE * sizeof(int32_t));
} else {
histogram = fb_alloc0((IM_L_HIST_SIZE * sizeof(uint32_t)) +
(IM_A_HIST_SIZE * sizeof(uint32_t)) +
(IM_B_HIST_SIZE * sizeof(uint32_t)));
histogram = fb_alloc0((IM_L_HIST_SIZE * sizeof(int32_t)) +
(IM_A_HIST_SIZE * sizeof(int32_t)) +
(IM_B_HIST_SIZE * sizeof(int32_t)));
}
if (IM_IS_GS(img)) {
for (int i = 0; i < rect.h; i++) {
@ -50,7 +50,7 @@ uint32_t *imlib_histogram(image_t *img, rectangle_t *r)
void imlib_statistics(image_t *img, rectangle_t *r, statistics_t *out)
{
memset(out, 0, sizeof(statistics_t));
uint32_t *histogram = imlib_histogram(img, r);
int32_t *histogram = imlib_histogram(img, r);
if (!histogram) {
return;
}
@ -61,7 +61,7 @@ void imlib_statistics(image_t *img, rectangle_t *r, statistics_t *out)
for (int i = IM_G_HIST_OFFSET; i < (IM_G_HIST_OFFSET + IM_G_HIST_SIZE); i++) {
sum += histogram[i];
avg += (i-IM_G_HIST_OFFSET) * histogram[i];
if (((int32_t) histogram[i]) > mode_count) {
if (histogram[i] > mode_count) {
mode_count = histogram[i];
out->g_mode = (i-IM_G_HIST_OFFSET);
}
@ -101,7 +101,7 @@ void imlib_statistics(image_t *img, rectangle_t *r, statistics_t *out)
for (int i = IM_L_HIST_OFFSET; i < (IM_L_HIST_OFFSET + IM_L_HIST_SIZE); i++) {
sum += histogram[i];
avg += (i-IM_L_HIST_OFFSET-128) * histogram[i];
if (((int32_t) histogram[i]) > mode_count) {
if (histogram[i] > mode_count) {
mode_count = histogram[i];
out->l_mode = (i-IM_L_HIST_OFFSET-128);
}
@ -142,7 +142,7 @@ void imlib_statistics(image_t *img, rectangle_t *r, statistics_t *out)
for (int i = IM_A_HIST_OFFSET; i < (IM_A_HIST_OFFSET + IM_A_HIST_SIZE); i++) {
sum += histogram[i];
avg += (i-IM_A_HIST_OFFSET-128) * histogram[i];
if (((int32_t) histogram[i]) > mode_count) {
if (histogram[i] > mode_count) {
mode_count = histogram[i];
out->a_mode = (i-IM_A_HIST_OFFSET-128);
}
@ -183,7 +183,7 @@ void imlib_statistics(image_t *img, rectangle_t *r, statistics_t *out)
for (int i = IM_B_HIST_OFFSET; i < (IM_B_HIST_OFFSET + IM_B_HIST_SIZE); i++) {
sum += histogram[i];
avg += (i-IM_B_HIST_OFFSET-128) * histogram[i];
if (((int32_t) histogram[i]) > mode_count) {
if (histogram[i] > mode_count) {
mode_count = histogram[i];
out->b_mode = (i-IM_B_HIST_OFFSET-128);
}

View File

@ -1316,6 +1316,65 @@ int py_image_descriptor_from_roi(image_t *image, const char *path, rectangle_t *
return 0;
}
mp_obj_t py_image_rgb_to_lab(mp_obj_t tuple)
{
mp_obj_t *rgb;
mp_obj_get_array_fixed_n(tuple, 3, &rgb);
simple_color_t rgb_color, lab_color;
rgb_color.red = mp_obj_get_int(rgb[0]);
rgb_color.green = mp_obj_get_int(rgb[1]);
rgb_color.blue = mp_obj_get_int(rgb[2]);
imlib_rgb_to_lab(&rgb_color, &lab_color);
return mp_obj_new_tuple(3, (mp_obj_t[3])
{mp_obj_new_int(lab_color.L),
mp_obj_new_int(lab_color.A),
mp_obj_new_int(lab_color.B)});
}
mp_obj_t py_image_lab_to_rgb(mp_obj_t tuple)
{
mp_obj_t *lab;
mp_obj_get_array_fixed_n(tuple, 3, &lab);
simple_color_t lab_color, rgb_color;
lab_color.L = mp_obj_get_int(lab[0]);
lab_color.A = mp_obj_get_int(lab[1]);
lab_color.B = mp_obj_get_int(lab[2]);
imlib_lab_to_rgb(&lab_color, &rgb_color);
return mp_obj_new_tuple(3, (mp_obj_t[3])
{mp_obj_new_int(rgb_color.red),
mp_obj_new_int(rgb_color.green),
mp_obj_new_int(rgb_color.blue)});
}
mp_obj_t py_image_rgb_to_grayscale(mp_obj_t tuple)
{
mp_obj_t *rgb;
mp_obj_get_array_fixed_n(tuple, 3, &rgb);
simple_color_t rgb_color, grayscale_color;
rgb_color.red = mp_obj_get_int(rgb[0]);
rgb_color.green = mp_obj_get_int(rgb[1]);
rgb_color.blue = mp_obj_get_int(rgb[2]);
imlib_rgb_to_grayscale(&rgb_color, &grayscale_color);
return mp_obj_new_int(grayscale_color.G);
}
mp_obj_t py_image_grayscale_to_rgb(mp_obj_t not_tuple)
{
simple_color_t grayscale_color, rgb_color;
grayscale_color.G = mp_obj_get_int(not_tuple);
imlib_grayscale_to_rgb(&grayscale_color, &rgb_color);
return mp_obj_new_tuple(3, (mp_obj_t[3])
{mp_obj_new_int(rgb_color.red),
mp_obj_new_int(rgb_color.green),
mp_obj_new_int(rgb_color.blue)});
}
// The image module (it's different from the Image class!)
mp_obj_t py_image_load_image(mp_obj_t path_obj)
@ -1502,6 +1561,11 @@ static mp_obj_t py_image_match_descriptor(uint n_args, const mp_obj_t *args, mp_
return match_obj;
}
/* Color space functions */
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_rgb_to_lab_obj, py_image_rgb_to_lab);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_lab_to_rgb_obj, py_image_lab_to_rgb);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_rgb_to_grayscale_obj, py_image_rgb_to_grayscale);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_grayscale_to_rgb_obj, py_image_grayscale_to_rgb);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_load_image_obj, py_image_load_image);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_load_cascade_obj, 1, py_image_load_cascade);
@ -1510,18 +1574,26 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_save_descriptor_obj, 3, py_image_save
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_match_descriptor_obj, 3, py_image_match_descriptor);
static const mp_map_elem_t globals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_image) },
// Descriptor types
{ MP_OBJ_NEW_QSTR(MP_QSTR_LBP), MP_OBJ_NEW_SMALL_INT(DESC_LBP)},
{ MP_OBJ_NEW_QSTR(MP_QSTR_FREAK), MP_OBJ_NEW_SMALL_INT(DESC_FREAK)},
{MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_image)},
/* Descriptor types */
{MP_OBJ_NEW_QSTR(MP_QSTR_LBP), MP_OBJ_NEW_SMALL_INT(DESC_LBP)},
{MP_OBJ_NEW_QSTR(MP_QSTR_FREAK), MP_OBJ_NEW_SMALL_INT(DESC_FREAK)},
/* Color space functions */
{MP_OBJ_NEW_QSTR(MP_QSTR_rgb_to_lab), (mp_obj_t)&py_image_rgb_to_lab_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_lab_to_rgb), (mp_obj_t)&py_image_lab_to_rgb_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_rgb_to_grayscale), (mp_obj_t)&py_image_rgb_to_grayscale_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_grayscale_to_rgb), (mp_obj_t)&py_image_grayscale_to_rgb_obj},
// Image module functions
{ MP_OBJ_NEW_QSTR(MP_QSTR_Image), (mp_obj_t)&py_image_load_image_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_HaarCascade), (mp_obj_t)&py_image_load_cascade_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_load_descriptor), (mp_obj_t)&py_image_load_descriptor_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_save_descriptor), (mp_obj_t)&py_image_save_descriptor_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_match_descriptor), (mp_obj_t)&py_image_match_descriptor_obj },
{MP_OBJ_NEW_QSTR(MP_QSTR_Image), (mp_obj_t)&py_image_load_image_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_HaarCascade), (mp_obj_t)&py_image_load_cascade_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_load_descriptor), (mp_obj_t)&py_image_load_descriptor_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_save_descriptor), (mp_obj_t)&py_image_save_descriptor_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_match_descriptor), (mp_obj_t)&py_image_match_descriptor_obj},
{ NULL, NULL }
};
STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table);
const mp_obj_module_t image_module = {