mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Add scale, blit and blend functions
* Add scale, blit, blend and rainbow * Update imlib header * Export new functions to MP
This commit is contained in:
parent
d151388e73
commit
f1861a332a
@ -1 +1 @@
|
||||
Subproject commit 6f78a8b2b3a96f1faa0261f7b044992aa65a39bb
|
||||
Subproject commit 44c005220f8d01e008f4c5c606c70e5868c19635
|
||||
@ -27,6 +27,22 @@
|
||||
__typeof__ (y) _y = (y); \
|
||||
src->data[_y*src->w+_x]=c; })
|
||||
|
||||
#define R565(p) \
|
||||
(uint8_t)((p>>3)&0x1F)
|
||||
|
||||
#define G565(p) \
|
||||
(uint8_t)(((p&0x07)<<3)|(p>>13))
|
||||
|
||||
#define B565(p) \
|
||||
(uint8_t)((p>>8)&0x1F)
|
||||
|
||||
#define RGB565(r, g, b)\
|
||||
(uint16_t)(((r&0x1F)<<3)|((g&0x3F)>>3)|(g<<13)|((b&0x1F)<<8))
|
||||
|
||||
#define SWAP(x)\
|
||||
({ uint16_t _x = (x); \
|
||||
(((_x & 0xff)<<8 |(_x & 0xff00) >> 8));})
|
||||
|
||||
#define MAX_GRAY_LEVEL (255)
|
||||
|
||||
/* RGB565->LAB lookup */
|
||||
@ -214,10 +230,6 @@ void imlib_erosion_filter(struct image *src, uint8_t *kernel, int k_size)
|
||||
xfree(dst);
|
||||
}
|
||||
|
||||
#define SWAP(x)\
|
||||
({ uint16_t _x = (x); \
|
||||
(((_x & 0xff)<<8 |(_x & 0xff00) >> 8));})
|
||||
|
||||
void imlib_threshold(image_t *src, image_t *dst, struct color *color, int threshold)
|
||||
{
|
||||
color_t lab1,lab2;
|
||||
@ -288,46 +300,191 @@ void imlib_subimage(struct image *src_img, struct image *dst_img, int x_off, int
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_blit(struct image *dst_img, struct image *src_img, int x_off, int y_off)
|
||||
void imlib_blit(struct image *src, struct image *dst, int x_off, int y_off)
|
||||
{
|
||||
int x, y;
|
||||
typeof(*src_img->data) *src = src_img->data;
|
||||
typeof(*dst_img->data) *dst = dst_img->data;
|
||||
typeof(*src->data) *srcp = src->data;
|
||||
typeof(*dst->data) *dstp = dst->data;
|
||||
|
||||
for (y=y_off; y<src_img->h+y_off; y++) {
|
||||
for (x=x_off; x<src_img->w+x_off; x++) {
|
||||
dst[y*dst_img->w+x]=*src++;
|
||||
for (y=y_off; y<src->h+y_off; y++) {
|
||||
for (x=x_off; x<src->w+x_off; x++) {
|
||||
dstp[y*dst->w+x]=*srcp++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_scale_image(struct image *src, struct image *dst)
|
||||
void imlib_blend(struct image *src, struct image *dst, int x_off, int y_off, uint8_t alpha)
|
||||
{
|
||||
uint16_t i,r, g, b;
|
||||
uint16_t spix, dpix;
|
||||
uint16_t *srcp = (uint16_t *)src->pixels;
|
||||
uint16_t *dstp = (uint16_t *)dst->pixels;
|
||||
|
||||
for (int y=y_off; y<src->h+y_off; y++) {
|
||||
i=y*dst->w;
|
||||
for (int x=x_off; x<src->w+x_off; x++) {
|
||||
spix = *srcp++;
|
||||
dpix = dstp[i+x];
|
||||
r=(alpha*R565(spix)+(100-alpha)*R565(dpix))/100;
|
||||
g=(alpha*G565(spix)+(100-alpha)*G565(dpix))/100;
|
||||
b=(alpha*B565(spix)+(100-alpha)*B565(dpix))/100;
|
||||
dstp[i+x]= RGB565(r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_scale_nearest(struct image *src, struct image *dst)
|
||||
{
|
||||
int x, y, i, j;
|
||||
uint8_t *t, *p;
|
||||
int w1 = src->w;
|
||||
int h1 = src->h;
|
||||
int w2 = dst->w;
|
||||
int h2 = dst->h;
|
||||
|
||||
int rat = 0;
|
||||
if (src->bpp ==1) {
|
||||
uint8_t *t, *p;
|
||||
uint8_t *src_data = src->pixels;
|
||||
uint8_t *dst_data = dst->pixels;
|
||||
int x_ratio = (int)((w1<<16)/w2) +1;
|
||||
int y_ratio = (int)((h1<<16)/h2) +1;
|
||||
|
||||
uint8_t *src_data = src->pixels;
|
||||
uint8_t *dst_data = dst->pixels;
|
||||
|
||||
int x_ratio = (int)((w1<<16)/w2) +1;
|
||||
int y_ratio = (int)((h1<<16)/h2) +1;
|
||||
|
||||
for (i=0;i<h2;i++){
|
||||
t = dst_data + i*w2;
|
||||
y = ((i*y_ratio)>>16);
|
||||
p = src_data + y*w1;
|
||||
rat = 0;
|
||||
for (j=0;j<w2;j++) {
|
||||
x = (rat>>16);
|
||||
*t++ = p[x];
|
||||
rat += x_ratio;
|
||||
for (i=0; i<h2; i++) {
|
||||
t = dst_data + i*w2;
|
||||
y = ((i*y_ratio)>>16);
|
||||
p = src_data + y*w1;
|
||||
rat = 0;
|
||||
for (j=0; j<w2; j++) {
|
||||
x = (rat>>16);
|
||||
*t++ = p[x];
|
||||
rat += x_ratio;
|
||||
}
|
||||
}
|
||||
} else if (src->bpp==2) {
|
||||
uint16_t *t, *p;
|
||||
uint16_t *src_data = (uint16_t *)src->pixels;
|
||||
uint16_t *dst_data = (uint16_t *)dst->pixels;
|
||||
int x_ratio = (int)((w1<<16)/w2) +1;
|
||||
int y_ratio = (int)((h1<<16)/h2) +1;
|
||||
|
||||
for (i=0; i<h2; i++) {
|
||||
t = dst_data + i*w2;
|
||||
y = ((i*y_ratio)>>16);
|
||||
p = src_data + y*w1;
|
||||
rat = 0;
|
||||
for (j=0; j<w2; j++) {
|
||||
x = (rat>>16);
|
||||
*t++ = p[x];
|
||||
rat += x_ratio;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_scale_bilinear(struct image *src, struct image *dst)
|
||||
{
|
||||
int w1 = src->w;
|
||||
int h1 = src->h;
|
||||
int w2 = dst->w;
|
||||
int h2 = dst->h;
|
||||
|
||||
int offset = 0 ;
|
||||
int x, y, index;
|
||||
|
||||
int r, g, b;
|
||||
uint16_t A, B, C, D;
|
||||
|
||||
float x_diff, y_diff;
|
||||
float x_ratio = ((float)(w1-1))/w2 ;
|
||||
float y_ratio = ((float)(h1-1))/h2 ;
|
||||
uint16_t *srcp = (uint16_t *)src->pixels;
|
||||
uint16_t *dstp = (uint16_t *)dst->pixels;
|
||||
|
||||
for (int i=0;i<h2;i++) {
|
||||
for (int j=0;j<w2;j++) {
|
||||
x = (int)(x_ratio * j) ;
|
||||
y = (int)(y_ratio * i) ;
|
||||
x_diff = (x_ratio * j) - x ;
|
||||
y_diff = (y_ratio * i) - y ;
|
||||
index = y*w1+x ;
|
||||
|
||||
A = srcp[index];
|
||||
B = srcp[index+1];
|
||||
C = srcp[index+w1];
|
||||
D = srcp[index+w1+1];
|
||||
|
||||
// Yb = Ar(1-w)(1-h) + Br(w)(1-h) + Cr(h)(1-w) + Dr(wh)
|
||||
r = (int)(R565(A)*(1-x_diff)*(1-y_diff) + R565(B)*(x_diff)*(1-y_diff) +
|
||||
R565(C)*(y_diff)*(1-x_diff) + R565(D)*(x_diff*y_diff));
|
||||
|
||||
// Yb = Ag(1-w)(1-h) + Bg(w)(1-h) + Cg(h)(1-w) + Dg(wh)
|
||||
g = (int)(G565(A)*(1-x_diff)*(1-y_diff) + G565(B)*(x_diff)*(1-y_diff) +
|
||||
G565(C)*(y_diff)*(1-x_diff) + G565(D)*(x_diff*y_diff));
|
||||
|
||||
// Yb = Ab(1-w)(1-h) + Bb(w)(1-h) + Cb(h)(1-w) + Db(wh)
|
||||
b =(int)(B565(A)*(1-x_diff)*(1-y_diff) + B565(B)*(x_diff)*(1-y_diff) +
|
||||
B565(C)*(y_diff)*(1-x_diff) + B565(D)*(x_diff*y_diff));
|
||||
|
||||
dstp[offset++] = RGB565(r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_scale_bilinear_gray(struct image *src, struct image *dst)
|
||||
{
|
||||
int w1 = src->w;
|
||||
int h1 = src->h;
|
||||
int w2 = dst->w;
|
||||
int h2 = dst->h;
|
||||
|
||||
int offset = 0 ;
|
||||
int A, B, C, D, x, y, index, gray ;
|
||||
|
||||
float x_diff, y_diff;
|
||||
float x_ratio = ((float)(w1-1))/w2 ;
|
||||
float y_ratio = ((float)(h1-1))/h2 ;
|
||||
|
||||
uint8_t *srcp = src->pixels;
|
||||
uint8_t *dstp = dst->pixels;
|
||||
|
||||
for (int i=0;i<h2;i++) {
|
||||
for (int j=0;j<w2;j++) {
|
||||
x = (int)(x_ratio * j) ;
|
||||
y = (int)(y_ratio * i) ;
|
||||
x_diff = (x_ratio * j) - x ;
|
||||
y_diff = (y_ratio * i) - y ;
|
||||
|
||||
index = y*w1+x;
|
||||
A = srcp[index];
|
||||
B = srcp[index+1];
|
||||
C = srcp[index+w1];
|
||||
D = srcp[index+w1+1];
|
||||
|
||||
// Y = A(1-w)(1-h) + B(w)(1-h) + C(h)(1-w) + Dwh
|
||||
gray = (int)(A*(1-x_diff)*(1-y_diff) + B*(x_diff)*(1-y_diff) +
|
||||
C*(y_diff)*(1-x_diff) + D*(x_diff*y_diff));
|
||||
|
||||
dstp[offset++] = gray ;
|
||||
}
|
||||
}
|
||||
}
|
||||
void imlib_scale(struct image *src, struct image *dst, interp_t interp)
|
||||
{
|
||||
switch (interp) {
|
||||
case INTERP_NEAREST:
|
||||
imlib_scale_nearest(src, dst);
|
||||
break;
|
||||
case INTERP_BILINEAR:
|
||||
if (src->bpp==2) {
|
||||
imlib_scale_bilinear(src, dst);
|
||||
} else {
|
||||
imlib_scale_bilinear_gray(src, dst);
|
||||
}
|
||||
break;
|
||||
case INTERP_BICUBIC:
|
||||
//NOT implemented
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -153,6 +153,12 @@ typedef struct cascade {
|
||||
int8_t *rectangles_array;
|
||||
} cascade_t;
|
||||
|
||||
typedef enum interp {
|
||||
INTERP_NEAREST,
|
||||
INTERP_BILINEAR,
|
||||
INTERP_BICUBIC
|
||||
} interp_t;
|
||||
|
||||
/* Point functions */
|
||||
point_t *point_alloc(int x, int y);
|
||||
int point_equal(point_t *p1, point_t *p2);
|
||||
@ -179,6 +185,7 @@ 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);
|
||||
void imlib_median_filter(image_t *src, int r);
|
||||
void imlib_erosion_filter(struct image *src, uint8_t *kernel, int k_size);
|
||||
@ -204,12 +211,15 @@ array_t *surf_match(surf_t *surf1, surf_t *surf2);
|
||||
void surf_draw_ipts(image_t *image, array_t *ipts);
|
||||
void surf_dump_ipts(array_t *ipts);
|
||||
|
||||
void imlib_scale_image(struct image *src, struct image *dst);
|
||||
/* Drawing functions */
|
||||
void imlib_draw_rectangle(struct image *image, struct rectangle *r);
|
||||
void imlib_draw_circle(struct image *image, int cx, int cy, int r);
|
||||
int imlib_image_mean(struct image *src);
|
||||
void imlib_subimage(struct image *src_img, struct image *dst_img, int x_off, int y_off);
|
||||
void imlib_blit(struct image *dst_img, struct image *src_img, int x_off, int y_off);
|
||||
|
||||
/* Misc */
|
||||
void imlib_scale(struct image *src, struct image *dst, interp_t interp);
|
||||
void imlib_blit(struct image *src, struct image *dst, int x_off, int y_off);
|
||||
void imlib_blend(struct image *src, struct image *dst, int x_off, int y_off, uint8_t alpha);
|
||||
void imlib_subimage(struct image *src, struct image *dst, int x_off, int y_off);
|
||||
|
||||
/* Image file functions */
|
||||
int ppm_read(image_t *img, const char *path);
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#include "imlib.h"
|
||||
#include "array.h"
|
||||
#include "sensor.h"
|
||||
#include "xalloc.h"
|
||||
#include "py_assert.h"
|
||||
#include "py_image.h"
|
||||
#include "py_file.h"
|
||||
@ -139,16 +140,39 @@ static mp_obj_t py_image_save(uint n_args, const mp_obj_t *args, mp_map_t *kw_ar
|
||||
return mp_const_true;
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_blit(mp_obj_t dst_image_obj, mp_obj_t offset_obj, mp_obj_t src_image_obj)
|
||||
static mp_obj_t py_image_scale(mp_obj_t image_obj, mp_obj_t size_obj)
|
||||
{
|
||||
int w,h;
|
||||
mp_obj_t *array;
|
||||
image_t *src_image = NULL;
|
||||
|
||||
/* get C image pointer */
|
||||
src_image = py_image_cobj(image_obj);
|
||||
|
||||
/* get x,y */
|
||||
mp_obj_get_array_fixed_n(size_obj, 2, &array);
|
||||
w = mp_obj_get_int(array[0]);
|
||||
h = mp_obj_get_int(array[1]);
|
||||
|
||||
image_t dst_image = {
|
||||
.w=w,
|
||||
.h=h,
|
||||
.bpp=src_image->bpp,
|
||||
.pixels=xalloc(w*h*src_image->bpp)
|
||||
};
|
||||
|
||||
imlib_scale(src_image, &dst_image, INTERP_BILINEAR);
|
||||
|
||||
*src_image = dst_image;
|
||||
return image_obj;
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_blit(mp_obj_t dst_image_obj, mp_obj_t src_image_obj, mp_obj_t offset_obj)
|
||||
{
|
||||
int x,y;
|
||||
image_t *src_image = NULL;
|
||||
image_t *dst_image = NULL;
|
||||
|
||||
/* sanity checks */
|
||||
PY_ASSERT_TRUE(sensor.framesize <= FRAMESIZE_QQVGA);
|
||||
PY_ASSERT_TRUE(sensor.pixformat == PIXFORMAT_GRAYSCALE);
|
||||
|
||||
/* get C image pointer */
|
||||
src_image = py_image_cobj(src_image_obj);
|
||||
dst_image = py_image_cobj(dst_image_obj);
|
||||
@ -165,7 +189,36 @@ static mp_obj_t py_image_blit(mp_obj_t dst_image_obj, mp_obj_t offset_obj, mp_ob
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
imlib_blit(dst_image, src_image, x, y);
|
||||
imlib_blit(src_image, dst_image, x, y);
|
||||
return mp_const_true;
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_blend(mp_obj_t dst_image_obj,
|
||||
mp_obj_t src_image_obj, mp_obj_t param_obj)
|
||||
{
|
||||
int x,y;
|
||||
float alpha;
|
||||
image_t *src_image = NULL;
|
||||
image_t *dst_image = NULL;
|
||||
|
||||
/* get C image pointer */
|
||||
src_image = py_image_cobj(src_image_obj);
|
||||
dst_image = py_image_cobj(dst_image_obj);
|
||||
|
||||
/* get x,y,alpha */
|
||||
mp_obj_t *array;
|
||||
mp_obj_get_array_fixed_n(param_obj, 3, &array);
|
||||
x = mp_obj_get_int(array[0]);
|
||||
y = mp_obj_get_int(array[1]);
|
||||
alpha = mp_obj_get_float(array[2]);
|
||||
|
||||
if ((src_image->w+x)>dst_image->w ||
|
||||
(src_image->h+y)>dst_image->h) {
|
||||
printf("src image > dst image\n");
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
imlib_blend(src_image, dst_image, x, y, (uint8_t)(alpha*100.0f));
|
||||
return mp_const_true;
|
||||
}
|
||||
|
||||
@ -226,6 +279,27 @@ static mp_obj_t py_image_threshold(mp_obj_t image_obj, mp_obj_t color_obj, mp_ob
|
||||
return bimage_obj;
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_rainbow(mp_obj_t src_image_obj)
|
||||
{
|
||||
image_t *src_image = NULL;
|
||||
|
||||
/* get C image pointer */
|
||||
src_image = py_image_cobj(src_image_obj);
|
||||
/* sanity checks */
|
||||
PY_ASSERT_TRUE(src_image->bpp==1);
|
||||
|
||||
image_t dst_image = {
|
||||
.w=src_image->w,
|
||||
.h=src_image->h,
|
||||
.bpp=2,
|
||||
.pixels=xalloc(src_image->w*src_image->h*2)
|
||||
};
|
||||
|
||||
imlib_rainbow(src_image, &dst_image);
|
||||
*src_image = dst_image;
|
||||
return src_image_obj;
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_draw_circle(mp_obj_t image_obj, mp_obj_t c_obj, mp_obj_t r_obj)
|
||||
{
|
||||
int cx, cy, r;
|
||||
@ -498,10 +572,13 @@ mp_obj_t py_image_load_cascade(mp_obj_t path_obj)
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_size_obj, py_image_size);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_save_obj, 2, py_image_save);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_scale_obj, py_image_scale);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_blit_obj, py_image_blit);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_blend_obj, py_image_blend);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_histeq_obj, py_image_histeq);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_median_obj, 1, py_image_median);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_threshold_obj, py_image_threshold);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_rainbow_obj, py_image_rainbow);
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_draw_circle_obj, py_image_draw_circle);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_draw_rectangle_obj, py_image_draw_rectangle);
|
||||
@ -518,10 +595,13 @@ static const mp_map_elem_t locals_dict_table[] = {
|
||||
|
||||
/* basic image functions */
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_save), (mp_obj_t)&py_image_save_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_scale), (mp_obj_t)&py_image_scale_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_blit), (mp_obj_t)&py_image_blit_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_blend), (mp_obj_t)&py_image_blend_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_histeq), (mp_obj_t)&py_image_histeq_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_median), (mp_obj_t)&py_image_median_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_threshold), (mp_obj_t)&py_image_threshold_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_rainbow), (mp_obj_t)&py_image_rainbow_obj},
|
||||
|
||||
/* drawing functions */
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_draw_circle), (mp_obj_t)&py_image_draw_circle_obj},
|
||||
@ -560,6 +640,14 @@ mp_obj_t py_image(int w, int h, int bpp, void *pixels)
|
||||
return o;
|
||||
}
|
||||
|
||||
mp_obj_t py_image_from_struct(image_t *image)
|
||||
{
|
||||
py_image_obj_t *o = m_new_obj(py_image_obj_t);
|
||||
o->base.type = &py_image_type;
|
||||
o->_cobj =*image;
|
||||
return o;
|
||||
}
|
||||
|
||||
#if 0
|
||||
typedef struct _mp_obj_array_it_t {
|
||||
mp_obj_base_t base;
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
#ifndef __PY_IMAGE_H__
|
||||
#define __PY_IMAGE_H__
|
||||
#include "imlib.h"
|
||||
mp_obj_t py_image_load_image(mp_obj_t path_obj);
|
||||
mp_obj_t py_image_load_cascade(mp_obj_t path_obj);
|
||||
mp_obj_t py_image(int width, int height, int bpp, void *pixels);
|
||||
mp_obj_t py_image_from_struct(image_t *image);
|
||||
void *py_image_cobj(mp_obj_t image);
|
||||
#endif /* __PY_IMAGE_H__ */
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user