@@ -148,154 +148,14 @@ STATIC mp_obj_t bitmapfilter_morph(size_t n_args, const mp_obj_t *pos_args, mp_m
148
148
return args [ARG_bitmap ].u_obj ;
149
149
}
150
150
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
-
216
151
static mp_obj_t subscr (mp_obj_t o , int i ) {
217
152
return mp_obj_subscr (o , MP_OBJ_NEW_SMALL_INT (i ), MP_OBJ_SENTINEL );
218
153
}
219
154
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
-
224
155
static mp_float_t float_subscr (mp_obj_t o , int i ) {
225
156
return mp_obj_get_float (subscr (o , i ));
226
157
}
227
158
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
-
299
159
//| def mix(
300
160
//| bitmap: displayio.Bitmap, weights: Sequence[int], mask: displayio.Bitmap | None = None
301
161
//| ) -> displayio.Bitmap:
@@ -557,7 +417,6 @@ MP_DEFINE_CONST_FUN_OBJ_KW(bitmapfilter_false_color_obj, 0, bitmapfilter_false_c
557
417
STATIC const mp_rom_map_elem_t bitmapfilter_module_globals_table [] = {
558
418
{ MP_ROM_QSTR (MP_QSTR___name__ ), MP_ROM_QSTR (MP_QSTR_bitmapfilter ) },
559
419
{ 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 ) },
561
420
{ MP_ROM_QSTR (MP_QSTR_mix ), MP_ROM_PTR (& bitmapfilter_mix_obj ) },
562
421
{ MP_ROM_QSTR (MP_QSTR_solarize ), MP_ROM_PTR (& bitmapfilter_solarize_obj ) },
563
422
{ MP_ROM_QSTR (MP_QSTR_false_color ), MP_ROM_PTR (& bitmapfilter_false_color_obj ) },
0 commit comments