Skip to content

Commit 0c36c15

Browse files
committed
Remove morph9, we're tight on flash space as it is
.. and no specific use case for morph9 is known that can't be done with mix+morph. Saves ~1800 bytes on Memento
1 parent 42a822d commit 0c36c15

File tree

4 files changed

+0
-654
lines changed

4 files changed

+0
-654
lines changed

shared-bindings/bitmapfilter/__init__.c

Lines changed: 0 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -148,154 +148,14 @@ STATIC mp_obj_t bitmapfilter_morph(size_t n_args, const mp_obj_t *pos_args, mp_m
148148
return args[ARG_bitmap].u_obj;
149149
}
150150
MP_DEFINE_CONST_FUN_OBJ_KW(bitmapfilter_morph_obj, 0, bitmapfilter_morph);
151-
152-
//|
153-
//| def morph9(
154-
//| bitmap: displayio.Bitmap,
155-
//| weights: Sequence[int],
156-
//| mul: Sequence[float] | None,
157-
//| add: Sequence[float] | None,
158-
//| mask: displayio.Bitmap | None = None,
159-
//| threshold=False,
160-
//| offset: int = 0,
161-
//| invert: bool = False,
162-
//| ) -> displayio.Bitmap:
163-
//| """Convolve an image with a kernel
164-
//|
165-
//| This is like a combination of 9 calls to morph plus one call to mix. It's
166-
//| so complicated and hard to explain that it must be good for something.
167-
//|
168-
//| The ``bitmap``, which must be in RGB565_SWAPPED format, is modified
169-
//| according to the ``weights``. Then a scaling factor ``m`` and an
170-
//| offset factor ``b`` are applied.
171-
//|
172-
//| The ``weights`` must be a tuple of integers. The length of the tuple
173-
//| must be 9 times the square of an odd number, such as 81 or 225. The weights
174-
//| are taken in groups of 9, with the first 3 giving the proportion of each of
175-
//| R, G, and B that are mixed into the output R, the next three the
176-
//| proportions mixed into the output G, and the last 3 the proportions that
177-
//| are mixed into the output blue.
178-
//|
179-
//| ``mul`` is a sequence of 3 numbers to multiply the convolution pixel
180-
//| results by. When not set it defaults to a value that will prevent scaling
181-
//| in the convolution output.
182-
//|
183-
//| ``add`` is a sequence of 3 numbers giving a value to add to each
184-
//| convolution pixel result. If unspecified or None, 0 is used for all 3 channels.
185-
//|
186-
//| ``mul`` basically allows you to do a global contrast adjustment and
187-
//| add allows you to do a global brightness adjustment. Pixels that go
188-
//| outside of the image mins and maxes for color channels will be
189-
//| clipped.
190-
//|
191-
//| If you’d like to adaptive threshold the image on the output of the
192-
//| filter you can pass ``threshold=True`` which will enable adaptive
193-
//| thresholding of the image which sets pixels to one or zero based on a
194-
//| pixel’s brightness in relation to the brightness of the kernel of pixels
195-
//| around them. A negative ``offset`` value sets more pixels to 1 as you make
196-
//| it more negative while a positive value only sets the sharpest contrast
197-
//| changes to 1. Set ``invert`` to invert the binary image resulting output.
198-
//|
199-
//| ``mask`` is another image to use as a pixel level mask for the operation.
200-
//| The mask should be an image the same size as the image being operated on.
201-
//| Only pixels set to a non-zero value in the mask are modified.
202-
//|
203-
//| .. code-block:: python
204-
//|
205-
//| kernel_gauss_3 = [
206-
//| 1, 2, 1,
207-
//| 2, 4, 2,
208-
//| 1, 2, 1]
209-
//|
210-
//| def blur(bitmap):
211-
//| \"""Blur the bitmap with a 3x3 gaussian kernel\"""
212-
//| bitmapfilter.morph(bitmap, kernel_gauss_3, 1/sum(kernel_gauss_3))
213-
//| """
214-
//|
215-
216151
static mp_obj_t subscr(mp_obj_t o, int i) {
217152
return mp_obj_subscr(o, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL);
218153
}
219154

220-
static mp_obj_t subscr_maybe(mp_obj_t o, int i) {
221-
return o == mp_const_none ? o : subscr(o, i);
222-
}
223-
224155
static mp_float_t float_subscr(mp_obj_t o, int i) {
225156
return mp_obj_get_float(subscr(o, i));
226157
}
227158

