Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
7512 lines (6643 sloc) 327 KB
/*
* This file is part of the OpenMV project.
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
* This work is licensed under the MIT license, see the file LICENSE for details.
*
* Image Python module.
*
*/
#include <arm_math.h>
#include <mp.h>
#include "imlib.h"
#include "array.h"
#include "sensor.h"
#include "ff_wrapper.h"
#include "xalloc.h"
#include "fb_alloc.h"
#include "framebuffer.h"
#include "py_assert.h"
#include "py_helper.h"
#include "py_image.h"
#include "omv_boardconfig.h"
#include "py/runtime0.h"
#include "py/runtime.h"
static const mp_obj_type_t py_cascade_type;
static const mp_obj_type_t py_image_type;
extern const char *ffs_strerror(FRESULT res);
// Haar Cascade ///////////////////////////////////////////////////////////////
typedef struct _py_cascade_obj_t {
mp_obj_base_t base;
struct cascade _cobj;
} py_cascade_obj_t;
void *py_cascade_cobj(mp_obj_t cascade)
{
PY_ASSERT_TYPE(cascade, &py_cascade_type);
return &((py_cascade_obj_t *)cascade)->_cobj;
}
static void py_cascade_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
{
py_cascade_obj_t *self = self_in;
mp_printf(print, "{\"width\":%d, \"height\":%d, \"n_stages\":%d, \"n_features\":%d, \"n_rectangles\":%d}",
self->_cobj.window.w, self->_cobj.window.h, self->_cobj.n_stages,
self->_cobj.n_features, self->_cobj.n_rectangles);
}
static const mp_obj_type_t py_cascade_type = {
{ &mp_type_type },
.name = MP_QSTR_Cascade,
.print = py_cascade_print,
};
// Keypoints object ///////////////////////////////////////////////////////////
#ifdef IMLIB_ENABLE_FIND_KEYPOINTS
typedef struct _py_kp_obj_t {
mp_obj_base_t base;
array_t *kpts;
int threshold;
bool normalized;
} py_kp_obj_t;
static void py_kp_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
{
py_kp_obj_t *self = self_in;
mp_printf(print, "{\"size\":%d, \"threshold\":%d, \"normalized\":%d}", array_length(self->kpts), self->threshold, self->normalized);
}
mp_obj_t py_kp_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
py_kp_obj_t *self = MP_OBJ_TO_PTR(self_in);
switch (op) {
case MP_UNARY_OP_LEN:
return MP_OBJ_NEW_SMALL_INT(array_length(self->kpts));
default:
return MP_OBJ_NULL; // op not supported
}
}
static mp_obj_t py_kp_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value)
{
if (value == MP_OBJ_SENTINEL) { // load
py_kp_obj_t *self = self_in;
int size = array_length(self->kpts);
int i = mp_get_index(self->base.type, size, index, false);
kp_t *kp = array_at(self->kpts, i);
return mp_obj_new_tuple(5, (mp_obj_t []) {mp_obj_new_int(kp->x),
mp_obj_new_int(kp->y),
mp_obj_new_int(kp->score),
mp_obj_new_int(kp->octave),
mp_obj_new_int(kp->angle)});
}
return MP_OBJ_NULL; // op not supported
}
static const mp_obj_type_t py_kp_type = {
{ &mp_type_type },
.name = MP_QSTR_kp_desc,
.print = py_kp_print,
.subscr = py_kp_subscr,
.unary_op = py_kp_unary_op,
};
py_kp_obj_t *py_kpts_obj(mp_obj_t kpts_obj)
{
PY_ASSERT_TYPE(kpts_obj, &py_kp_type);
return kpts_obj;
}
#endif // IMLIB_ENABLE_FIND_KEYPOINTS
// LBP descriptor /////////////////////////////////////////////////////////////
#ifdef IMLIB_ENABLE_FIND_LBP
typedef struct _py_lbp_obj_t {
mp_obj_base_t base;
uint8_t *hist;
} py_lbp_obj_t;
static void py_lbp_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
{
mp_printf(print, "{}");
}
static const mp_obj_type_t py_lbp_type = {
{ &mp_type_type },
.name = MP_QSTR_lbp_desc,
.print = py_lbp_print,
};
#endif // IMLIB_ENABLE_FIND_LBP
// Keypoints Match Object /////////////////////////////////////////////////////
#ifdef IMLIB_ENABLE_FIND_KEYPOINTS
#define kptmatch_obj_size 9
typedef struct _py_kptmatch_obj_t {
mp_obj_base_t base;
mp_obj_t cx, cy;
mp_obj_t x, y, w, h;
mp_obj_t count;
mp_obj_t theta;
mp_obj_t match;
} py_kptmatch_obj_t;
static void py_kptmatch_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
{
py_kptmatch_obj_t *self = self_in;
mp_printf(print, "{\"cx\":%d, \"cy\":%d, \"x\":%d, \"y\":%d, \"w\":%d, \"h\":%d, \"count\":%d, \"theta\":%d}",
mp_obj_get_int(self->cx), mp_obj_get_int(self->cy), mp_obj_get_int(self->x), mp_obj_get_int(self->y),
mp_obj_get_int(self->w), mp_obj_get_int(self->h), mp_obj_get_int(self->count), mp_obj_get_int(self->theta));
}
static mp_obj_t py_kptmatch_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value)
{
if (value == MP_OBJ_SENTINEL) { // load
py_kptmatch_obj_t *self = self_in;
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(kptmatch_obj_size, index, &slice)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported"));
}
mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL);
mp_seq_copy(result->items, &(self->x) + slice.start, result->len, mp_obj_t);
return result;
}
switch (mp_get_index(self->base.type, kptmatch_obj_size, index, false)) {
case 0: return self->cx;
case 1: return self->cy;
case 2: return self->x;
case 3: return self->y;
case 4: return self->w;
case 5: return self->h;
case 6: return self->count;
case 7: return self->theta;
case 8: return self->match;
}
}
return MP_OBJ_NULL; // op not supported
}
mp_obj_t py_kptmatch_cx(mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->cx; }
mp_obj_t py_kptmatch_cy(mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->cy; }
mp_obj_t py_kptmatch_x (mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->x; }
mp_obj_t py_kptmatch_y (mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->y; }
mp_obj_t py_kptmatch_w (mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->w; }
mp_obj_t py_kptmatch_h (mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->h; }
mp_obj_t py_kptmatch_count(mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->count; }
mp_obj_t py_kptmatch_theta(mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->theta; }
mp_obj_t py_kptmatch_match(mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->match; }
mp_obj_t py_kptmatch_rect(mp_obj_t self_in) {
return mp_obj_new_tuple(4, (mp_obj_t []) {((py_kptmatch_obj_t *) self_in)->x,
((py_kptmatch_obj_t *) self_in)->y,
((py_kptmatch_obj_t *) self_in)->w,
((py_kptmatch_obj_t *) self_in)->h});
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_cx_obj, py_kptmatch_cx);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_cy_obj, py_kptmatch_cy);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_x_obj, py_kptmatch_x);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_y_obj, py_kptmatch_y);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_w_obj, py_kptmatch_w);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_h_obj, py_kptmatch_h);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_count_obj, py_kptmatch_count);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_theta_obj, py_kptmatch_theta);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_match_obj, py_kptmatch_match);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_rect_obj, py_kptmatch_rect);
STATIC const mp_rom_map_elem_t py_kptmatch_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_cx), MP_ROM_PTR(&py_kptmatch_cx_obj) },
{ MP_ROM_QSTR(MP_QSTR_cy), MP_ROM_PTR(&py_kptmatch_cy_obj) },
{ MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&py_kptmatch_x_obj) },
{ MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&py_kptmatch_y_obj) },
{ MP_ROM_QSTR(MP_QSTR_w), MP_ROM_PTR(&py_kptmatch_w_obj) },
{ MP_ROM_QSTR(MP_QSTR_h), MP_ROM_PTR(&py_kptmatch_h_obj) },
{ MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&py_kptmatch_count_obj) },
{ MP_ROM_QSTR(MP_QSTR_theta), MP_ROM_PTR(&py_kptmatch_theta_obj) },
{ MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&py_kptmatch_match_obj) },
{ MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&py_kptmatch_rect_obj) }
};
STATIC MP_DEFINE_CONST_DICT(py_kptmatch_locals_dict, py_kptmatch_locals_dict_table);
static const mp_obj_type_t py_kptmatch_type = {
{ &mp_type_type },
.name = MP_QSTR_kptmatch,
.print = py_kptmatch_print,
.subscr = py_kptmatch_subscr,
.locals_dict = (mp_obj_t) &py_kptmatch_locals_dict
};
#endif // IMLIB_ENABLE_FIND_KEYPOINTS
// Image //////////////////////////////////////////////////////////////////////
typedef struct _py_image_obj_t {
mp_obj_base_t base;
image_t _cobj;
} py_image_obj_t;
void *py_image_cobj(mp_obj_t img_obj)
{
PY_ASSERT_TYPE(img_obj, &py_image_type);
return &((py_image_obj_t *)img_obj)->_cobj;
}
static void py_image_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
{
py_image_obj_t *self = self_in;
switch(self->_cobj.bpp) {
case IMAGE_BPP_BINARY: {
mp_printf(print, "{\"w\":%d, \"h\":%d, \"type\"=\"binary\", \"size\":%d}",
self->_cobj.w, self->_cobj.h,
((self->_cobj.w + UINT32_T_MASK) >> UINT32_T_SHIFT) * self->_cobj.h);
break;
}
case IMAGE_BPP_GRAYSCALE: {
mp_printf(print, "{\"w\":%d, \"h\":%d, \"type\"=\"grayscale\", \"size\":%d}",
self->_cobj.w, self->_cobj.h,
(self->_cobj.w * self->_cobj.h) * sizeof(uint8_t));
break;
}
case IMAGE_BPP_RGB565: {
mp_printf(print, "{\"w\":%d, \"h\":%d, \"type\"=\"rgb565\", \"size\":%d}",
self->_cobj.w, self->_cobj.h,
(self->_cobj.w * self->_cobj.h) * sizeof(uint16_t));
break;
}
default: {
if((self->_cobj.data[0] == 0xFE) && (self->_cobj.data[self->_cobj.bpp-1] == 0xFE)) { // for ide
print->print_strn(print->data, (const char *) self->_cobj.data, self->_cobj.bpp);
} else { // not for ide
mp_printf(print, "{\"w\":%d, \"h\":%d, \"type\"=\"jpeg\", \"size\":%d}",
self->_cobj.w, self->_cobj.h,
self->_cobj.bpp);
}
break;
}
}
}
static mp_obj_t py_image_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value)
{
py_image_obj_t *self = self_in;
if (value == MP_OBJ_NULL) { // delete
} else if (value == MP_OBJ_SENTINEL) { // load
switch (self->_cobj.bpp) {
case IMAGE_BPP_BINARY: {
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(self->_cobj.w * self->_cobj.h, index, &slice)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported"));
}
mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL);
for (mp_uint_t i = 0; i < result->len; i++) {
result->items[i] = mp_obj_new_int(IMAGE_GET_BINARY_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w));
}
return result;
}
mp_uint_t i = mp_get_index(self->base.type, self->_cobj.w * self->_cobj.h, index, false);
return mp_obj_new_int(IMAGE_GET_BINARY_PIXEL(&(self->_cobj), i % self->_cobj.w, i / self->_cobj.w));
}
case IMAGE_BPP_BAYER:
case IMAGE_BPP_GRAYSCALE: {
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(self->_cobj.w * self->_cobj.h, index, &slice)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported"));
}
mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL);
for (mp_uint_t i = 0; i < result->len; i++) {
uint8_t p = IMAGE_GET_GRAYSCALE_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w);
result->items[i] = mp_obj_new_int(p);
}
return result;
}
mp_uint_t i = mp_get_index(self->base.type, self->_cobj.w * self->_cobj.h, index, false);
uint8_t p = IMAGE_GET_GRAYSCALE_PIXEL(&(self->_cobj), i % self->_cobj.w, i / self->_cobj.w);
return mp_obj_new_int(p);
}
case IMAGE_BPP_RGB565: {
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(self->_cobj.w * self->_cobj.h, index, &slice)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported"));
}
mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL);
for (mp_uint_t i = 0; i < result->len; i++) {
uint16_t p = IMAGE_GET_RGB565_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w);
result->items[i] = mp_obj_new_tuple(3, (mp_obj_t []) {mp_obj_new_int(COLOR_RGB565_TO_R8(p)),
mp_obj_new_int(COLOR_RGB565_TO_G8(p)),
mp_obj_new_int(COLOR_RGB565_TO_B8(p))});
}
return result;
}
mp_uint_t i = mp_get_index(self->base.type, self->_cobj.w * self->_cobj.h, index, false);
uint16_t p = IMAGE_GET_RGB565_PIXEL(&(self->_cobj), i % self->_cobj.w, i / self->_cobj.w);
return mp_obj_new_tuple(3, (mp_obj_t []) {mp_obj_new_int(COLOR_RGB565_TO_R8(p)),
mp_obj_new_int(COLOR_RGB565_TO_G8(p)),
mp_obj_new_int(COLOR_RGB565_TO_B8(p))});
}
default: {
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(self->_cobj.bpp, index, &slice)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported"));
}
mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL);
for (mp_uint_t i = 0; i < result->len; i++) {
result->items[i] = mp_obj_new_int(self->_cobj.data[slice.start + i]);
}
return result;
}
mp_uint_t i = mp_get_index(self->base.type, self->_cobj.bpp, index, false);
return mp_obj_new_int(self->_cobj.data[i]);
}
}
} else { // store
switch (self->_cobj.bpp) {
case IMAGE_BPP_BINARY: {
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(self->_cobj.w * self->_cobj.h, index, &slice)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported"));
}
if (MP_OBJ_IS_TYPE(value, &mp_type_list)) {
mp_uint_t value_l_len;
mp_obj_t *value_l;
mp_obj_get_array(value, &value_l_len, &value_l);
PY_ASSERT_TRUE_MSG(value_l_len == (slice.stop - slice.start), "cannot grow or shrink image");
for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) {
IMAGE_PUT_BINARY_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w, mp_obj_get_int(value_l[i]));
}
} else {
mp_int_t v = mp_obj_get_int(value);
for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) {
IMAGE_PUT_BINARY_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w, v);
}
}
return mp_const_none;
}
mp_uint_t i = mp_get_index(self->base.type, self->_cobj.w * self->_cobj.h, index, false);
IMAGE_PUT_BINARY_PIXEL(&(self->_cobj), i % self->_cobj.w, i / self->_cobj.w, mp_obj_get_int(value));
return mp_const_none;
}
case IMAGE_BPP_BAYER:
case IMAGE_BPP_GRAYSCALE: {
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(self->_cobj.w * self->_cobj.h, index, &slice)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported"));
}
if (MP_OBJ_IS_TYPE(value, &mp_type_list)) {
mp_uint_t value_l_len;
mp_obj_t *value_l;
mp_obj_get_array(value, &value_l_len, &value_l);
PY_ASSERT_TRUE_MSG(value_l_len == (slice.stop - slice.start), "cannot grow or shrink image");
for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) {
uint8_t p = mp_obj_get_int(value_l[i]);
IMAGE_PUT_GRAYSCALE_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w, p);
}
} else {
uint8_t p = mp_obj_get_int(value);
for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) {
IMAGE_PUT_GRAYSCALE_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w, p);
}
}
return mp_const_none;
}
mp_uint_t i = mp_get_index(self->base.type, self->_cobj.w * self->_cobj.h, index, false);
uint8_t p = mp_obj_get_int(value);
IMAGE_PUT_GRAYSCALE_PIXEL(&(self->_cobj), i % self->_cobj.w, i / self->_cobj.w, p);
return mp_const_none;
}
case IMAGE_BPP_RGB565: {
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(self->_cobj.w * self->_cobj.h, index, &slice)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported"));
}
if (MP_OBJ_IS_TYPE(value, &mp_type_list)) {
mp_uint_t value_l_len;
mp_obj_t *value_l;
mp_obj_get_array(value, &value_l_len, &value_l);
PY_ASSERT_TRUE_MSG(value_l_len == (slice.stop - slice.start), "cannot grow or shrink image");
for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) {
mp_obj_t *value_2;
mp_obj_get_array_fixed_n(value_l[i], 3, &value_2);
uint16_t p = COLOR_R8_G8_B8_TO_RGB565(mp_obj_get_int(value_2[0]), mp_obj_get_int(value_2[1]), mp_obj_get_int(value_2[2]));
IMAGE_PUT_RGB565_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w, p);
}
} else {
mp_obj_t *value_2;
mp_obj_get_array_fixed_n(value, 3, &value_2);
uint16_t p = COLOR_R8_G8_B8_TO_RGB565(mp_obj_get_int(value_2[0]), mp_obj_get_int(value_2[1]), mp_obj_get_int(value_2[2]));
for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) {
IMAGE_PUT_RGB565_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w, p);
}
}
return mp_const_none;
}
mp_uint_t i = mp_get_index(self->base.type, self->_cobj.w * self->_cobj.h, index, false);
mp_obj_t *value_2;
mp_obj_get_array_fixed_n(value, 3, &value_2);
uint16_t p = COLOR_R8_G8_B8_TO_RGB565(mp_obj_get_int(value_2[0]), mp_obj_get_int(value_2[1]), mp_obj_get_int(value_2[2]));
IMAGE_PUT_RGB565_PIXEL(&(self->_cobj), i % self->_cobj.w, i / self->_cobj.w, p);
return mp_const_none;
}
default: {
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(self->_cobj.bpp, index, &slice)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported"));
}
if (MP_OBJ_IS_TYPE(value, &mp_type_list)) {
mp_uint_t value_l_len;
mp_obj_t *value_l;
mp_obj_get_array(value, &value_l_len, &value_l);
PY_ASSERT_TRUE_MSG(value_l_len == (slice.stop - slice.start), "cannot grow or shrink image");
for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) {
self->_cobj.data[slice.start + i] = mp_obj_get_int(value_l[i]);
}
} else {
mp_int_t v = mp_obj_get_int(value);
for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) {
self->_cobj.data[slice.start + i] = v;
}
}
return mp_const_none;
}
mp_uint_t i = mp_get_index(self->base.type, self->_cobj.bpp, index, false);
self->_cobj.data[i] = mp_obj_get_int(value);
return mp_const_none;
}
}
}
return MP_OBJ_NULL; // op not supported
}
static mp_int_t py_image_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags)
{
py_image_obj_t *self = self_in;
if (flags == MP_BUFFER_READ) {
bufinfo->buf = self->_cobj.data;
bufinfo->len = image_size(&self->_cobj);
bufinfo->typecode = 'b';
return 0;
} else { // Can't write to an image!
bufinfo->buf = NULL;
bufinfo->len = 0;
bufinfo->typecode = -1;
return 1;
}
}
////////////////
// Basic Methods
////////////////
static mp_obj_t py_image_width(mp_obj_t img_obj)
{
return mp_obj_new_int(((image_t *) py_image_cobj(img_obj))->w);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_width_obj, py_image_width);
static mp_obj_t py_image_height(mp_obj_t img_obj)
{
return mp_obj_new_int(((image_t *) py_image_cobj(img_obj))->h);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_height_obj, py_image_height);
static mp_obj_t py_image_format(mp_obj_t img_obj)
{
switch (((image_t *) py_image_cobj(img_obj))->bpp) {
case IMAGE_BPP_BINARY: return mp_obj_new_int(PIXFORMAT_BINARY);
case IMAGE_BPP_GRAYSCALE: return mp_obj_new_int(PIXFORMAT_GRAYSCALE);
case IMAGE_BPP_RGB565: return mp_obj_new_int(PIXFORMAT_RGB565);
case IMAGE_BPP_BAYER: return mp_obj_new_int(PIXFORMAT_BAYER);
default: return mp_obj_new_int(PIXFORMAT_JPEG);
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_format_obj, py_image_format);
static mp_obj_t py_image_size(mp_obj_t img_obj)
{
return mp_obj_new_int(image_size((image_t *) py_image_cobj(img_obj)));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_size_obj, py_image_size);
STATIC mp_obj_t py_image_get_pixel(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]);
const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 1, 2, &arg_vec);
int arg_x = mp_obj_get_int(arg_vec[0]);
int arg_y = mp_obj_get_int(arg_vec[1]);
bool arg_rgbtuple =
py_helper_keyword_int(n_args, args, offset, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgbtuple), arg_img->bpp == IMAGE_BPP_RGB565);
if ((!IM_X_INSIDE(arg_img, arg_x)) || (!IM_Y_INSIDE(arg_img, arg_y))) {
return mp_const_none;
}
switch (arg_img->bpp) {
case IMAGE_BPP_BINARY: {
if (arg_rgbtuple) {
int pixel = IMAGE_GET_BINARY_PIXEL(arg_img, arg_x, arg_y);
mp_obj_t pixel_tuple[3];
pixel_tuple[0] = mp_obj_new_int(COLOR_RGB565_TO_R8(COLOR_BINARY_TO_RGB565(pixel)));
pixel_tuple[1] = mp_obj_new_int(COLOR_RGB565_TO_G8(COLOR_BINARY_TO_RGB565(pixel)));
pixel_tuple[2] = mp_obj_new_int(COLOR_RGB565_TO_B8(COLOR_BINARY_TO_RGB565(pixel)));
return mp_obj_new_tuple(3, pixel_tuple);
} else {
return mp_obj_new_int(IMAGE_GET_BINARY_PIXEL(arg_img, arg_x, arg_y));
}
}
case IMAGE_BPP_GRAYSCALE: {
if (arg_rgbtuple) {
int pixel = IMAGE_GET_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y);
mp_obj_t pixel_tuple[3];
pixel_tuple[0] = mp_obj_new_int(COLOR_RGB565_TO_R8(COLOR_GRAYSCALE_TO_RGB565(pixel)));
pixel_tuple[1] = mp_obj_new_int(COLOR_RGB565_TO_G8(COLOR_GRAYSCALE_TO_RGB565(pixel)));
pixel_tuple[2] = mp_obj_new_int(COLOR_RGB565_TO_B8(COLOR_GRAYSCALE_TO_RGB565(pixel)));
return mp_obj_new_tuple(3, pixel_tuple);
} else {
return mp_obj_new_int(IMAGE_GET_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y));
}
}
case IMAGE_BPP_RGB565: {
if (arg_rgbtuple) {
int pixel = IMAGE_GET_RGB565_PIXEL(arg_img, arg_x, arg_y);
mp_obj_t pixel_tuple[3];
pixel_tuple[0] = mp_obj_new_int(COLOR_R5_TO_R8(COLOR_RGB565_TO_R5(pixel)));
pixel_tuple[1] = mp_obj_new_int(COLOR_G6_TO_G8(COLOR_RGB565_TO_G6(pixel)));
pixel_tuple[2] = mp_obj_new_int(COLOR_B5_TO_B8(COLOR_RGB565_TO_B5(pixel)));
return mp_obj_new_tuple(3, pixel_tuple);
} else {
return mp_obj_new_int(IMAGE_GET_RGB565_PIXEL(arg_img, arg_x, arg_y));
}
}
case IMAGE_BPP_BAYER:
if (arg_rgbtuple) {
int pixel = IMAGE_GET_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y); // Correct!
mp_obj_t pixel_tuple[3];
pixel_tuple[0] = mp_obj_new_int(COLOR_RGB565_TO_R8(COLOR_GRAYSCALE_TO_RGB565(pixel)));
pixel_tuple[1] = mp_obj_new_int(COLOR_RGB565_TO_G8(COLOR_GRAYSCALE_TO_RGB565(pixel)));
pixel_tuple[2] = mp_obj_new_int(COLOR_RGB565_TO_B8(COLOR_GRAYSCALE_TO_RGB565(pixel)));
return mp_obj_new_tuple(3, pixel_tuple);
} else {
return mp_obj_new_int(IMAGE_GET_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y)); // Correct!
}
default: return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_get_pixel_obj, 2, py_image_get_pixel);
STATIC mp_obj_t py_image_set_pixel(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]);
const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 1, 2, &arg_vec);
int arg_x = mp_obj_get_int(arg_vec[0]);
int arg_y = mp_obj_get_int(arg_vec[1]);
int arg_c =
py_helper_keyword_color(arg_img, n_args, args, offset, kw_args, -1); // White.
if ((!IM_X_INSIDE(arg_img, arg_x)) || (!IM_Y_INSIDE(arg_img, arg_y))) {
return args[0];
}
switch (arg_img->bpp) {
case IMAGE_BPP_BINARY: {
IMAGE_PUT_BINARY_PIXEL(arg_img, arg_x, arg_y, arg_c);
return args[0];
}
case IMAGE_BPP_GRAYSCALE: {
IMAGE_PUT_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y, arg_c);
return args[0];
}
case IMAGE_BPP_RGB565: {
IMAGE_PUT_RGB565_PIXEL(arg_img, arg_x, arg_y, arg_c);
return args[0];
}
case IMAGE_BPP_BAYER: {
IMAGE_PUT_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y, arg_c); // Correct!
return args[0];
}
default: return args[0];
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_set_pixel_obj, 2, py_image_set_pixel);
#ifdef IMLIB_ENABLE_MEAN_POOLING
static mp_obj_t py_image_mean_pool(mp_obj_t img_obj, mp_obj_t x_div_obj, mp_obj_t y_div_obj)
{
image_t *arg_img = py_helper_arg_to_image_mutable(img_obj);
int arg_x_div = mp_obj_get_int(x_div_obj);
PY_ASSERT_TRUE_MSG(arg_x_div >= 1, "Width divisor must be greater than >= 1");
PY_ASSERT_TRUE_MSG(arg_x_div <= arg_img->w, "Width divisor must be less than <= img width");
int arg_y_div = mp_obj_get_int(y_div_obj);
PY_ASSERT_TRUE_MSG(arg_y_div >= 1, "Height divisor must be greater than >= 1");
PY_ASSERT_TRUE_MSG(arg_y_div <= arg_img->h, "Height divisor must be less than <= img height");
image_t out_img;
out_img.w = arg_img->w / arg_x_div;
out_img.h = arg_img->h / arg_y_div;
out_img.bpp = arg_img->bpp;
out_img.pixels = arg_img->pixels;
PY_ASSERT_TRUE_MSG(image_size(&out_img) <= image_size(arg_img), "Can't pool in place!");
imlib_mean_pool(arg_img, &out_img, arg_x_div, arg_y_div);
arg_img->w = out_img.w;
arg_img->h = out_img.h;
if (MAIN_FB()->pixels == arg_img->data) {
MAIN_FB()->w = out_img.w;
MAIN_FB()->h = out_img.h;
}
return img_obj;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_mean_pool_obj, py_image_mean_pool);
static mp_obj_t py_image_mean_pooled(mp_obj_t img_obj, mp_obj_t x_div_obj, mp_obj_t y_div_obj)
{
image_t *arg_img = py_helper_arg_to_image_mutable(img_obj);
int arg_x_div = mp_obj_get_int(x_div_obj);
PY_ASSERT_TRUE_MSG(arg_x_div >= 1, "Width divisor must be greater than >= 1");
PY_ASSERT_TRUE_MSG(arg_x_div <= arg_img->w, "Width divisor must be less than <= img width");
int arg_y_div = mp_obj_get_int(y_div_obj);
PY_ASSERT_TRUE_MSG(arg_y_div >= 1, "Height divisor must be greater than >= 1");
PY_ASSERT_TRUE_MSG(arg_y_div <= arg_img->h, "Height divisor must be less than <= img height");
image_t out_img;
out_img.w = arg_img->w / arg_x_div;
out_img.h = arg_img->h / arg_y_div;
out_img.bpp = arg_img->bpp;
out_img.pixels = xalloc(image_size(&out_img));
imlib_mean_pool(arg_img, &out_img, arg_x_div, arg_y_div);
return py_image_from_struct(&out_img);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_mean_pooled_obj, py_image_mean_pooled);
#endif // IMLIB_ENABLE_MEAN_POOLING
#ifdef IMLIB_ENABLE_MIDPOINT_POOLING
static mp_obj_t py_image_midpoint_pool(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_x_div = mp_obj_get_int(args[1]);
PY_ASSERT_TRUE_MSG(arg_x_div >= 1, "Width divisor must be greater than >= 1");
PY_ASSERT_TRUE_MSG(arg_x_div <= arg_img->w, "Width divisor must be less than <= img width");
int arg_y_div = mp_obj_get_int(args[2]);
PY_ASSERT_TRUE_MSG(arg_y_div >= 1, "Height divisor must be greater than >= 1");
PY_ASSERT_TRUE_MSG(arg_y_div <= arg_img->h, "Height divisor must be less than <= img height");
int arg_bias = py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bias), 0.5) * 256;
PY_ASSERT_TRUE_MSG((0 <= arg_bias) && (arg_bias <= 256), "Error: 0 <= bias <= 1!");
image_t out_img;
out_img.w = arg_img->w / arg_x_div;
out_img.h = arg_img->h / arg_y_div;
out_img.bpp = arg_img->bpp;
out_img.pixels = arg_img->pixels;
PY_ASSERT_TRUE_MSG(image_size(&out_img) <= image_size(arg_img), "Can't pool in place!");
imlib_midpoint_pool(arg_img, &out_img, arg_x_div, arg_y_div, arg_bias);
arg_img->w = out_img.w;
arg_img->h = out_img.h;
if (MAIN_FB()->pixels == arg_img->data) {
MAIN_FB()->w = out_img.w;
MAIN_FB()->h = out_img.h;
}
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_pool_obj, 3, py_image_midpoint_pool);
static mp_obj_t py_image_midpoint_pooled(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_x_div = mp_obj_get_int(args[1]);
PY_ASSERT_TRUE_MSG(arg_x_div >= 1, "Width divisor must be greater than >= 1");
PY_ASSERT_TRUE_MSG(arg_x_div <= arg_img->w, "Width divisor must be less than <= img width");
int arg_y_div = mp_obj_get_int(args[2]);
PY_ASSERT_TRUE_MSG(arg_y_div >= 1, "Height divisor must be greater than >= 1");
PY_ASSERT_TRUE_MSG(arg_y_div <= arg_img->h, "Height divisor must be less than <= img height");
int arg_bias = py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bias), 0.5) * 256;
PY_ASSERT_TRUE_MSG((0 <= arg_bias) && (arg_bias <= 256), "Error: 0 <= bias <= 1!");
image_t out_img;
out_img.w = arg_img->w / arg_x_div;
out_img.h = arg_img->h / arg_y_div;
out_img.bpp = arg_img->bpp;
out_img.pixels = xalloc(image_size(&out_img));
imlib_midpoint_pool(arg_img, &out_img, arg_x_div, arg_y_div, arg_bias);
return py_image_from_struct(&out_img);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_pooled_obj, 3, py_image_midpoint_pooled);
#endif // IMLIB_ENABLE_MIDPOINT_POOLING
static mp_obj_t py_image_to_bitmap(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]);
bool copy = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy), false);
int channel = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgb_channel), -1);
image_t out;
out.w = arg_img->w;
out.h = arg_img->h;
out.bpp = IMAGE_BPP_BINARY;
out.data = copy ? xalloc(image_size(&out)) : arg_img->data;
switch(arg_img->bpp) {
case IMAGE_BPP_BINARY: {
if (copy) memcpy(out.data, arg_img->data, image_size(&out));
break;
}
case IMAGE_BPP_GRAYSCALE: {
PY_ASSERT_TRUE_MSG((out.w >= (sizeof(uint32_t)/sizeof(uint8_t))) || copy,
"Can't convert to bitmap in place!");
fb_alloc_mark();
uint32_t *out_row_ptr = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(&out));
for (int y = 0, yy = out.h; y < yy; y++) {
uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(arg_img, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_BINARY_PIXEL_FAST(out_row_ptr, x,
COLOR_GRAYSCALE_TO_BINARY(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)));
}
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&out, y),
out_row_ptr, IMAGE_BINARY_LINE_LEN_BYTES(&out));
}
fb_alloc_free_till_mark();
break;
}
case IMAGE_BPP_RGB565: {
PY_ASSERT_TRUE_MSG((out.w >= (sizeof(uint32_t)/sizeof(uint16_t))) || copy,
"Can't convert to bitmap in place!");
fb_alloc_mark();
uint32_t *out_row_ptr = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(&out));
for (int y = 0, yy = out.h; y < yy; y++) {
uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(arg_img, y);
for (int x = 0, xx = out.w; x < xx; x++) {
int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x);
switch (channel) {
case 0: {
pixel = COLOR_RGB565_TO_R5(pixel) > (((COLOR_R5_MAX - COLOR_R5_MIN) / 2) + COLOR_R5_MIN);
break;
}
case 1: {
pixel = COLOR_RGB565_TO_G6(pixel) > (((COLOR_G6_MAX - COLOR_G6_MIN) / 2) + COLOR_G6_MIN);
break;
}
case 2: {
pixel = COLOR_RGB565_TO_B5(pixel) > (((COLOR_B5_MAX - COLOR_B5_MIN) / 2) + COLOR_B5_MIN);
break;
}
default: {
pixel = COLOR_RGB565_TO_BINARY(pixel);
break;
}
}
IMAGE_PUT_BINARY_PIXEL_FAST(out_row_ptr, x, pixel);
}
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&out, y),
out_row_ptr, IMAGE_BINARY_LINE_LEN_BYTES(&out));
}
fb_alloc_free_till_mark();
break;
}
default: {
break;
}
}
if (!copy) {
arg_img->bpp = IMAGE_BPP_BINARY;
if ((MAIN_FB()->pixels == out.data)) {
MAIN_FB()->bpp = out.bpp;
}
}
return py_image_from_struct(&out);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_to_bitmap_obj, 1, py_image_to_bitmap);
static mp_obj_t py_image_to_grayscale(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]);
bool copy = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy), false);
int channel = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgb_channel), -1);
image_t out;
out.w = arg_img->w;
out.h = arg_img->h;
out.bpp = IMAGE_BPP_GRAYSCALE;
out.data = copy ? xalloc(image_size(&out)) : arg_img->data;
switch(arg_img->bpp) {
case IMAGE_BPP_BINARY: {
if (copy || (MAIN_FB()->pixels != out.data)) {
PY_ASSERT_TRUE_MSG((out.w == 1) || copy,
"Can't convert to grayscale in place!");
for (int y = 0, yy = out.h; y < yy; y++) {
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(arg_img, y);
uint8_t *out_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(out_row_ptr, x,
COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)));
}
}
} else {
image_t temp;
memcpy(&temp, arg_img, sizeof(image_t));
fb_alloc_mark();
temp.data = fb_alloc(image_size(&temp));
memcpy(temp.data, arg_img->data, image_size(&temp));
MAIN_FB()->w = 0;
MAIN_FB()->h = 0;
MAIN_FB()->bpp = 0;
PY_ASSERT_TRUE_MSG((image_size(&out) <= fb_avail()), "Can't convert to grayscale in place!");
MAIN_FB()->w = out.w;
MAIN_FB()->h = out.h;
MAIN_FB()->bpp = out.bpp;
for (int y = 0, yy = out.h; y < yy; y++) {
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&temp, y);
uint8_t *out_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(out_row_ptr, x,
COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)));
}
}
fb_alloc_free_till_mark();
}
break;
}
case IMAGE_BPP_GRAYSCALE: {
if (copy) memcpy(out.data, arg_img->data, image_size(&out));
break;
}
case IMAGE_BPP_RGB565: {
for (int y = 0, yy = out.h; y < yy; y++) {
uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(arg_img, y);
uint8_t *out_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x);
switch (channel) {
case 0: {
pixel = COLOR_RGB565_TO_R8(pixel);
break;
}
case 1: {
pixel = COLOR_RGB565_TO_G8(pixel);
break;
}
case 2: {
pixel = COLOR_RGB565_TO_B8(pixel);
break;
}
default: {
pixel = COLOR_RGB565_TO_GRAYSCALE(pixel);
break;
}
}
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(out_row_ptr, x, pixel);
}
}
break;
}
default: {
break;
}
}
if (!copy) {
arg_img->bpp = IMAGE_BPP_GRAYSCALE;
if ((MAIN_FB()->pixels == out.data)) {
MAIN_FB()->bpp = out.bpp;
}
}
return py_image_from_struct(&out);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_to_grayscale_obj, 1, py_image_to_grayscale);
static mp_obj_t py_image_to_rgb565(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]);
bool copy = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy), false);
int channel = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgb_channel), -1);
image_t out;
out.w = arg_img->w;
out.h = arg_img->h;
out.bpp = IMAGE_BPP_RGB565;
out.data = copy ? xalloc(image_size(&out)) : arg_img->data;
switch(arg_img->bpp) {
case IMAGE_BPP_BINARY: {
if (copy || (MAIN_FB()->pixels != out.data)) {
PY_ASSERT_TRUE_MSG((out.w == 1) || copy,
"Can't convert to grayscale in place!");
for (int y = 0, yy = out.h; y < yy; y++) {
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(arg_img, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x,
imlib_yuv_to_rgb(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x) * COLOR_GRAYSCALE_MAX, 0, 0));
}
}
} else {
image_t temp;
memcpy(&temp, arg_img, sizeof(image_t));
fb_alloc_mark();
temp.data = fb_alloc(image_size(&temp));
memcpy(temp.data, arg_img->data, image_size(&temp));
MAIN_FB()->w = 0;
MAIN_FB()->h = 0;
MAIN_FB()->bpp = 0;
PY_ASSERT_TRUE_MSG((image_size(&out) <= fb_avail()), "Can't convert to grayscale in place!");
MAIN_FB()->w = out.w;
MAIN_FB()->h = out.h;
MAIN_FB()->bpp = out.bpp;
for (int y = 0, yy = out.h; y < yy; y++) {
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&temp, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x,
imlib_yuv_to_rgb(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x) * COLOR_GRAYSCALE_MAX, 0, 0));
}
}
fb_alloc_free_till_mark();
}
break;
}
case IMAGE_BPP_GRAYSCALE: {
if (copy || (MAIN_FB()->pixels != out.data)) {
PY_ASSERT_TRUE_MSG(copy,
"Can't convert to rgb565 in place!");
for (int y = 0, yy = out.h; y < yy; y++) {
uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(arg_img, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x,
imlib_yuv_to_rgb(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x), 0, 0));
}
}
} else {
image_t temp;
memcpy(&temp, arg_img, sizeof(image_t));
fb_alloc_mark();
temp.data = fb_alloc(image_size(&temp));
memcpy(temp.data, arg_img->data, image_size(&temp));
MAIN_FB()->w = 0;
MAIN_FB()->h = 0;
MAIN_FB()->bpp = 0;
PY_ASSERT_TRUE_MSG((image_size(&out) <= fb_avail()), "Can't convert to grayscale in place!");
MAIN_FB()->w = out.w;
MAIN_FB()->h = out.h;
MAIN_FB()->bpp = out.bpp;
for (int y = 0, yy = out.h; y < yy; y++) {
uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&temp, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x,
imlib_yuv_to_rgb(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x), 0, 0));
}
}
fb_alloc_free_till_mark();
}
break;
}
case IMAGE_BPP_RGB565: {
for (int y = 0, yy = out.h; y < yy; y++) {
uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(arg_img, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x);
switch (channel) {
case 0: {
pixel = COLOR_R5_G6_B5_TO_RGB565(COLOR_RGB565_TO_R5(pixel), 0, 0);
break;
}
case 1: {
pixel = COLOR_R5_G6_B5_TO_RGB565(0, COLOR_RGB565_TO_G6(pixel), 0);
break;
}
case 2: {
pixel = COLOR_R5_G6_B5_TO_RGB565(0, 0, COLOR_RGB565_TO_B5(pixel));
break;
}
default: {
break;
}
}
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x, pixel);
}
}
break;
}
default: {
break;
}
}
if (!copy) {
arg_img->bpp = IMAGE_BPP_RGB565;
if ((MAIN_FB()->pixels == out.data)) {
MAIN_FB()->bpp = out.bpp;
}
}
return py_image_from_struct(&out);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_to_rgb565_obj, 1, py_image_to_rgb565);
static mp_obj_t py_image_to_rainbow(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]);
bool copy = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy), false);
int channel = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgb_channel), -1);
int palette = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color_palette), COLOR_PALETTE_RAINBOW);
const uint16_t *color_palette = NULL;
if (palette == COLOR_PALETTE_RAINBOW) {
color_palette = rainbow_table;
} else if (palette == COLOR_PALETTE_IRONBOW) {
color_palette = ironbow_table;
} else {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid color palette!"));
}
image_t out;
out.w = arg_img->w;
out.h = arg_img->h;
out.bpp = IMAGE_BPP_RGB565;
out.data = copy ? xalloc(image_size(&out)) : arg_img->data;
switch(arg_img->bpp) {
case IMAGE_BPP_BINARY: {
if (copy || (MAIN_FB()->pixels != out.data)) {
PY_ASSERT_TRUE_MSG((out.w == 1) || copy,
"Can't convert to rainbow in place!");
for (int y = 0, yy = out.h; y < yy; y++) {
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(arg_img, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x,
color_palette[IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x) * COLOR_GRAYSCALE_MAX]);
}
}
} else {
image_t temp;
memcpy(&temp, arg_img, sizeof(image_t));
fb_alloc_mark();
temp.data = fb_alloc(image_size(&temp));
memcpy(temp.data, arg_img->data, image_size(&temp));
MAIN_FB()->w = 0;
MAIN_FB()->h = 0;
MAIN_FB()->bpp = 0;
PY_ASSERT_TRUE_MSG((image_size(&out) <= fb_avail()), "Can't convert to rainbow in place!");
MAIN_FB()->w = out.w;
MAIN_FB()->h = out.h;
MAIN_FB()->bpp = out.bpp;
for (int y = 0, yy = out.h; y < yy; y++) {
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&temp, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x,
color_palette[IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x) * COLOR_GRAYSCALE_MAX]);
}
}
fb_alloc_free_till_mark();
}
break;
}
case IMAGE_BPP_GRAYSCALE: {
if (copy || (MAIN_FB()->pixels != out.data)) {
PY_ASSERT_TRUE_MSG(copy,
"Can't convert to rainbow in place!");
for (int y = 0, yy = out.h; y < yy; y++) {
uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(arg_img, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x,
color_palette[IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)]);
}
}
} else {
image_t temp;
memcpy(&temp, arg_img, sizeof(image_t));
fb_alloc_mark();
temp.data = fb_alloc(image_size(&temp));
memcpy(temp.data, arg_img->data, image_size(&temp));
MAIN_FB()->w = 0;
MAIN_FB()->h = 0;
MAIN_FB()->bpp = 0;
PY_ASSERT_TRUE_MSG((image_size(&out) <= fb_avail()), "Can't convert to rainbow in place!");
MAIN_FB()->w = out.w;
MAIN_FB()->h = out.h;
MAIN_FB()->bpp = out.bpp;
for (int y = 0, yy = out.h; y < yy; y++) {
uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&temp, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x,
color_palette[IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)]);
}
}
fb_alloc_free_till_mark();
}
break;
}
case IMAGE_BPP_RGB565: {
for (int y = 0, yy = out.h; y < yy; y++) {
uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(arg_img, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x);
switch (channel) {
case 0: {
pixel = color_palette[COLOR_RGB565_TO_R8(pixel)];
break;
}
case 1: {
pixel = color_palette[COLOR_RGB565_TO_G8(pixel)];
break;
}
case 2: {
pixel = color_palette[COLOR_RGB565_TO_B8(pixel)];
break;
}
default: {
pixel = color_palette[COLOR_RGB565_TO_GRAYSCALE(pixel)];
break;
}
}
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x, pixel);
}
}
break;
}
default: {
break;
}
}
if (!copy) {
arg_img->bpp = IMAGE_BPP_RGB565;
if (MAIN_FB()->pixels == out.data) {
MAIN_FB()->bpp = out.bpp;
}
}
return py_image_from_struct(&out);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_to_rainbow_obj, 1, py_image_to_rainbow);
static mp_obj_t py_image_compress(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]);
int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50);
PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!");
uint32_t size;
fb_alloc_mark();
uint8_t *buffer = fb_alloc_all(&size);
image_t out = { .w=arg_img->w, .h=arg_img->h, .bpp=size, .data=buffer };
PY_ASSERT_FALSE_MSG(jpeg_compress(arg_img, &out, arg_q, false), "Out of Memory!");
PY_ASSERT_TRUE_MSG(out.bpp <= image_size(arg_img), "Can't compress in place!");
memcpy(arg_img->data, out.data, out.bpp);
arg_img->bpp = out.bpp;
fb_alloc_free_till_mark();
if (MAIN_FB()->pixels == arg_img->data) {
MAIN_FB()->bpp = arg_img->bpp;
}
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compress_obj, 1, py_image_compress);
static mp_obj_t py_image_compress_for_ide(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]);
int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50);
PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!");
uint32_t size;
fb_alloc_mark();
uint8_t *buffer = fb_alloc_all(&size);
image_t out = { .w=arg_img->w, .h=arg_img->h, .bpp=size, .data=buffer };
PY_ASSERT_FALSE_MSG(jpeg_compress(arg_img, &out, arg_q, false), "Out of Memory!");
PY_ASSERT_TRUE_MSG(((((out.bpp * 8) + 5) / 6) + 2) <= image_size(arg_img), "Can't compress in place!");
uint8_t *ptr = arg_img->data;
*ptr++ = 0xFE;
for(int i = 0, j = (out.bpp / 3) * 3; i < j; i += 3) {
int x = 0;
x |= out.data[i + 0] << 0;
x |= out.data[i + 1] << 8;
x |= out.data[i + 2] << 16;
*ptr++ = 0x80 | ((x >> 0) & 0x3F);
*ptr++ = 0x80 | ((x >> 6) & 0x3F);
*ptr++ = 0x80 | ((x >> 12) & 0x3F);
*ptr++ = 0x80 | ((x >> 18) & 0x3F);
}
if((out.bpp % 3) == 2) { // 2 bytes -> 16-bits -> 24-bits sent
int x = 0;
x |= out.data[out.bpp - 2] << 0;
x |= out.data[out.bpp - 1] << 8;
*ptr++ = 0x80 | ((x >> 0) & 0x3F);
*ptr++ = 0x80 | ((x >> 6) & 0x3F);
*ptr++ = 0x80 | ((x >> 12) & 0x3F);
}
if((out.bpp % 3) == 1) { // 1 byte -> 8-bits -> 16-bits sent
int x = 0;
x |= out.data[out.bpp - 1] << 0;
*ptr++ = 0x80 | ((x >> 0) & 0x3F);
*ptr++ = 0x80 | ((x >> 6) & 0x3F);
}
*ptr++ = 0xFE;
out.bpp = (((out.bpp * 8) + 5) / 6) + 2;
arg_img->bpp = out.bpp;
fb_alloc_free_till_mark();
if (MAIN_FB()->pixels == arg_img->data) {
MAIN_FB()->bpp = arg_img->bpp;
}
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compress_for_ide_obj, 1, py_image_compress_for_ide);
static mp_obj_t py_image_compressed(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]);
int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50);
PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!");
uint32_t size;
fb_alloc_mark();
uint8_t *buffer = fb_alloc_all(&size);
image_t out = { .w=arg_img->w, .h=arg_img->h, .bpp=size, .data=buffer };
PY_ASSERT_FALSE_MSG(jpeg_compress(arg_img, &out, arg_q, false), "Out of Memory!");
uint8_t *temp = xalloc(out.bpp);
memcpy(temp, out.data, out.bpp);
out.data = temp;
fb_alloc_free_till_mark();
return py_image_from_struct(&out);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compressed_obj, 1, py_image_compressed);
static mp_obj_t py_image_compressed_for_ide(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]);
int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50);
PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!");
uint32_t size;
fb_alloc_mark();
uint8_t *buffer = fb_alloc_all(&size);
image_t out = { .w=arg_img->w, .h=arg_img->h, .bpp=size, .data=buffer };
PY_ASSERT_FALSE_MSG(jpeg_compress(arg_img, &out, arg_q, false), "Out of Memory!");
uint8_t *temp = xalloc((((out.bpp * 8) + 5) / 6) + 2);
uint8_t *ptr = temp;
*ptr++ = 0xFE;
for(int i = 0, j = (out.bpp / 3) * 3; i < j; i += 3) {
int x = 0;
x |= out.data[i + 0] << 0;
x |= out.data[i + 1] << 8;
x |= out.data[i + 2] << 16;
*ptr++ = 0x80 | ((x >> 0) & 0x3F);
*ptr++ = 0x80 | ((x >> 6) & 0x3F);
*ptr++ = 0x80 | ((x >> 12) & 0x3F);
*ptr++ = 0x80 | ((x >> 18) & 0x3F);
}
if((out.bpp % 3) == 2) { // 2 bytes -> 16-bits -> 24-bits sent
int x = 0;
x |= out.data[out.bpp - 2] << 0;
x |= out.data[out.bpp - 1] << 8;
*ptr++ = 0x80 | ((x >> 0) & 0x3F);
*ptr++ = 0x80 | ((x >> 6) & 0x3F);
*ptr++ = 0x80 | ((x >> 12) & 0x0F);
}
if((out.bpp % 3) == 1) { // 1 byte -> 8-bits -> 16-bits sent
int x = 0;
x |= out.data[out.bpp - 1] << 0;
*ptr++ = 0x80 | ((x >> 0) & 0x3F);
*ptr++ = 0x80 | ((x >> 6) & 0x03);
}
*ptr++ = 0xFE;
out.bpp = (((out.bpp * 8) + 5) / 6) + 2;
out.data = temp;
fb_alloc_free_till_mark();
return py_image_from_struct(&out);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compressed_for_ide_obj, 1, py_image_compressed_for_ide);
static mp_obj_t py_image_copy_int(uint n_args, const mp_obj_t *args, mp_map_t *kw_args, bool mode)
{
// mode == false -> copy behavior
// mode == true -> crop/scale behavior
image_t *arg_img = py_helper_arg_to_image_mutable(args[0]);
rectangle_t roi;
py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi);
float arg_x_scale =
py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_scale), 1.0f);
PY_ASSERT_TRUE_MSG((0.0f <= arg_x_scale), "Error: 0.0 <= x_scale!");
float arg_y_scale =
py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_scale), 1.0f);
PY_ASSERT_TRUE_MSG((0.0f <= arg_y_scale), "Error: 0.0 <= y_scale!");
mp_obj_t copy_to_fb_obj = py_helper_keyword_object(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(mode ? MP_QSTR_copy : MP_QSTR_copy_to_fb));
bool copy_to_fb = false;
image_t *arg_other = mode ? arg_img : NULL;
if (copy_to_fb_obj) {
if (mp_obj_is_integer(copy_to_fb_obj)) {
if (!mode) {
copy_to_fb = mp_obj_get_int(copy_to_fb_obj);
} else if (mp_obj_get_int(copy_to_fb_obj)) {
arg_other = NULL;
}
} else {
arg_other = py_helper_arg_to_image_mutable(copy_to_fb_obj);
}
}
if (copy_to_fb) {
fb_update_jpeg_buffer();
}
image_t image;
image.w = fast_floorf(roi.w * arg_x_scale);
PY_ASSERT_TRUE_MSG(image.w >= 1, "Output image width is 0!");
image.h = fast_floorf(roi.h * arg_y_scale);
PY_ASSERT_TRUE_MSG(image.h >= 1, "Output image height is 0!");
image.bpp = arg_img->bpp;
image.data = NULL;
if (copy_to_fb) {
MAIN_FB()->w = 0;
MAIN_FB()->h = 0;
MAIN_FB()->bpp = 0;
PY_ASSERT_TRUE_MSG((image_size(&image) <= fb_avail()), "The new image won't fit in the main frame buffer!");
MAIN_FB()->w = image.w;
MAIN_FB()->h = image.h;
MAIN_FB()->bpp = image.bpp;
image.data = MAIN_FB()->pixels;
} else if (arg_other) {
PY_ASSERT_TRUE_MSG((image_size(&image) <= image_size(arg_other)), "The new image won't fit in the target frame buffer!");
image.data = arg_other->data;
} else {
image.data = xalloc(image_size(&image));
}
bool in_place = arg_img->data == image.data;
image_t temp;
if (in_place) {
memcpy(&temp, arg_img, sizeof(image_t));
fb_alloc_mark();
temp.data = fb_alloc(image_size(&temp));
memcpy(temp.data, arg_img->data, image_size(&temp));
arg_img = &temp;
if (copy_to_fb) {
MAIN_FB()->w = 0;
MAIN_FB()->h = 0;
MAIN_FB()->bpp = 0;
PY_ASSERT_TRUE_MSG((image_size(&image) <= fb_avail()), "The new image won't fit in the main frame buffer!");
MAIN_FB()->w = image.w;
MAIN_FB()->h = image.h;
MAIN_FB()->bpp = image.bpp;
}
}
float over_xscale = IM_DIV(1.0, arg_x_scale), over_yscale = IM_DIV(1.0f, arg_y_scale);
switch(arg_img->bpp) {
case IMAGE_BPP_BINARY: {
for (int y = 0, yy = image.h; y < yy; y++) {
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(arg_img, fast_floorf(y * over_yscale) + roi.y);
uint32_t *row_ptr_2 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&image, y);
for (int x = 0, xx = image.w; x < xx; x++) {
IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr_2, x,
IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, fast_floorf(x * over_xscale) + roi.x));
}
}
break;
}
case IMAGE_BPP_GRAYSCALE: {
for (int y = 0, yy = image.h; y < yy; y++) {
uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(arg_img, fast_floorf(y * over_yscale) + roi.y);
uint8_t *row_ptr_2 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&image, y);
for (int x = 0, xx = image.w; x < xx; x++) {
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr_2, x,
IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, fast_floorf(x * over_xscale) + roi.x));
}
}
break;
}
case IMAGE_BPP_RGB565: {
for (int y = 0, yy = image.h; y < yy; y++) {
uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(arg_img, fast_floorf(y * over_yscale) + roi.y);
uint16_t *row_ptr_2 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&image, y);
for (int x = 0, xx = image.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr_2, x,
IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, fast_floorf(x * over_xscale) + roi.x));
}
}
break;
}
default: {
break;
}
}
if (in_place) {
fb_alloc_free_till_mark();
}
if (MAIN_FB()->pixels == image.data) {
MAIN_FB()->w = image.w;
MAIN_FB()->h = image.h;
MAIN_FB()->bpp = image.bpp;
}
if (copy_to_fb) {
image_t *arg_img = py_helper_arg_to_image_mutable(args[0]);
if (MAIN_FB()->pixels == arg_img->data) {
arg_img->w = image.w;
arg_img->h = image.h;
arg_img->bpp = image.bpp;
}
} else {
if (arg_other) {
arg_other->w = image.w;
arg_other->h = image.h;
arg_other->bpp = image.bpp;
}
}
return py_image_from_struct(&image);
}
static mp_obj_t py_image_copy(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
return py_image_copy_int(n_args, args, kw_args, false);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_copy_obj, 1, py_image_copy);
static mp_obj_t py_image_crop(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
return py_image_copy_int(n_args, args, kw_args, true);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_crop_obj, 1, py_image_crop);
static mp_obj_t py_image_save(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_image_cobj(args[0]);
const char *path = mp_obj_str_get_str(args[1]);
rectangle_t roi;
py_helper_keyword_rectangle_roi(arg_img, n_args, args, 2, kw_args, &roi);
int arg_q = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50);
PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!");
fb_alloc_mark();
imlib_save_image(arg_img, path, &roi, arg_q);
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_save_obj, 2, py_image_save);
//////////////////
// Drawing Methods
//////////////////
STATIC mp_obj_t py_image_clear(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 1, kw_args);
if (!arg_msk) {
memset(arg_img->data, 0, image_size(arg_img));
} else {
imlib_zero(arg_img, arg_msk, false);
}
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_clear_obj, 1, py_image_clear);
STATIC mp_obj_t py_image_draw_line(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]);
const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 1, 4, &arg_vec);
int arg_x0 = mp_obj_get_int(arg_vec[0]);
int arg_y0 = mp_obj_get_int(arg_vec[1]);
int arg_x1 = mp_obj_get_int(arg_vec[2]);
int arg_y1 = mp_obj_get_int(arg_vec[3]);
int arg_c =
py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White.
int arg_thickness =
py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1);
imlib_draw_line(arg_img, arg_x0, arg_y0, arg_x1, arg_y1, arg_c, arg_thickness);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_line_obj, 2, py_image_draw_line);
STATIC mp_obj_t py_image_draw_rectangle(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]);
const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 1, 4, &arg_vec);
int arg_rx = mp_obj_get_int(arg_vec[0]);
int arg_ry = mp_obj_get_int(arg_vec[1]);
int arg_rw = mp_obj_get_int(arg_vec[2]);
int arg_rh = mp_obj_get_int(arg_vec[3]);
int arg_c =
py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White.
int arg_thickness =
py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1);
bool arg_fill =
py_helper_keyword_int(n_args, args, offset + 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fill), false);
imlib_draw_rectangle(arg_img, arg_rx, arg_ry, arg_rw, arg_rh, arg_c, arg_thickness, arg_fill);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_rectangle_obj, 2, py_image_draw_rectangle);
STATIC mp_obj_t py_image_draw_circle(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]);
const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 1, 3, &arg_vec);
int arg_cx = mp_obj_get_int(arg_vec[0]);
int arg_cy = mp_obj_get_int(arg_vec[1]);
int arg_cr = mp_obj_get_int(arg_vec[2]);
int arg_c =
py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White.
int arg_thickness =
py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1);
bool arg_fill =
py_helper_keyword_int(n_args, args, offset + 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fill), false);
imlib_draw_circle(arg_img, arg_cx, arg_cy, arg_cr, arg_c, arg_thickness, arg_fill);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_circle_obj, 2, py_image_draw_circle);
STATIC mp_obj_t py_image_draw_ellipse(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]);
const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 1, 5, &arg_vec);
int arg_cx = mp_obj_get_int(arg_vec[0]);
int arg_cy = mp_obj_get_int(arg_vec[1]);
int arg_rx = mp_obj_get_int(arg_vec[2]);
int arg_ry = mp_obj_get_int(arg_vec[3]);
int arg_r = mp_obj_get_int(arg_vec[4]);
int arg_c =
py_helper_keyword_color(arg_img, n_args, args, offset + 1, kw_args, -1); // White.
int arg_thickness =
py_helper_keyword_int(n_args, args, offset + 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1);
bool arg_fill =
py_helper_keyword_int(n_args, args, offset + 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fill), false);
imlib_draw_ellipse(arg_img, arg_cx, arg_cy, arg_rx, arg_ry, arg_r, arg_c, arg_thickness, arg_fill);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_ellipse_obj, 2, py_image_draw_ellipse);
STATIC mp_obj_t py_image_draw_string(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]);
const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 1, 3, &arg_vec);
int arg_x_off = mp_obj_get_int(arg_vec[0]);
int arg_y_off = mp_obj_get_int(arg_vec[1]);
const char *arg_str = mp_obj_str_get_str(arg_vec[2]);
int arg_c =
py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White.
float arg_scale =
py_helper_keyword_float(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_scale), 1.0);
PY_ASSERT_TRUE_MSG(0 < arg_scale, "Error: 0 < scale!");
int arg_x_spacing =
py_helper_keyword_int(n_args, args, offset + 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_spacing), 0);
int arg_y_spacing =
py_helper_keyword_int(n_args, args, offset + 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_spacing), 0);
bool arg_mono_space =
py_helper_keyword_int(n_args, args, offset + 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mono_space), true);
int arg_char_rotation =
py_helper_keyword_int(n_args, args, offset + 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_char_rotation), 0);
int arg_char_hmirror =
py_helper_keyword_int(n_args, args, offset + 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_char_hmirror), false);
int arg_char_vflip =
py_helper_keyword_int(n_args, args, offset + 7, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_char_vflip), false);
int arg_string_rotation =
py_helper_keyword_int(n_args, args, offset + 8, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_string_rotation), 0);
int arg_string_hmirror =
py_helper_keyword_int(n_args, args, offset + 9, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_string_hmirror), false);
int arg_string_vflip =
py_helper_keyword_int(n_args, args, offset + 10, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_string_vflip), false);
imlib_draw_string(arg_img, arg_x_off, arg_y_off, arg_str,
arg_c, arg_scale, arg_x_spacing, arg_y_spacing, arg_mono_space,
arg_char_rotation, arg_char_hmirror, arg_char_vflip,
arg_string_rotation, arg_string_hmirror, arg_string_vflip);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_string_obj, 2, py_image_draw_string);
STATIC mp_obj_t py_image_draw_cross(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]);
const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 1, 2, &arg_vec);
int arg_x = mp_obj_get_int(arg_vec[0]);
int arg_y = mp_obj_get_int(arg_vec[1]);
int arg_c =
py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White.
int arg_s =
py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 5);
int arg_thickness =
py_helper_keyword_int(n_args, args, offset + 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1);
imlib_draw_line(arg_img, arg_x - arg_s, arg_y , arg_x + arg_s, arg_y , arg_c, arg_thickness);
imlib_draw_line(arg_img, arg_x , arg_y - arg_s, arg_x , arg_y + arg_s, arg_c, arg_thickness);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_cross_obj, 2, py_image_draw_cross);
STATIC mp_obj_t py_image_draw_arrow(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]);
const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 1, 4, &arg_vec);
int arg_x0 = mp_obj_get_int(arg_vec[0]);
int arg_y0 = mp_obj_get_int(arg_vec[1]);
int arg_x1 = mp_obj_get_int(arg_vec[2]);
int arg_y1 = mp_obj_get_int(arg_vec[3]);
int arg_c =
py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White.
int arg_s =
py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 10);
int arg_thickness =
py_helper_keyword_int(n_args, args, offset + 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1);
int dx = (arg_x1 - arg_x0);
int dy = (arg_y1 - arg_y0);
float length = fast_sqrtf((dx * dx) + (dy * dy));
float ux = IM_DIV(dx, length);
float uy = IM_DIV(dy, length);
float vx = -uy;
float vy = ux;
int a0x = fast_roundf(arg_x1 - (arg_s * ux) + (arg_s * vx * 0.5));
int a0y = fast_roundf(arg_y1 - (arg_s * uy) + (arg_s * vy * 0.5));
int a1x = fast_roundf(arg_x1 - (arg_s * ux) - (arg_s * vx * 0.5));
int a1y = fast_roundf(arg_y1 - (arg_s * uy) - (arg_s * vy * 0.5));
imlib_draw_line(arg_img, arg_x0, arg_y0, arg_x1, arg_y1, arg_c, arg_thickness);
imlib_draw_line(arg_img, arg_x1, arg_y1, a0x, a0y, arg_c, arg_thickness);
imlib_draw_line(arg_img, arg_x1, arg_y1, a1x, a1y, arg_c, arg_thickness);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_arrow_obj, 2, py_image_draw_arrow);
STATIC mp_obj_t py_image_draw_edges(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]);
mp_obj_t *corners, *p0, *p1, *p2, *p3;
mp_obj_get_array_fixed_n(args[1], 4, &corners);
mp_obj_get_array_fixed_n(corners[0], 2, &p0);
mp_obj_get_array_fixed_n(corners[1], 2, &p1);
mp_obj_get_array_fixed_n(corners[2], 2, &p2);
mp_obj_get_array_fixed_n(corners[3], 2, &p3);
int x0, y0, x1, y1, x2, y2, x3, y3;
x0 = mp_obj_get_int(p0[0]);
y0 = mp_obj_get_int(p0[1]);
x1 = mp_obj_get_int(p1[0]);
y1 = mp_obj_get_int(p1[1]);
x2 = mp_obj_get_int(p2[0]);
y2 = mp_obj_get_int(p2[1]);
x3 = mp_obj_get_int(p3[0]);
y3 = mp_obj_get_int(p3[1]);
int arg_c =
py_helper_keyword_color(arg_img, n_args, args, 2, kw_args, -1); // White.
int arg_s =
py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 0);
int arg_thickness =
py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1);
bool arg_fill =
py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fill), false);
imlib_draw_line(arg_img, x0, y0, x1, y1, arg_c, arg_thickness);
imlib_draw_line(arg_img, x1, y1, x2, y2, arg_c, arg_thickness);
imlib_draw_line(arg_img, x2, y2, x3, y3, arg_c, arg_thickness);
imlib_draw_line(arg_img, x3, y3, x0, y0, arg_c, arg_thickness);
if (arg_s >= 1) {
imlib_draw_circle(arg_img, x0, y0, arg_s, arg_c, arg_thickness, arg_fill);
imlib_draw_circle(arg_img, x1, y1, arg_s, arg_c, arg_thickness, arg_fill);
imlib_draw_circle(arg_img, x2, y2, arg_s, arg_c, arg_thickness, arg_fill);
imlib_draw_circle(arg_img, x3, y3, arg_s, arg_c, arg_thickness, arg_fill);
}
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_edges_obj, 2, py_image_draw_edges);
STATIC mp_obj_t py_image_draw_image(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]);
image_t *arg_other =
py_helper_arg_to_image_mutable(args[1]);
const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 2, 2, &arg_vec);
int arg_cx = mp_obj_get_int(arg_vec[0]);
int arg_cy = mp_obj_get_int(arg_vec[1]);
float arg_x_scale =
py_helper_keyword_float(n_args, args, offset + 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_scale), 1.0f);
PY_ASSERT_TRUE_MSG((0.0f <= arg_x_scale), "Error: 0.0 <= x_scale!");
float arg_y_scale =
py_helper_keyword_float(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_scale), 1.0f);
PY_ASSERT_TRUE_MSG((0.0f <= arg_y_scale), "Error: 0.0 <= y_scale!");
float arg_alpha =
py_helper_keyword_int(n_args, args, offset + 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_alpha), 256) / 256.0f;
PY_ASSERT_TRUE_MSG((0 <= arg_alpha) && (arg_alpha <= 1), "Error: 0 <= alpha <= 256!");
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, offset + 3, kw_args);
imlib_draw_image(arg_img, arg_other, arg_cx, arg_cy, arg_x_scale, arg_y_scale, arg_alpha, arg_msk);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_image_obj, 3, py_image_draw_image);
STATIC mp_obj_t py_image_draw_keypoints(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_c =
py_helper_keyword_color(arg_img, n_args, args, 2, kw_args, -1); // White.
int arg_s =
py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 10);
int arg_thickness =
py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1);
bool arg_fill =
py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fill), false);
if (MP_OBJ_IS_TYPE(args[1], &mp_type_tuple) || MP_OBJ_IS_TYPE(args[1], &mp_type_list)) {
size_t len;
mp_obj_t *items;
mp_obj_get_array(args[1], &len, &items);
for (size_t i = 0; i < len; i++) {
mp_obj_t *tuple;
mp_obj_get_array_fixed_n(items[i], 3, &tuple);
int cx = mp_obj_get_int(tuple[0]);
int cy = mp_obj_get_int(tuple[1]);
int angle = mp_obj_get_int(tuple[2]) % 360;
int si = sin_table[angle] * arg_s;
int co = cos_table[angle] * arg_s;
imlib_draw_line(arg_img, cx, cy, cx + co, cy + si, arg_c, arg_thickness);
imlib_draw_circle(arg_img, cx, cy, (arg_s - 2) / 2, arg_c, arg_thickness, arg_fill);
}
} else {
#ifdef IMLIB_ENABLE_FIND_KEYPOINTS
py_kp_obj_t *kpts_obj = py_kpts_obj(args[1]);
for (int i = 0, ii = array_length(kpts_obj->kpts); i < ii; i++) {
kp_t *kp = array_at(kpts_obj->kpts, i);
int cx = kp->x;
int cy = kp->y;
int angle = kp->angle % 360;
int si = sin_table[angle] * arg_s;
int co = cos_table[angle] * arg_s;
imlib_draw_line(arg_img, cx, cy, cx + co, cy + si, arg_c, arg_thickness);
imlib_draw_circle(arg_img, cx, cy, (arg_s - 2) / 2, arg_c, arg_thickness, arg_fill);
}
#else
PY_ASSERT_TRUE_MSG(false, "Expected a list of tuples!");
#endif // IMLIB_ENABLE_FIND_KEYPOINTS
}
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_keypoints_obj, 2, py_image_draw_keypoints);
STATIC mp_obj_t py_image_mask_rectangle(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_rx;
int arg_ry;
int arg_rw;
int arg_rh;
if (n_args > 1) {
const mp_obj_t *arg_vec;
py_helper_consume_array(n_args, args, 1, 4, &arg_vec);
arg_rx = mp_obj_get_int(arg_vec[0]);
arg_ry = mp_obj_get_int(arg_vec[1]);
arg_rw = mp_obj_get_int(arg_vec[2]);
arg_rh = mp_obj_get_int(arg_vec[3]);
} else {
arg_rx = arg_img->w / 4;
arg_ry = arg_img->h / 4;
arg_rw = arg_img->w / 2;
arg_rh = arg_img->h / 2;
}
fb_alloc_mark();
image_t temp;
temp.w = arg_img->w;
temp.h = arg_img->h;
temp.bpp = IMAGE_BPP_BINARY;
temp.data = fb_alloc0(image_size(&temp));
imlib_draw_rectangle(&temp, arg_rx, arg_ry, arg_rw, arg_rh, -1, 0, true);
imlib_zero(arg_img, &temp, true);
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mask_rectangle_obj, 1, py_image_mask_rectangle);
STATIC mp_obj_t py_image_mask_circle(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_cx;
int arg_cy;
int arg_cr;
if (n_args > 1) {
const mp_obj_t *arg_vec;
py_helper_consume_array(n_args, args, 1, 3, &arg_vec);
arg_cx = mp_obj_get_int(arg_vec[0]);
arg_cy = mp_obj_get_int(arg_vec[1]);
arg_cr = mp_obj_get_int(arg_vec[2]);
} else {
arg_cx = arg_img->w / 2;
arg_cy = arg_img->h / 2;
arg_cr = IM_MIN(arg_img->w, arg_img->h) / 2;
}
fb_alloc_mark();
image_t temp;
temp.w = arg_img->w;
temp.h = arg_img->h;
temp.bpp = IMAGE_BPP_BINARY;
temp.data = fb_alloc0(image_size(&temp));
imlib_draw_circle(&temp, arg_cx, arg_cy, arg_cr, -1, 0, true);
imlib_zero(arg_img, &temp, true);
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mask_circle_obj, 1, py_image_mask_circle);
STATIC mp_obj_t py_image_mask_ellipse(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_cx;
int arg_cy;
int arg_rx;
int arg_ry;
int arg_r;
if (n_args > 1) {
const mp_obj_t *arg_vec;
py_helper_consume_array(n_args, args, 1, 5, &arg_vec);
arg_cx = mp_obj_get_int(arg_vec[0]);
arg_cy = mp_obj_get_int(arg_vec[1]);
arg_rx = mp_obj_get_int(arg_vec[2]);
arg_ry = mp_obj_get_int(arg_vec[3]);
arg_r = mp_obj_get_int(arg_vec[4]);
} else {
arg_cx = arg_img->w / 2;
arg_cy = arg_img->h / 2;
arg_rx = arg_img->w / 2;
arg_ry = arg_img->h / 2;
arg_r = 0;
}
fb_alloc_mark();
image_t temp;
temp.w = arg_img->w;
temp.h = arg_img->h;
temp.bpp = IMAGE_BPP_BINARY;
temp.data = fb_alloc0(image_size(&temp));
imlib_draw_ellipse(&temp, arg_cx, arg_cy, arg_rx, arg_ry, arg_r, -1, 0, true);
imlib_zero(arg_img, &temp, true);
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mask_ellipse_obj, 1, py_image_mask_ellipse);
#ifdef IMLIB_ENABLE_FLOOD_FILL
STATIC mp_obj_t py_image_flood_fill(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]);
const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 1, 2, &arg_vec);
int arg_x_off = mp_obj_get_int(arg_vec[0]);
int arg_y_off = mp_obj_get_int(arg_vec[1]);
float arg_seed_threshold =
py_helper_keyword_float(n_args, args, offset + 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_seed_threshold), 0.05);
PY_ASSERT_TRUE_MSG((0.0f <= arg_seed_threshold) && (arg_seed_threshold <= 1.0f),
"Error: 0.0 <= seed_threshold <= 1.0!");
float arg_floating_threshold =
py_helper_keyword_float(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_floating_threshold), 0.05);
PY_ASSERT_TRUE_MSG((0.0f <= arg_floating_threshold) && (arg_floating_threshold <= 1.0f),
"Error: 0.0 <= floating_threshold <= 1.0!");
int arg_c =
py_helper_keyword_color(arg_img, n_args, args, offset + 2, kw_args, -1); // White.
bool arg_invert =
py_helper_keyword_float(n_args, args, offset + 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false);
bool clear_background =
py_helper_keyword_float(n_args, args, offset + 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_clear_background), false);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, offset + 5, kw_args);
fb_alloc_mark();
imlib_flood_fill(arg_img, arg_x_off, arg_y_off,
arg_seed_threshold, arg_floating_threshold,
arg_c, arg_invert, clear_background, arg_msk);
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_flood_fill_obj, 2, py_image_flood_fill);
#endif // IMLIB_ENABLE_FLOOD_FILL
#ifdef IMLIB_ENABLE_BINARY_OPS
/////////////////
// Binary Methods
/////////////////
STATIC mp_obj_t py_image_binary(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]);
list_t arg_thresholds;
list_init(&arg_thresholds, sizeof(color_thresholds_list_lnk_data_t));
py_helper_arg_to_thresholds(args[1], &arg_thresholds);
bool arg_invert =
py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false);
bool arg_zero =
py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_zero), false);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 4, kw_args);
bool arg_to_bitmap =
py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_to_bitmap), false);
bool arg_copy =
py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy), false);
if (arg_to_bitmap && (!arg_copy)) {
switch(arg_img->bpp) {
case IMAGE_BPP_GRAYSCALE: {
PY_ASSERT_TRUE_MSG((arg_img->w >= (sizeof(uint32_t)/sizeof(uint8_t))),
"Can't convert to bitmap in place!");
break;
}
case IMAGE_BPP_RGB565: {
PY_ASSERT_TRUE_MSG((arg_img->w >= (sizeof(uint32_t)/sizeof(uint16_t))),
"Can't convert to bitmap in place!");
break;
}
default: {
break;
}
}
}
image_t out;
out.w = arg_img->w;
out.h = arg_img->h;
out.bpp = arg_to_bitmap ? IMAGE_BPP_BINARY : arg_img->bpp;
out.data = arg_copy ? xalloc(image_size(&out)) : arg_img->data;
fb_alloc_mark();
imlib_binary(&out, arg_img, &arg_thresholds, arg_invert, arg_zero, arg_msk);
fb_alloc_free_till_mark();
list_free(&arg_thresholds);
if (arg_to_bitmap && (!arg_copy)) {
arg_img->bpp = IMAGE_BPP_BINARY;
if ((MAIN_FB()->pixels == out.data)) {
MAIN_FB()->bpp = out.bpp;
}
}
return py_image_from_struct(&out);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_binary_obj, 2, py_image_binary);
STATIC mp_obj_t py_image_invert(mp_obj_t img_obj)
{
imlib_invert(py_helper_arg_to_image_mutable(img_obj));
return img_obj;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_invert_obj, py_image_invert);
STATIC mp_obj_t py_image_b_and(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]);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args);
fb_alloc_mark();
if (MP_OBJ_IS_STR(args[1])) {
imlib_b_and(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk);
} else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) {
imlib_b_and(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk);
} else {
imlib_b_and(arg_img, NULL, NULL,
py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0),
arg_msk);
}
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_and_obj, 2, py_image_b_and);
STATIC mp_obj_t py_image_b_nand(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]);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args);
fb_alloc_mark();
if (MP_OBJ_IS_STR(args[1])) {
imlib_b_nand(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk);
} else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) {
imlib_b_nand(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk);
} else {
imlib_b_nand(arg_img, NULL, NULL,
py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0),
arg_msk);
}
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_nand_obj, 2, py_image_b_nand);
STATIC mp_obj_t py_image_b_or(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]);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args);
fb_alloc_mark();
if (MP_OBJ_IS_STR(args[1])) {
imlib_b_or(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk);
} else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) {
imlib_b_or(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk);
} else {
imlib_b_or(arg_img, NULL, NULL,
py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0),
arg_msk);
}
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_or_obj, 2, py_image_b_or);
STATIC mp_obj_t py_image_b_nor(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]);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args);
fb_alloc_mark();
if (MP_OBJ_IS_STR(args[1])) {
imlib_b_nor(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk);
} else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) {
imlib_b_nor(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk);
} else {
imlib_b_nor(arg_img, NULL, NULL,
py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0),
arg_msk);
}
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_nor_obj, 2, py_image_b_nor);
STATIC mp_obj_t py_image_b_xor(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]);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args);
fb_alloc_mark();
if (MP_OBJ_IS_STR(args[1])) {
imlib_b_xor(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk);
} else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) {
imlib_b_xor(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk);
} else {
imlib_b_xor(arg_img, NULL, NULL,
py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0),
arg_msk);
}
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_xor_obj, 2, py_image_b_xor);
STATIC mp_obj_t py_image_b_xnor(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]);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args);
fb_alloc_mark();
if (MP_OBJ_IS_STR(args[1])) {
imlib_b_xnor(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk);
} else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) {
imlib_b_xnor(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk);
} else {
imlib_b_xnor(arg_img, NULL, NULL,
py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0),
arg_msk);
}
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_xnor_obj, 2, py_image_b_xnor);
STATIC mp_obj_t py_image_erode(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),
py_helper_ksize_to_n(arg_ksize) - 1);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args);
fb_alloc_mark();
imlib_erode(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_erode_obj, 2, py_image_erode);
STATIC mp_obj_t py_image_dilate(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_dilate(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_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);
#endif // IMLIB_ENABLE_BINARY_OPS
#ifdef IMLIB_ENABLE_MATH_OPS
///////////////
// Math Methods
///////////////
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);
STATIC mp_obj_t py_image_gamma_corr(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]);
float arg_gamma =
py_helper_keyword_float(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_gamma), 1.0f);
float arg_contrast =
py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_contrast), 1.0f);
float arg_brightness =
py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_brightness), 0.0f);
fb_alloc_mark();
imlib_gamma_corr(arg_img, arg_gamma, arg_contrast, arg_brightness);
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_gamma_corr_obj, 1, py_image_gamma_corr);
STATIC mp_obj_t py_image_negate(mp_obj_t img_obj)
{
imlib_negate(py_helper_arg_to_image_mutable(img_obj));
return img_obj;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_negate_obj, py_image_negate);
STATIC mp_obj_t py_image_replace(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]);
bool arg_hmirror =
py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_hmirror), false);
bool arg_vflip =
py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_vflip), false);
bool arg_transpose =
py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_transpose), false);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 5, kw_args);
if (arg_transpose) {
size_t size0 = image_size(arg_img);
int w = arg_img->w;
int h = arg_img->h;
arg_img->w = h;
arg_img->h = w;
size_t size1 = image_size(arg_img);
arg_img->w = w;
arg_img->h = h;
PY_ASSERT_TRUE_MSG(size1 <= size0,
"Unable to transpose the image because it would grow in size!");
}
fb_alloc_mark();
mp_obj_t arg_1 = (n_args > 1) ? args[1] : args[0];
if (MP_OBJ_IS_STR(arg_1)) {
imlib_replace(arg_img, mp_obj_str_get_str(arg_1), NULL, 0,
arg_hmirror, arg_vflip, arg_transpose, arg_msk);
} else if (MP_OBJ_IS_TYPE(arg_1, &py_image_type)) {
imlib_replace(arg_img, NULL, py_helper_arg_to_image_mutable(arg_1), 0,
arg_hmirror, arg_vflip, arg_transpose, arg_msk);
} else {
imlib_replace(arg_img, NULL, NULL,
py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0),
arg_hmirror, arg_vflip, arg_transpose, arg_msk);
}
fb_alloc_free_till_mark();
if (MAIN_FB()->pixels == arg_img->data) {
MAIN_FB()->w = arg_img->w;
MAIN_FB()->h = arg_img->h;
}
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_replace_obj, 1, py_image_replace);
STATIC mp_obj_t py_image_add(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]);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args);
fb_alloc_mark();
if (MP_OBJ_IS_STR(args[1])) {
imlib_add(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk);
} else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) {
imlib_add(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk);
} else {
imlib_add(arg_img, NULL, NULL,
py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0),
arg_msk);
}
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_add_obj, 2, py_image_add);
STATIC mp_obj_t py_image_sub(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]);
bool arg_reverse =
py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_reverse), false);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args);
fb_alloc_mark();
if (MP_OBJ_IS_STR(args[1])) {
imlib_sub(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_reverse, arg_msk);
} else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) {
imlib_sub(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_reverse, arg_msk);
} else {
imlib_sub(arg_img, NULL, NULL,
py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0),
arg_reverse, arg_msk);
}
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_sub_obj, 2, py_image_sub);
STATIC mp_obj_t py_image_mul(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]);
bool arg_invert =
py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args);
fb_alloc_mark();
if (MP_OBJ_IS_STR(args[1])) {
imlib_mul(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_invert, arg_msk);
} else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) {
imlib_mul(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_invert, arg_msk);
} else {
imlib_mul(arg_img, NULL, NULL,
py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0),
arg_invert, arg_msk);
}
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mul_obj, 2, py_image_mul);
STATIC mp_obj_t py_image_div(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]);
bool arg_invert =
py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false);
bool arg_mod =
py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mod), false);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 4, kw_args);
fb_alloc_mark();
if (MP_OBJ_IS_STR(args[1])) {
imlib_div(arg_img, mp_obj_str_get_str(args[1]), NULL, 0,
arg_invert, arg_mod, arg_msk);
} else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) {
imlib_div(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0,
arg_invert, arg_mod, arg_msk);
} else {
imlib_div(arg_img, NULL, NULL,
py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0),
arg_invert, arg_mod, arg_msk);
}
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_div_obj, 2, py_image_div);
STATIC mp_obj_t py_image_min(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]);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args);
fb_alloc_mark();
if (MP_OBJ_IS_STR(args[1])) {
imlib_min(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk);
} else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) {
imlib_min(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk);
} else {
imlib_min(arg_img, NULL, NULL,
py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0),
arg_msk);
}
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_min_obj, 2, py_image_min);
STATIC mp_obj_t py_image_max(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]);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args);
fb_alloc_mark();
if (MP_OBJ_IS_STR(args[1])) {
imlib_max(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk);
} else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) {
imlib_max(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk);
} else {
imlib_max(arg_img, NULL, NULL,
py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0),
arg_msk);
}
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_max_obj, 2, py_image_max);
STATIC mp_obj_t py_image_difference(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]);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args);
fb_alloc_mark();
if (MP_OBJ_IS_STR(args[1])) {
imlib_difference(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk);
} else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) {
imlib_difference(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk);
} else {
imlib_difference(arg_img, NULL, NULL,
py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0),
arg_msk);
}
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_difference_obj, 2, py_image_difference);
STATIC mp_obj_t py_image_blend(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]);
float arg_alpha =
py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_alpha), 128) / 256.0f;
PY_ASSERT_TRUE_MSG((0 <= arg_alpha) && (arg_alpha <= 1), "Error: 0 <= alpha <= 256!");
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args);
fb_alloc_mark();
if (MP_OBJ_IS_STR(args[1])) {
imlib_blend(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_alpha, arg_msk);
} else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) {
imlib_blend(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_alpha, arg_msk);
} else {
imlib_blend(arg_img, NULL, NULL,
py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0),
arg_alpha, arg_msk);
}
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_blend_obj, 2, py_image_blend);
#endif//IMLIB_ENABLE_MATH_OPS
////////////////////
// Filtering Methods
////////////////////
static mp_obj_t py_image_histeq(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]);
bool arg_adaptive =
py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_adaptive), false);
float arg_clip_limit =
py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_clip_limit), -1);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args);
fb_alloc_mark();
if (arg_adaptive) imlib_clahe_histeq(arg_img, arg_clip_limit, arg_msk); else imlib_histeq(arg_img, arg_msk);
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_histeq_obj, 1, py_image_histeq);
#ifdef IMLIB_ENABLE_MEAN
STATIC mp_obj_t py_image_mean(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img =
py_helper_arg_to_image_mutable(args[0]);
int arg_ksize =
py_helper_arg_to_ksize(args[1]);
bool arg_threshold =
py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false);
int arg_offset =
py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0);
bool arg_invert =
py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 5, kw_args);
fb_alloc_mark();
imlib_mean_filter(arg_img, arg_ksize, 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_mean_obj, 2, py_image_mean);
#endif // IMLIB_ENABLE_MEAN
#ifdef IMLIB_ENABLE_MEDIAN
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_helper_arg_to_image_mutable(args[0]);
int arg_ksize =
py_helper_arg_to_ksize(args[1]);
float arg_percentile =
py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_percentile), 0.5f);
PY_ASSERT_TRUE_MSG((0 <= arg_percentile) && (arg_percentile <= 1), "Error: 0 <= percentile <= 1!");
bool arg_threshold =
py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false);
int arg_offset =
py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0);
bool arg_invert =
py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 6, kw_args);
fb_alloc_mark();
imlib_median_filter(arg_img, arg_ksize, arg_percentile, 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_median_obj, 2, py_image_median);
#endif // IMLIB_ENABLE_MEDIAN
#ifdef IMLIB_ENABLE_MODE
STATIC mp_obj_t py_image_mode(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img =
py_helper_arg_to_image_mutable(args[0]);
int arg_ksize =
py_helper_arg_to_ksize(args[1]);
bool arg_threshold =
py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false);
int arg_offset =
py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0);
bool arg_invert =
py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 5, kw_args);
fb_alloc_mark();
imlib_mode_filter(arg_img, arg_ksize, 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_mode_obj, 2, py_image_mode);
#endif // IMLIB_ENABLE_MODE
#ifdef IMLIB_ENABLE_MIDPOINT
STATIC mp_obj_t py_image_midpoint(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_bias =
py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bias), 0.5f);
PY_ASSERT_TRUE_MSG((0 <= arg_bias) && (arg_bias <= 1), "Error: 0 <= bias <= 1!");
bool arg_threshold =
py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false);
int arg_offset =
py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0);
bool arg_invert =
py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 6, kw_args);
fb_alloc_mark();
imlib_midpoint_filter(arg_img, arg_ksize, arg_bias, 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_midpoint_obj, 2, py_image_midpoint);
#endif // IMLIB_ENABLE_MIDPOINT
#ifdef IMLIB_ENABLE_MORPH
STATIC mp_obj_t py_image_morph(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]);
int n = py_helper_ksize_to_n(arg_ksize);
mp_obj_t *krn;
mp_obj_get_array_fixed_n(args[2], n, &krn);
fb_alloc_mark();
int *arg_krn = fb_alloc(n * sizeof(int));
int arg_m = 0;
for (int i = 0; i < n; i++) {
arg_krn[i] = mp_obj_get_int(krn[i]);
arg_m += arg_krn[i];
}
if (arg_m == 0) {
arg_m = 1;
}
float arg_mul =
py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mul), 1.0f / arg_m);
float arg_add =
py_helper_keyword_float(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_add), 0.0f);
bool arg_threshold =
py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false);
int arg_offset =
py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0);
bool arg_invert =
py_helper_keyword_int(n_args, args, 7, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 8, kw_args);
imlib_morph(arg_img, arg_ksize, arg_krn, arg_mul, arg_add, 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_morph_obj, 3, py_image_morph);
#endif //IMLIB_ENABLE_MORPH
#ifdef IMLIB_ENABLE_GAUSSIAN
STATIC mp_obj_t py_image_gaussian(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]);
int k_2 = arg_ksize * 2;
int n = k_2 + 1;
fb_alloc_mark();
int *pascal = fb_alloc(n * sizeof(int));
pascal[0] = 1;
for (int i = 0; i < k_2; i++) { // Compute a row of pascal's triangle.
pascal[i + 1] = (pascal[i] * (k_2 - i)) / (i + 1);
}
int *arg_krn = fb_alloc(n * n * sizeof(int));
int arg_m = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
int temp = pascal[i] * pascal[j];
arg_krn[(i * n) + j] = temp;
arg_m += temp;
}
}
if (py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_unsharp), false)) {
arg_krn[((n/2)*n)+(n/2)] -= arg_m * 2;
arg_m = -arg_m;
}
float arg_mul =
py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mul), 1.0f / arg_m);
float arg_add =
py_helper_keyword_float(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_add), 0.0f);
bool arg_threshold =
py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false);
int arg_offset =
py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0);
bool arg_invert =
py_helper_keyword_int(n_args, args, 7, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 8, kw_args);
imlib_morph(arg_img, arg_ksize, arg_krn, arg_mul, arg_add, 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_gaussian_obj, 2, py_image_gaussian);
#endif // IMLIB_ENABLE_GAUSSIAN
#ifdef IMLIB_ENABLE_LAPLACIAN
STATIC mp_obj_t py_image_laplacian(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]);
int k_2 = arg_ksize * 2;
int n = k_2 + 1;
fb_alloc_mark();
int *pascal = fb_alloc(n * sizeof(int));
pascal[0] = 1;
for (int i = 0; i < k_2; i++) { // Compute a row of pascal's triangle.
pascal[i + 1] = (pascal[i] * (k_2 - i)) / (i + 1);
}
int *arg_krn = fb_alloc(n * n * sizeof(int));
int arg_m = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
int temp = pascal[i] * pascal[j];
arg_krn[(i * n) + j] = -temp;
arg_m += temp;
}
}
arg_krn[((n/2)*n)+(n/2)] += arg_m;
arg_m = arg_krn[((n/2)*n)+(n/2)];
if (py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_sharpen), false)) {
arg_krn[((n/2)*n)+(n/2)] += arg_m;
}
float arg_mul =
py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mul), 1.0f / arg_m);
float arg_add =
py_helper_keyword_float(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_add), 0.0f);
bool arg_threshold =
py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false);
int arg_offset =
py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0);
bool arg_invert =
py_helper_keyword_int(n_args, args, 7, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false);
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 8, kw_args);
imlib_morph(arg_img, arg_ksize, arg_krn, arg_mul, arg_add, 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_laplacian_obj, 2, py_image_laplacian);
#endif // IMLIB_ENABLE_LAPLACIAN
#ifdef IMLIB_ENABLE_BILATERAL
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), 0.1);
float arg_space_sigma =
py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_space_sigma), 1);
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);
#endif // IMLIB_ENABLE_BILATERAL
#ifdef IMLIB_ENABLE_CARTOON
STATIC mp_obj_t py_image_cartoon(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]);
float arg_seed_threshold =
py_helper_keyword_float(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_seed_threshold), 0.05);
PY_ASSERT_TRUE_MSG((0.0f <= arg_seed_threshold) && (arg_seed_threshold <= 1.0f),
"Error: 0.0 <= seed_threshold <= 1.0!");
float arg_floating_threshold =
py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_floating_threshold), 0.05);
PY_ASSERT_TRUE_MSG((0.0f <= arg_floating_threshold) && (arg_floating_threshold <= 1.0f),
"Error: 0.0 <= floating_threshold <= 1.0!");
image_t *arg_msk =
py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args);
fb_alloc_mark();
imlib_cartoon_filter(arg_img, arg_seed_threshold, arg_floating_threshold, arg_msk);
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_cartoon_obj, 1, py_image_cartoon);
#endif // IMLIB_ENABLE_CARTOON
/////////////////////////
// Shadow Removal Methods
/////////////////////////
#ifdef IMLIB_ENABLE_REMOVE_SHADOWS
STATIC mp_obj_t py_image_remove_shadows(uint n_args, const mp_obj_t *args)
{
image_t *arg_img =
py_helper_arg_to_image_color(args[0]);
fb_alloc_mark();
if (n_args < 2) {
imlib_remove_shadows(arg_img, NULL, NULL, 0, true);
} else if (MP_OBJ_IS_STR(args[1])) {
imlib_remove_shadows(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, false);
} else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) {
imlib_remove_shadows(arg_img, NULL, py_helper_arg_to_image_color(args[1]), 0, false);
} else {
imlib_remove_shadows(arg_img, NULL, NULL,
py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0),
false);
}
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_image_remove_shadows_obj, 1, 2, py_image_remove_shadows);
#endif // IMLIB_ENABLE_REMOVE_SHADOWS
#ifdef IMLIB_ENABLE_CHROMINVAR
STATIC mp_obj_t py_image_chrominvar(mp_obj_t img_obj)
{
fb_alloc_mark();
imlib_chrominvar(py_helper_arg_to_image_color(img_obj));
fb_alloc_free_till_mark();
return img_obj;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_chrominvar_obj, py_image_chrominvar);
#endif // IMLIB_ENABLE_CHROMINVAR
#ifdef IMLIB_ENABLE_ILLUMINVAR
STATIC mp_obj_t py_image_illuminvar(mp_obj_t img_obj)
{
fb_alloc_mark();
imlib_illuminvar(py_helper_arg_to_image_color(img_obj));
fb_alloc_free_till_mark();
return img_obj;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_illuminvar_obj, py_image_illuminvar);
#endif // IMLIB_ENABLE_ILLUMINVAR
////////////////////
// Geometric Methods
////////////////////
#ifdef IMLIB_ENABLE_LINPOLAR
static mp_obj_t py_image_linpolar(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]);
bool arg_reverse =
py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_reverse), false);
fb_alloc_mark();
imlib_logpolar(arg_img, true, arg_reverse);
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_linpolar_obj, 1, py_image_linpolar);
#endif // IMLIB_ENABLE_LINPOLAR
#ifdef IMLIB_ENABLE_LOGPOLAR
static mp_obj_t py_image_logpolar(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]);
bool arg_reverse =
py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_reverse), false);
fb_alloc_mark();
imlib_logpolar(arg_img, false, arg_reverse);
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_logpolar_obj, 1, py_image_logpolar);
#endif // IMLIB_ENABLE_LOGPOLAR
STATIC mp_obj_t py_image_lens_corr(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]);
float arg_strength =
py_helper_keyword_float(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_strength), 1.8);
PY_ASSERT_TRUE_MSG(arg_strength > 0.0, "Strength must be > 0!");
float arg_zoom =
py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_zoom), 1.0);
PY_ASSERT_TRUE_MSG(arg_zoom > 0.0, "Zoom must be > 0!");
fb_alloc_mark();
imlib_lens_corr(arg_img, arg_strength, arg_zoom);
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_lens_corr_obj, 1, py_image_lens_corr);
#ifdef IMLIB_ENABLE_ROTATION_CORR
STATIC mp_obj_t py_image_rotation_corr(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]);
float arg_x_rotation =
IM_DEG2RAD(py_helper_keyword_float(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_rotation), 0.0));
float arg_y_rotation =
IM_DEG2RAD(py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_rotation), 0.0));
float arg_z_rotation =
IM_DEG2RAD(py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_z_rotation), 0.0));
float arg_x_translation =
py_helper_keyword_float(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_translation), 0.0);
float arg_y_translation =
py_helper_keyword_float(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_translation), 0.0);
float arg_zoom =
py_helper_keyword_float(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_zoom), 1.0);
PY_ASSERT_TRUE_MSG(arg_zoom > 0.0, "Zoom must be > 0!");
fb_alloc_mark();
imlib_rotation_corr(arg_img,
arg_x_rotation, arg_y_rotation, arg_z_rotation,
arg_x_translation, arg_y_translation,
arg_zoom);
fb_alloc_free_till_mark();
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_rotation_corr_obj, 1, py_image_rotation_corr);
#endif // IMLIB_ENABLE_ROTATION_CORR
//////////////
// Get Methods
//////////////
#ifdef IMLIB_ENABLE_GET_SIMILARITY
// Similarity Object //
#define py_similarity_obj_size 4
typedef struct py_similarity_obj {
mp_obj_base_t base;
mp_obj_t avg, std, min, max;
} py_similarity_obj_t;
static void py_similarity_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
{
py_similarity_obj_t *self = self_in;
mp_printf(print,
"{\"mean\":%f, \"stdev\":%f, \"min\":%f, \"max\":%f}",
(double) mp_obj_get_float(self->avg),
(double) mp_obj_get_float(self->std),
(double) mp_obj_get_float(self->min),
(double) mp_obj_get_float(self->max));
}
static mp_obj_t py_similarity_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value)
{
if (value == MP_OBJ_SENTINEL) { // load
py_similarity_obj_t *self = self_in;
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(py_similarity_obj_size, index, &slice)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported"));
}
mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL);
mp_seq_copy(result->items, &(self->avg) + slice.start, result->len, mp_obj_t);
return result;
}
switch (mp_get_index(self->base.type, py_similarity_obj_size, index, false)) {
case 0: return self->avg;
case 1: return self->std;
case 2: return self->min;
case 3: return self->max;
}
}
return MP_OBJ_NULL; // op not supported
}
mp_obj_t py_similarity_mean(mp_obj_t self_in) { return ((py_similarity_obj_t *) self_in)->avg; }
mp_obj_t py_similarity_stdev(mp_obj_t self_in) { return ((py_similarity_obj_t *) self_in)->std; }
mp_obj_t py_similarity_min(mp_obj_t self_in) { return ((py_similarity_obj_t *) self_in)->min; }
mp_obj_t py_similarity_max(mp_obj_t self_in) { return ((py_similarity_obj_t *) self_in)->max; }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_similarity_mean_obj, py_similarity_mean);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_similarity_stdev_obj, py_similarity_stdev);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_similarity_min_obj, py_similarity_min);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_similarity_max_obj, py_similarity_max);
STATIC const mp_rom_map_elem_t py_similarity_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_mean), MP_ROM_PTR(&py_similarity_mean_obj) },
{ MP_ROM_QSTR(MP_QSTR_stdev), MP_ROM_PTR(&py_similarity_stdev_obj) },
{ MP_ROM_QSTR(MP_QSTR_min), MP_ROM_PTR(&py_similarity_min_obj) },
{ MP_ROM_QSTR(MP_QSTR_max), MP_ROM_PTR(&py_similarity_max_obj) }
};
STATIC MP_DEFINE_CONST_DICT(py_similarity_locals_dict, py_similarity_locals_dict_table);
static const mp_obj_type_t py_similarity_type = {
{ &mp_type_type },
.name = MP_QSTR_similarity,
.print = py_similarity_print,
.subscr = py_similarity_subscr,
.locals_dict = (mp_obj_t) &py_similarity_locals_dict
};
static mp_obj_t py_image_get_similarity(mp_obj_t img_obj, mp_obj_t other_obj)
{
image_t *arg_img = py_helper_arg_to_image_mutable(img_obj);
float avg, std, min, max;
fb_alloc_mark();
if (MP_OBJ_IS_STR(other_obj)) {
imlib_get_similarity(arg_img, mp_obj_str_get_str(other_obj), NULL, 0, &avg, &std, &min, &max);
} else if (MP_OBJ_IS_TYPE(other_obj, &py_image_type)) {
imlib_get_similarity(arg_img, NULL, py_helper_arg_to_image_mutable(other_obj), 0, &avg, &std, &min, &max);
} else {
imlib_get_similarity(arg_img, NULL, NULL,
py_helper_keyword_color(arg_img, 1, &other_obj, 0, NULL, 0),
&avg, &std, &min, &max);
}
fb_alloc_free_till_mark();
py_similarity_obj_t *o = m_new_obj(py_similarity_obj_t);
o->base.type = &py_similarity_type;
o->avg = mp_obj_new_float(avg);
o->std = mp_obj_new_float(std);
o->min = mp_obj_new_float(min);
o->max = mp_obj_new_float(max);
return o;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_get_similarity_obj, py_image_get_similarity);
#endif // IMLIB_ENABLE_GET_SIMILARITY
// Statistics Object //
#define py_statistics_obj_size 24
typedef struct py_statistics_obj {
mp_obj_base_t base;
image_bpp_t bpp;
mp_obj_t LMean, LMedian, LMode, LSTDev, LMin, LMax, LLQ, LUQ,
AMean, AMedian, AMode, ASTDev, AMin, AMax, ALQ, AUQ,
BMean, BMedian, BMode, BSTDev, BMin, BMax, BLQ, BUQ;
} py_statistics_obj_t;
static void py_statistics_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
{
py_statistics_obj_t *self = self_in;
switch(self->bpp) {
case IMAGE_BPP_BINARY: {
mp_printf(print, "{\"mean\":%d, \"median\":%d, \"mode\":%d, \"stdev\":%d, \"min\":%d, \"max\":%d, \"lq\":%d, \"uq\":%d}",
mp_obj_get_int(self->LMean),
mp_obj_get_int(self->LMedian),
mp_obj_get_int(self->LMode),
mp_obj_get_int(self->LSTDev),
mp_obj_get_int(self->LMin),
mp_obj_get_int(self->LMax),
mp_obj_get_int(self->LLQ),
mp_obj_get_int(self->LUQ));
break;
}
case IMAGE_BPP_GRAYSCALE: {
mp_printf(print, "{\"mean\":%d, \"median\":%d, \"mode\":%d, \"stdev\":%d, \"min\":%d, \"max\":%d, \"lq\":%d, \"uq\":%d}",
mp_obj_get_int(self->LMean),
mp_obj_get_int(self->LMedian),
mp_obj_get_int(self->LMode),
mp_obj_get_int(self->LSTDev),
mp_obj_get_int(self->LMin),
mp_obj_get_int(self->LMax),
mp_obj_get_int(self->LLQ),
mp_obj_get_int(self->LUQ));
break;
}
case IMAGE_BPP_RGB565: {
mp_printf(print, "{\"l_mean\":%d, \"l_median\":%d, \"l_mode\":%d, \"l_stdev\":%d, \"l_min\":%d, \"l_max\":%d, \"l_lq\":%d, \"l_uq\":%d,"
" \"a_mean\":%d, \"a_median\":%d, \"a_mode\":%d, \"a_stdev\":%d, \"a_min\":%d, \"a_max\":%d, \"a_lq\":%d, \"a_uq\":%d,"
" \"b_mean\":%d, \"b_median\":%d, \"b_mode\":%d, \"b_stdev\":%d, \"b_min\":%d, \"b_max\":%d, \"b_lq\":%d, \"b_uq\":%d}",
mp_obj_get_int(self->LMean),
mp_obj_get_int(self->LMedian),
mp_obj_get_int(self->LMode),
mp_obj_get_int(self->LSTDev),
mp_obj_get_int(self->LMin),
mp_obj_get_int(self->LMax),
mp_obj_get_int(self->LLQ),
mp_obj_get_int(self->LUQ),
mp_obj_get_int(self->AMean),
mp_obj_get_int(self->AMedian),
mp_obj_get_int(self->AMode),
mp_obj_get_int(self->ASTDev),
mp_obj_get_int(self->AMin),
mp_obj_get_int(self->AMax),
mp_obj_get_int(self->ALQ),
mp_obj_get_int(self->AUQ),
mp_obj_get_int(self->BMean),
mp_obj_get_int(self->BMedian),
mp_obj_get_int(self->BMode),
mp_obj_get_int(self->BSTDev),
mp_obj_get_int(self->BMin),
mp_obj_get_int(self->BMax),
mp_obj_get_int(self->BLQ),
mp_obj_get_int(self->BUQ));
break;
}
default: {
mp_printf(print, "{}");
break;
}
}
}
static mp_obj_t py_statistics_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value)
{
if (value == MP_OBJ_SENTINEL) { // load
py_statistics_obj_t *self = self_in;
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(py_statistics_obj_size, index, &slice)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported"));
}
mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL);
mp_seq_copy(result->items, &(self->LMean) + slice.start, result->len, mp_obj_t);
return result;
}
switch (mp_get_index(self->base.type, py_statistics_obj_size, index, false)) {
case 0: return self->LMean;
case 1: return self->LMedian;
case 2: return self->LMode;
case 3: return self->LSTDev;
case 4: return self->LMin;
case 5: return self->LMax;
case 6: return self->LLQ;
case 7: return self->LUQ;
case 8: return self->AMean;
case 9: return self->AMedian;
case 10: return self->AMode;
case 11: return self->ASTDev;
case 12: return self->AMin;
case 13: return self->AMax;
case 14: return self->ALQ;
case 15: return self->AUQ;
case 16: return self->BMean;
case 17: return self->BMedian;
case 18: return self->BMode;
case 19: return self->BSTDev;
case 20: return self->BMin;
case 21: return self->BMax;
case 22: return self->BLQ;
case 23: return self->BUQ;
}
}
return MP_OBJ_NULL; // op not supported
}
mp_obj_t py_statistics_mean(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMean; }
mp_obj_t py_statistics_median(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMedian; }
mp_obj_t py_statistics_mode(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMode; }
mp_obj_t py_statistics_stdev(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LSTDev; }
mp_obj_t py_statistics_min(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMin; }
mp_obj_t py_statistics_max(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMax; }
mp_obj_t py_statistics_lq(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LLQ; }
mp_obj_t py_statistics_uq(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LUQ; }
mp_obj_t py_statistics_l_mean(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMean; }
mp_obj_t py_statistics_l_median(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMedian; }
mp_obj_t py_statistics_l_mode(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMode; }
mp_obj_t py_statistics_l_stdev(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LSTDev; }
mp_obj_t py_statistics_l_min(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMin; }
mp_obj_t py_statistics_l_max(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMax; }
mp_obj_t py_statistics_l_lq(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LLQ; }
mp_obj_t py_statistics_l_uq(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LUQ; }
mp_obj_t py_statistics_a_mean(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->AMean; }
mp_obj_t py_statistics_a_median(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->AMedian; }
mp_obj_t py_statistics_a_mode(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->AMode; }
mp_obj_t py_statistics_a_stdev(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->ASTDev; }
mp_obj_t py_statistics_a_min(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->AMin; }
mp_obj_t py_statistics_a_max(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->AMax; }
mp_obj_t py_statistics_a_lq(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->ALQ; }
mp_obj_t py_statistics_a_uq(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->AUQ; }
mp_obj_t py_statistics_b_mean(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->BMean; }
mp_obj_t py_statistics_b_median(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->BMedian; }
mp_obj_t py_statistics_b_mode(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->BMode; }
mp_obj_t py_statistics_b_stdev(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->BSTDev; }
mp_obj_t py_statistics_b_min(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->BMin; }
mp_obj_t py_statistics_b_max(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->BMax; }
mp_obj_t py_statistics_b_lq(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->BLQ; }
mp_obj_t py_statistics_b_uq(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->BUQ; }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_mean_obj, py_statistics_mean);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_median_obj, py_statistics_median);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_mode_obj, py_statistics_mode);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_stdev_obj, py_statistics_stdev);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_min_obj, py_statistics_min);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_max_obj, py_statistics_max);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_lq_obj, py_statistics_lq);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_uq_obj, py_statistics_uq);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_l_mean_obj, py_statistics_l_mean);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_l_median_obj, py_statistics_l_median);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_l_mode_obj, py_statistics_l_mode);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_l_stdev_obj, py_statistics_l_stdev);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_l_min_obj, py_statistics_l_min);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_l_max_obj, py_statistics_l_max);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_l_lq_obj, py_statistics_l_lq);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_l_uq_obj, py_statistics_l_uq);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_a_mean_obj, py_statistics_a_mean);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_a_median_obj, py_statistics_a_median);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_a_mode_obj, py_statistics_a_mode);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_a_stdev_obj, py_statistics_a_stdev);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_a_min_obj, py_statistics_a_min);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_a_max_obj, py_statistics_a_max);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_a_lq_obj, py_statistics_a_lq);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_a_uq_obj, py_statistics_a_uq);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_b_mean_obj, py_statistics_b_mean);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_b_median_obj, py_statistics_b_median);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_b_mode_obj, py_statistics_b_mode);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_b_stdev_obj, py_statistics_b_stdev);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_b_min_obj, py_statistics_b_min);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_b_max_obj, py_statistics_b_max);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_b_lq_obj, py_statistics_b_lq);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_b_uq_obj, py_statistics_b_uq);
STATIC const mp_rom_map_elem_t py_statistics_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_mean), MP_ROM_PTR(&py_statistics_mean_obj) },
{ MP_ROM_QSTR(MP_QSTR_median), MP_ROM_PTR(&py_statistics_median_obj) },
{ MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&py_statistics_mode_obj) },
{ MP_ROM_QSTR(MP_QSTR_stdev), MP_ROM_PTR(&py_statistics_stdev_obj) },
{ MP_ROM_QSTR(MP_QSTR_min), MP_ROM_PTR(&py_statistics_min_obj) },
{ MP_ROM_QSTR(MP_QSTR_max), MP_ROM_PTR(&py_statistics_max_obj) },
{ MP_ROM_QSTR(MP_QSTR_lq), MP_ROM_PTR(&py_statistics_lq_obj) },
{ MP_ROM_QSTR(MP_QSTR_uq), MP_ROM_PTR(&py_statistics_uq_obj) },
{ MP_ROM_QSTR(MP_QSTR_l_mean), MP_ROM_PTR(&py_statistics_l_mean_obj) },
{ MP_ROM_QSTR(MP_QSTR_l_median), MP_ROM_PTR(&py_statistics_l_median_obj) },
{ MP_ROM_QSTR(MP_QSTR_l_mode), MP_ROM_PTR(&py_statistics_l_mode_obj) },
{ MP_ROM_QSTR(MP_QSTR_l_stdev), MP_ROM_PTR(&py_statistics_l_stdev_obj) },
{ MP_ROM_QSTR(MP_QSTR_l_min), MP_ROM_PTR(&py_statistics_l_min_obj) },
{ MP_ROM_QSTR(MP_QSTR_l_max), MP_ROM_PTR(&py_statistics_l_max_obj) },
{ MP_ROM_QSTR(MP_QSTR_l_lq), MP_ROM_PTR(&py_statistics_l_lq_obj) },
{ MP_ROM_QSTR(MP_QSTR_l_uq), MP_ROM_PTR(&py_statistics_l_uq_obj) },
{ MP_ROM_QSTR(MP_QSTR_a_mean), MP_ROM_PTR(&py_statistics_a_mean_obj) },
{ MP_ROM_QSTR(MP_QSTR_a_median), MP_ROM_PTR(&py_statistics_a_median_obj) },
{ MP_ROM_QSTR(MP_QSTR_a_mode), MP_ROM_PTR(&py_statistics_a_mode_obj) },
{ MP_ROM_QSTR(MP_QSTR_a_stdev), MP_ROM_PTR(&py_statistics_a_stdev_obj) },
{ MP_ROM_QSTR(MP_QSTR_a_min), MP_ROM_PTR(&py_statistics_a_min_obj) },
{ MP_ROM_QSTR(MP_QSTR_a_max), MP_ROM_PTR(&py_statistics_a_max_obj) },
{ MP_ROM_QSTR(MP_QSTR_a_lq), MP_ROM_PTR(&py_statistics_a_lq_obj) },
{ MP_ROM_QSTR(MP_QSTR_a_uq), MP_ROM_PTR(&py_statistics_a_uq_obj) },
{ MP_ROM_QSTR(MP_QSTR_b_mean), MP_ROM_PTR(&py_statistics_b_mean_obj) },
{ MP_ROM_QSTR(MP_QSTR_b_median), MP_ROM_PTR(&py_statistics_b_median_obj) },
{ MP_ROM_QSTR(MP_QSTR_b_mode), MP_ROM_PTR(&py_statistics_b_mode_obj) },
{ MP_ROM_QSTR(MP_QSTR_b_stdev), MP_ROM_PTR(&py_statistics_b_stdev_obj) },
{ MP_ROM_QSTR(MP_QSTR_b_min), MP_ROM_PTR(&py_statistics_b_min_obj) },
{ MP_ROM_QSTR(MP_QSTR_b_max), MP_ROM_PTR(&py_statistics_b_max_obj) },
{ MP_ROM_QSTR(MP_QSTR_b_lq), MP_ROM_PTR(&py_statistics_b_lq_obj) },
{ MP_ROM_QSTR(MP_QSTR_b_uq), MP_ROM_PTR(&py_statistics_b_uq_obj) }
};
STATIC MP_DEFINE_CONST_DICT(py_statistics_locals_dict, py_statistics_locals_dict_table);
static const mp_obj_type_t py_statistics_type = {
{ &mp_type_type },
.name = MP_QSTR_statistics,
.print = py_statistics_print,
.subscr = py_statistics_subscr,
.locals_dict = (mp_obj_t) &py_statistics_locals_dict
};
// Percentile Object //
#define py_percentile_obj_size 3
typedef struct py_percentile_obj {
mp_obj_base_t base;
image_bpp_t bpp;
mp_obj_t LValue, AValue, BValue;
} py_percentile_obj_t;
static void py_percentile_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
{
py_percentile_obj_t *self = self_in;
switch(self->bpp) {
case IMAGE_BPP_BINARY: {
mp_printf(print, "{\"value\":%d}",
mp_obj_get_int(self->LValue));
break;
}
case IMAGE_BPP_GRAYSCALE: {
mp_printf(print, "{\"value\":%d}",
mp_obj_get_int(self->LValue));
break;
}
case IMAGE_BPP_RGB565: {
mp_printf(print, "{\"l_value:%d\", \"a_value\":%d, \"b_value\":%d}",
mp_obj_get_int(self->LValue),
mp_obj_get_int(self->AValue),
mp_obj_get_int(self->BValue));
break;
}
default: {
mp_printf(print, "{}");
break;
}
}
}
static mp_obj_t py_percentile_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value)
{
if (value == MP_OBJ_SENTINEL) { // load
py_percentile_obj_t *self = self_in;
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(py_percentile_obj_size, index, &slice)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported"));
}
mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL);
mp_seq_copy(result->items, &(self->LValue) + slice.start, result->len, mp_obj_t);
return result;
}
switch (mp_get_index(self->base.type, py_percentile_obj_size, index, false)) {
case 0: return self->LValue;
case 1: return self->AValue;
case 2: return self->BValue;
}
}
return MP_OBJ_NULL; // op not supported
}
mp_obj_t py_percentile_value(mp_obj_t self_in) { return ((py_percentile_obj_t *) self_in)->LValue; }
mp_obj_t py_percentile_l_value(mp_obj_t self_in) { return ((py_percentile_obj_t *) self_in)->LValue; }
mp_obj_t py_percentile_a_value(mp_obj_t self_in) { return ((py_percentile_obj_t *) self_in)->AValue; }
mp_obj_t py_percentile_b_value(mp_obj_t self_in) { return ((py_percentile_obj_t *) self_in)->BValue; }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_percentile_value_obj, py_percentile_value);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_percentile_l_value_obj, py_percentile_l_value);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_percentile_a_value_obj, py_percentile_a_value);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_percentile_b_value_obj, py_percentile_b_value);
STATIC const mp_rom_map_elem_t py_percentile_locals_dict_table