modules/py_image: Update morph() to use arg parse.

This commit is contained in:
Kwabena W. Agyeman 2024-05-12 21:46:35 -07:00
parent 547859cb00
commit 919d3379d2

View File

@ -2424,161 +2424,213 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_obj, 2, py_image_midpoint);
#endif // IMLIB_ENABLE_MIDPOINT #endif // IMLIB_ENABLE_MIDPOINT
#ifdef IMLIB_ENABLE_MORPH #ifdef IMLIB_ENABLE_MORPH
static mp_obj_t py_image_morph(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { static mp_obj_t py_image_morph(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
image_t *arg_img = enum { ARG_mul, ARG_add, ARG_threshold, ARG_offset, ARG_invert, ARG_mask };
py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); static const mp_arg_t allowed_args[] = {
int arg_ksize = { MP_QSTR_mul, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE } },
py_helper_arg_to_ksize(args[1]); { MP_QSTR_add, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE } },
{ MP_QSTR_threshold, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false } },
{ MP_QSTR_offset, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0 } },
{ MP_QSTR_invert, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false } },
{ MP_QSTR_mask, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} },
};
int n = imlib_ksize_to_n(arg_ksize); // Parse args.
image_t *image = py_helper_arg_to_image(pos_args[0], ARG_IMAGE_MUTABLE);
int ksize = py_helper_arg_to_ksize(pos_args[1]);
int n = (ksize * 2) + 1;
mp_obj_t *krn; if (n > 31) {
mp_obj_get_array_fixed_n(args[2], n, &krn); mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Kernel size too large!"));
}
size_t len;
mp_obj_t *items;
mp_obj_get_array(pos_args[2], &len, &items);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 3, pos_args + 3, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
fb_alloc_mark(); fb_alloc_mark();
int *arg_krn = fb_alloc(n * sizeof(int), FB_ALLOC_NO_HINT); int krn[n * n];
int arg_m = 0; int sum = 0;
for (int i = 0; i < n; i++) { if (len == n) {
arg_krn[i] = mp_obj_get_int(krn[i]); for (int i = 0; i < n; i++) {
arg_m += arg_krn[i]; size_t row_len;
mp_obj_t *row_items;
mp_obj_get_array(items[i], &row_len, &row_items);
if (row_len == n) {
for (int j = 0; j < n; j++) {
krn[(i * n) + j] = mp_obj_get_int(row_items[j]);
sum += krn[(i * n) + j];
}
} else {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Unexpected kernel dimensions!"));
}
}
} else if (len == (n * n)) {
for (int i = 0; i < (n * n); i++) {
krn[i] = mp_obj_get_int(items[i]);
sum += krn[i];
}
} else {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Unexpected kernel dimensions!"));
} }
if (arg_m == 0) { if (sum == 0) {
arg_m = 1; sum = 1;
} }
float arg_mul = image_t *mask = NULL;
py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mul), 1.0f / arg_m); if (args[ARG_mask].u_obj != mp_const_none) {
float arg_add = mask = py_helper_arg_to_image(args[ARG_mask].u_obj, ARG_IMAGE_MUTABLE | ARG_IMAGE_ALLOC);
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(n_args, args, 8, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL);
imlib_morph(arg_img, arg_ksize, arg_krn, arg_mul, arg_add, arg_threshold, arg_offset, arg_invert, arg_msk); float mul = py_helper_arg_to_float(args[ARG_mul].u_obj, 1.0f);
float add = py_helper_arg_to_float(args[ARG_add].u_obj, 0.0f);
imlib_morph(image, ksize, krn, mul / sum, add, args[ARG_threshold].u_bool,
args[ARG_offset].u_int, args[ARG_invert].u_bool, mask);
fb_alloc_free_till_mark(); fb_alloc_free_till_mark();
return args[0]; return pos_args[0];
} }
static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_morph_obj, 3, py_image_morph); static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_morph_obj, 3, py_image_morph);
#endif //IMLIB_ENABLE_MORPH #endif // IMLIB_ENABLE_MORPH
#ifdef IMLIB_ENABLE_GAUSSIAN #ifdef IMLIB_ENABLE_GAUSSIAN
static mp_obj_t py_image_gaussian(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { static mp_obj_t py_image_gaussian(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
image_t *arg_img = enum { ARG_unsharp, ARG_mul, ARG_add, ARG_threshold, ARG_offset, ARG_invert, ARG_mask };
py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); static const mp_arg_t allowed_args[] = {
int arg_ksize = { MP_QSTR_unsharp, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false } },
py_helper_arg_to_ksize(args[1]); { MP_QSTR_mul, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE } },
{ MP_QSTR_add, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE } },
{ MP_QSTR_threshold, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false } },
{ MP_QSTR_offset, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0 } },
{ MP_QSTR_invert, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false } },
{ MP_QSTR_mask, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} },
};
int k_2 = arg_ksize * 2; // Parse args.
int n = k_2 + 1; image_t *image = py_helper_arg_to_image(pos_args[0], ARG_IMAGE_MUTABLE);
int ksize = py_helper_arg_to_ksize(pos_args[1]);
int n = (ksize * 2) + 1;
if (n > 31) {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Kernel size too large!"));
}
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
fb_alloc_mark(); fb_alloc_mark();
int *pascal = fb_alloc(n * sizeof(int), FB_ALLOC_NO_HINT); int pascal[n];
pascal[0] = 1; pascal[0] = 1;
for (int i = 0; i < k_2; i++) { for (int i = 0; i < (ksize * 2); i++) {
// Compute a row of pascal's triangle. // Compute a row of pascal's triangle.
pascal[i + 1] = (pascal[i] * (k_2 - i)) / (i + 1); pascal[i + 1] = (pascal[i] * ((ksize * 2) - i)) / (i + 1);
} }
int *arg_krn = fb_alloc(n * n * sizeof(int), FB_ALLOC_NO_HINT); int krn[n * n];
int arg_m = 0; int sum = 0;
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) { for (int j = 0; j < n; j++) {
int temp = pascal[i] * pascal[j]; int temp = pascal[i] * pascal[j];
arg_krn[(i * n) + j] = temp; krn[(i * n) + j] = temp;
arg_m += temp; sum += temp;
} }
} }
if (py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_unsharp), false)) { if (args[ARG_unsharp].u_bool) {
arg_krn[((n / 2) * n) + (n / 2)] -= arg_m * 2; krn[(n * n) / 2] -= sum * 2;
arg_m = -arg_m; sum = -sum;
} }
float arg_mul = image_t *mask = NULL;
py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mul), 1.0f / arg_m); if (args[ARG_mask].u_obj != mp_const_none) {
float arg_add = mask = py_helper_arg_to_image(args[ARG_mask].u_obj, ARG_IMAGE_MUTABLE | ARG_IMAGE_ALLOC);
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(n_args, args, 8, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL);
imlib_morph(arg_img, arg_ksize, arg_krn, arg_mul, arg_add, arg_threshold, arg_offset, arg_invert, arg_msk); float mul = py_helper_arg_to_float(args[ARG_mul].u_obj, 1.0f);
float add = py_helper_arg_to_float(args[ARG_add].u_obj, 0.0f);
imlib_morph(image, ksize, krn, mul / sum, add, args[ARG_threshold].u_bool,
args[ARG_offset].u_int, args[ARG_invert].u_bool, mask);
fb_alloc_free_till_mark(); fb_alloc_free_till_mark();
return args[0]; return pos_args[0];
} }
static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_gaussian_obj, 2, py_image_gaussian); static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_gaussian_obj, 2, py_image_gaussian);
#endif // IMLIB_ENABLE_GAUSSIAN #endif // IMLIB_ENABLE_GAUSSIAN
#ifdef IMLIB_ENABLE_LAPLACIAN #ifdef IMLIB_ENABLE_LAPLACIAN
static mp_obj_t py_image_laplacian(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { static mp_obj_t py_image_laplacian(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
image_t *arg_img = enum { ARG_sharpen, ARG_mul, ARG_add, ARG_threshold, ARG_offset, ARG_invert, ARG_mask };
py_helper_arg_to_image(args[0], ARG_IMAGE_MUTABLE); static const mp_arg_t allowed_args[] = {
int arg_ksize = { MP_QSTR_sharpen, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false } },
py_helper_arg_to_ksize(args[1]); { MP_QSTR_mul, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE } },
{ MP_QSTR_add, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE } },
{ MP_QSTR_threshold, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false } },
{ MP_QSTR_offset, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0 } },
{ MP_QSTR_invert, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false } },
{ MP_QSTR_mask, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} },
};
int k_2 = arg_ksize * 2; // Parse args.
int n = k_2 + 1; image_t *image = py_helper_arg_to_image(pos_args[0], ARG_IMAGE_MUTABLE);
int ksize = py_helper_arg_to_ksize(pos_args[1]);
int n = (ksize * 2) + 1;
if (n > 31) {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Kernel size too large!"));
}
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
fb_alloc_mark(); fb_alloc_mark();
int *pascal = fb_alloc(n * sizeof(int), FB_ALLOC_NO_HINT); int pascal[n];
pascal[0] = 1; pascal[0] = 1;
for (int i = 0; i < k_2; i++) { for (int i = 0; i < (ksize * 2); i++) {
// Compute a row of pascal's triangle. // Compute a row of pascal's triangle.
pascal[i + 1] = (pascal[i] * (k_2 - i)) / (i + 1); pascal[i + 1] = (pascal[i] * ((ksize * 2) - i)) / (i + 1);
} }
int *arg_krn = fb_alloc(n * n * sizeof(int), FB_ALLOC_NO_HINT); int krn[n * n];
int arg_m = 0; int sum = 0;
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) { for (int j = 0; j < n; j++) {
int temp = pascal[i] * pascal[j]; int temp = pascal[i] * pascal[j];
arg_krn[(i * n) + j] = -temp; krn[(i * n) + j] = -temp;
arg_m += temp; sum += temp;
} }
} }
arg_krn[((n / 2) * n) + (n / 2)] += arg_m; krn[(n * n) / 2] += sum;
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)) { if (args[ARG_sharpen].u_bool) {
arg_krn[((n / 2) * n) + (n / 2)] += arg_m; krn[(n * n) / 2] += sum;
} }
float arg_mul = image_t *mask = NULL;
py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mul), 1.0f / arg_m); if (args[ARG_mask].u_obj != mp_const_none) {
float arg_add = mask = py_helper_arg_to_image(args[ARG_mask].u_obj, ARG_IMAGE_MUTABLE | ARG_IMAGE_ALLOC);
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(n_args, args, 8, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL);
imlib_morph(arg_img, arg_ksize, arg_krn, arg_mul, arg_add, arg_threshold, arg_offset, arg_invert, arg_msk); float mul = py_helper_arg_to_float(args[ARG_mul].u_obj, 1.0f);
float add = py_helper_arg_to_float(args[ARG_add].u_obj, 0.0f);
imlib_morph(image, ksize, krn, mul / sum, add, args[ARG_threshold].u_bool,
args[ARG_offset].u_int, args[ARG_invert].u_bool, mask);
fb_alloc_free_till_mark(); fb_alloc_free_till_mark();
return args[0]; return pos_args[0];
} }
static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_laplacian_obj, 2, py_image_laplacian); static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_laplacian_obj, 2, py_image_laplacian);
#endif // IMLIB_ENABLE_LAPLACIAN #endif // IMLIB_ENABLE_LAPLACIAN