228-
STATIC mp_float_t float_subscr_maybe(mp_obj_t seq_maybe, int i, mp_float_t defval) {
229-
if (seq_maybe == mp_const_none) {
230-
return defval;
231-
}
232-
return float_subscr(seq_maybe, i);
233-
}
234-
235-
STATIC mp_obj_t bitmapfilter_morph9(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
236-
enum { ARG_bitmap, ARG_weights, ARG_mul, ARG_add, ARG_threshold, ARG_offset, ARG_invert, ARG_mask };
237-
static const mp_arg_t allowed_args[] = {
238-
{ MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } },
239-
{ MP_QSTR_weights, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } },
240-
{ MP_QSTR_mul, MP_ARG_OBJ, { .u_obj = MP_ROM_NONE } },
241-
{ MP_QSTR_add, MP_ARG_OBJ, { .u_obj = MP_ROM_NONE } },
242-
{ MP_QSTR_threshold, MP_ARG_BOOL, { .u_bool = false } },
243-
{ MP_QSTR_offset, MP_ARG_INT, { .u_int = 0 } },
244-
{ MP_QSTR_invert, MP_ARG_BOOL, { .u_bool = false } },
245-
{ MP_QSTR_mask, MP_ARG_OBJ, { .u_obj = MP_ROM_NONE } },
246-
};
247-
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
248-
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
249-
250-
mp_arg_validate_type(args[ARG_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_bitmap);
251-
displayio_bitmap_t *bitmap = args[ARG_bitmap].u_obj;
252-
253-
displayio_bitmap_t *mask = NULL; // the mask bitmap
254-
if (args[ARG_mask].u_obj != mp_const_none) {
255-
mp_arg_validate_type(args[ARG_mask].u_obj, &displayio_bitmap_type, MP_QSTR_mask);
256-
mask = MP_OBJ_TO_PTR(args[ARG_mask].u_obj);
257-
}
258-
259-
mp_float_t b[3] = {
260-
float_subscr_maybe(args[ARG_add].u_obj, 0, 0),
261-
float_subscr_maybe(args[ARG_add].u_obj, 1, 0),
262-
float_subscr_maybe(args[ARG_add].u_obj, 2, 0),
263-
};
264-
265-
mp_obj_t weights = args[ARG_weights].u_obj;
266-
mp_obj_t obj_len = mp_obj_len(weights);
267-
if (obj_len == MP_OBJ_NULL || !mp_obj_is_small_int(obj_len)) {
268-
mp_raise_ValueError_varg(MP_ERROR_TEXT("%q must be of type %q, not %q"), MP_QSTR_weights, MP_QSTR_Sequence, mp_obj_get_type(weights)->name);
269-
}
270-
271-
size_t n_weights = MP_OBJ_SMALL_INT_VALUE(obj_len);
272-
273-
size_t sq_n_weights = (int)MICROPY_FLOAT_C_FUN(sqrt)(n_weights / 9);
274-
if (sq_n_weights % 2 == 0 || sq_n_weights * sq_n_weights * 9 != n_weights) {
275-
mp_raise_ValueError(MP_ERROR_TEXT("weights must be a sequence with 9 times an odd square number of elements (usually 81 or 225)"));
276-
}
277-
278-
int iweights[n_weights];
279-
int weight_sum[3] = {0, 0, 0};
280-
for (size_t i = 0; i < n_weights; i++) {
281-
mp_int_t j = mp_obj_get_int(mp_obj_subscr(weights, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL));
282-
iweights[i] = j;
283-
int target_channel = (i / 3) % 3;
284-
weight_sum[target_channel] += j;
285-
}
286-
287-
mp_float_t m[3] = {
288-
get_m(subscr_maybe(args[ARG_mul].u_obj, 0), weight_sum[0]),
289-
get_m(subscr_maybe(args[ARG_mul].u_obj, 1), weight_sum[1]),
290-
get_m(subscr_maybe(args[ARG_mul].u_obj, 2), weight_sum[2])
291-
};
292-
293-
shared_module_bitmapfilter_morph9(bitmap, mask, sq_n_weights / 2, iweights, m, b,
294-
args[ARG_threshold].u_bool, args[ARG_offset].u_bool, args[ARG_invert].u_bool);
295-
return args[ARG_bitmap].u_obj;
296-
}
297-
MP_DEFINE_CONST_FUN_OBJ_KW(bitmapfilter_morph9_obj, 0, bitmapfilter_morph9);
298-
299159
//| def mix(
300160
//| bitmap: displayio.Bitmap, weights: Sequence[int], mask: displayio.Bitmap | None = None
301161
//| ) -> displayio.Bitmap:
@@ -557,7 +417,6 @@ MP_DEFINE_CONST_FUN_OBJ_KW(bitmapfilter_false_color_obj, 0, bitmapfilter_false_c
557417
STATIC const mp_rom_map_elem_t bitmapfilter_module_globals_table[] = {
558418
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bitmapfilter) },
559419
{ MP_ROM_QSTR(MP_QSTR_morph), MP_ROM_PTR(&bitmapfilter_morph_obj) },
560-
{ MP_ROM_QSTR(MP_QSTR_morph9), MP_ROM_PTR(&bitmapfilter_morph9_obj) },
561420
{ MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&bitmapfilter_mix_obj) },
562421
{ MP_ROM_QSTR(MP_QSTR_solarize), MP_ROM_PTR(&bitmapfilter_solarize_obj) },
563422
{ MP_ROM_QSTR(MP_QSTR_false_color), MP_ROM_PTR(&bitmapfilter_false_color_obj) },

shared-module/bitmapfilter/__init__.c

Lines changed: 0 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -177,151 +177,6 @@ STATIC uint16_t imlib_yuv_to_rgb(uint8_t y, int8_t u, int8_t v) {
177177
#define COLOR_YUV_TO_RGB565(y, u, v) imlib_yuv_to_rgb((y), u, v)
178178

179179

180-
void shared_module_bitmapfilter_morph9(
181-
displayio_bitmap_t *bitmap,
182-
displayio_bitmap_t *mask,
183-
const int ksize,
184-
int krn[9 * (2 * ksize + 1) * (2 * ksize + 1)], // Note: modifies krn[]
185-
const mp_float_t m[3],
186-
const mp_float_t b[3],
187-
bool threshold,
188-
int offset,
189-
bool invert) {
190-
191-
int brows = ksize + 1;
192-
193-
int arrsize = (ksize * 2 + 1) * (ksize * 2 + 1) * 9;
194-
195-
for (int i = 0; i < arrsize; i++) {
196-
int source_channel = i % 3;
197-
int target_channel = (i / 3) % 3;
198-
int source_is_green = (source_channel == 1);
199-
int target_is_green = (target_channel == 1);
200-
201-
int scale = (source_is_green == target_is_green) ? 65536
202-
: source_is_green ? 32768 : 131072;
203-
204-
krn[i] = (int)MICROPY_FLOAT_C_FUN(round)(scale * m[target_channel] * krn[i]);
205-
}
206-
207-
const int32_t b_int[3] = {
208-
(int32_t)MICROPY_FLOAT_C_FUN(round)(65536 * COLOR_R5_MAX * b[0]),
209-
(int32_t)MICROPY_FLOAT_C_FUN(round)(65536 * COLOR_G6_MAX * b[1]),
210-
(int32_t)MICROPY_FLOAT_C_FUN(round)(65536 * COLOR_B5_MAX * b[2])
211-
};
212-
213-
check_matching_details(bitmap, bitmap);
214-
215-
switch (bitmap->bits_per_value) {
216-
default:
217-
mp_raise_ValueError(MP_ERROR_TEXT("unsupported bitmap depth"));
218-
case 16: {
219-
displayio_bitmap_t buf;
220-
scratch_bitmap16(&buf, brows, bitmap->width);
221-
222-
for (int y = 0, yy = bitmap->height; y < yy; y++) {
223-
uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(bitmap, y);
224-
uint16_t *buf_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows));
225-
226-
for (int x = 0, xx = bitmap->width; x < xx; x++) {
227-
if (mask && common_hal_displayio_bitmap_get_pixel(mask, x, y)) {
228-
IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x));
229-
continue; // Short circuit.
230-
231-
}
232-
int32_t r_acc = b_int[0], g_acc = b_int[1], b_acc = b_int[2], ptr = 0;
233-
234-
if (x >= ksize && x < bitmap->width - ksize && y >= ksize && y < bitmap->height - ksize) {
235-
for (int j = -ksize; j <= ksize; j++) {
236-
uint16_t *k_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(bitmap, y + j);
237-
for (int k = -ksize; k <= ksize; k++) {
238-
int pixel = IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr, x + k);
239-
int r = COLOR_RGB565_TO_R5(pixel);
240-
int g = COLOR_RGB565_TO_G6(pixel);
241-
int b = COLOR_RGB565_TO_B5(pixel);
242-
r_acc += krn[ptr++] * r;
243-
r_acc += krn[ptr++] * g;
244-
r_acc += krn[ptr++] * b;
245-
g_acc += krn[ptr++] * r;
246-
g_acc += krn[ptr++] * g;
247-
g_acc += krn[ptr++] * b;
248-
b_acc += krn[ptr++] * r;
249-
b_acc += krn[ptr++] * g;
250-
b_acc += krn[ptr++] * b;
251-
}
252-
}
253-
} else {
254-
for (int j = -ksize; j <= ksize; j++) {
255-
uint16_t *k_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(bitmap,
256-
IM_MIN(IM_MAX(y + j, 0), (bitmap->height - 1)));
257-
for (int k = -ksize; k <= ksize; k++) {
258-
int pixel = IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr,
259-
IM_MIN(IM_MAX(x + k, 0), (bitmap->width - 1)));
260-
int r = COLOR_RGB565_TO_R5(pixel);
261-
int g = COLOR_RGB565_TO_G6(pixel);
262-
int b = COLOR_RGB565_TO_B5(pixel);
263-
r_acc += krn[ptr++] * r;
264-
r_acc += krn[ptr++] * g;
265-
r_acc += krn[ptr++] * b;
266-
g_acc += krn[ptr++] * r;
267-
g_acc += krn[ptr++] * g;
268-
g_acc += krn[ptr++] * b;
269-
b_acc += krn[ptr++] * r;
270-
b_acc += krn[ptr++] * g;
271-
b_acc += krn[ptr++] * b;
272-
}
273-
}
274-
}
275-
r_acc >>= 16;
276-
if (r_acc > COLOR_R5_MAX) {
277-
r_acc = COLOR_R5_MAX;
278-
} else if (r_acc < 0) {
279-
r_acc = 0;
280-
}
281-
g_acc >>= 16;
282-
if (g_acc > COLOR_G6_MAX) {
283-
g_acc = COLOR_G6_MAX;
284-
} else if (g_acc < 0) {
285-
g_acc = 0;
286-
}
287-
b_acc >>= 16;
288-
if (b_acc > COLOR_B5_MAX) {
289-
b_acc = COLOR_B5_MAX;
290-
} else if (b_acc < 0) {
291-
b_acc = 0;
292-
}
293-
294-
int pixel = COLOR_R5_G6_B5_TO_RGB565(r_acc, g_acc, b_acc);
295-
296-
if (threshold) {
297-
if (((COLOR_RGB565_TO_Y(pixel) - offset) < COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x))) ^ invert) {
298-
pixel = COLOR_RGB565_BINARY_MAX;
299-
} else {
300-
pixel = COLOR_RGB565_BINARY_MIN;
301-
}
302-
}
303-
304-
IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, pixel);
305-
}
306-
307-
if (y >= ksize) { // Transfer buffer lines...
308-
memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(bitmap, (y - ksize)),
309-
IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
310-
IMAGE_RGB565_LINE_LEN_BYTES(bitmap));
311-
}
312-
}
313-
314-
// Copy any remaining lines from the buffer image...
315-
for (int y = IM_MAX(bitmap->height - ksize, 0), yy = bitmap->height; y < yy; y++) {
316-
memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(bitmap, y),
317-
IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)),
318-
IMAGE_RGB565_LINE_LEN_BYTES(bitmap));
319-
}
320-
321-
break;
322-
}
323-
}
324-
}
325180
void shared_module_bitmapfilter_morph(
326181
displayio_bitmap_t *bitmap,
327182
displayio_bitmap_t *mask,

tests/circuitpython/bitmapfilter_morph9.py

Lines changed: 0 additions & 29 deletions
This file was deleted.

0 commit comments

Comments
 (0)