Skip to content

Commit 6d30ff5

Browse files
committed
Add false_color
1 parent e3a5e48 commit 6d30ff5

File tree

6 files changed

+225
-0
lines changed

6 files changed

+225
-0
lines changed

shared-bindings/bitmapfilter/__init__.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
#include "py/runtime.h"
3030
#include "shared-bindings/displayio/Bitmap.h"
31+
#include "shared-bindings/displayio/Palette.h"
3132
#include "shared-bindings/bitmapfilter/__init__.h"
3233

3334
//|
@@ -347,11 +348,54 @@ STATIC mp_obj_t bitmapfilter_lookup(size_t n_args, const mp_obj_t *pos_args, mp_
347348

348349
MP_DEFINE_CONST_FUN_OBJ_KW(bitmapfilter_lookup_obj, 0, bitmapfilter_lookup);
349350

351+
//| def false_color(
352+
//| bitmap: displayio.Bitmap,
353+
//| palette: displayio.Palette | Sequence[int],
354+
//| mask: displayio.Bitmap | None,
355+
//| ) -> displayio.Bitmap:
356+
//| """Convert the image to false color using the given palette
357+
//|
358+
//| The ``bitmap``, which must be in RGB565_SWAPPED format, is converted into false color:
359+
//|
360+
//| Each pixel is converted to a luminance (brightness/greyscale) value
361+
//| in the range 0..255, then the corresponding palette entry is looked up and
362+
//| stored in the bitmap.
363+
//| """
364+
//|
365+
STATIC mp_obj_t bitmapfilter_false_color(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
366+
enum { ARG_bitmap, ARG_palette, ARG_mask };
367+
static const mp_arg_t allowed_args[] = {
368+
{ MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } },
369+
{ MP_QSTR_palette, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } },
370+
{ MP_QSTR_mask, MP_ARG_OBJ, { .u_obj = MP_ROM_NONE } },
371+
};
372+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
373+
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
374+
375+
mp_arg_validate_type(args[ARG_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_bitmap);
376+
displayio_bitmap_t *bitmap = MP_OBJ_TO_PTR(args[ARG_bitmap].u_obj);
377+
378+
mp_arg_validate_type(args[ARG_palette].u_obj, &displayio_palette_type, MP_QSTR_palette);
379+
displayio_palette_t *palette = MP_OBJ_TO_PTR(args[ARG_palette].u_obj);
380+
mp_arg_validate_length(palette->color_count, 256, MP_QSTR_palette);
381+
382+
displayio_bitmap_t *mask = NULL;
383+
if (args[ARG_mask].u_obj != mp_const_none) {
384+
mp_arg_validate_type(args[ARG_mask].u_obj, &displayio_bitmap_type, MP_QSTR_mask);
385+
mask = MP_OBJ_TO_PTR(args[ARG_mask].u_obj);
386+
}
387+
388+
shared_module_bitmapfilter_false_color(bitmap, mask, palette->colors);
389+
return args[ARG_bitmap].u_obj;
390+
}
391+
392+
MP_DEFINE_CONST_FUN_OBJ_KW(bitmapfilter_false_color_obj, 0, bitmapfilter_false_color);
350393
STATIC const mp_rom_map_elem_t bitmapfilter_module_globals_table[] = {
351394
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bitmapfilter) },
352395
{ MP_ROM_QSTR(MP_QSTR_morph), MP_ROM_PTR(&bitmapfilter_morph_obj) },
353396
{ MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&bitmapfilter_mix_obj) },
354397
{ MP_ROM_QSTR(MP_QSTR_solarize), MP_ROM_PTR(&bitmapfilter_solarize_obj) },
398+
{ MP_ROM_QSTR(MP_QSTR_false_color), MP_ROM_PTR(&bitmapfilter_false_color_obj) },
355399
{ MP_ROM_QSTR(MP_QSTR_lookup), MP_ROM_PTR(&bitmapfilter_lookup_obj) },
356400
};
357401
STATIC MP_DEFINE_CONST_DICT(bitmapfilter_module_globals, bitmapfilter_module_globals_table);

shared-bindings/bitmapfilter/__init__.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,8 @@ void shared_module_bitmapfilter_lookup(
5757
displayio_bitmap_t *bitmap,
5858
displayio_bitmap_t *mask,
5959
const bitmapfilter_lookup_table_t *table);
60+
61+
void shared_module_bitmapfilter_false_color(
62+
displayio_bitmap_t *bitmap,
63+
displayio_bitmap_t *mask,
64+
_displayio_color_t palette[256]);

shared-module/bitmapfilter/__init__.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "py/runtime.h"
1414

1515
#include "shared-bindings/displayio/Bitmap.h"
16+
#include "shared-bindings/displayio/Palette.h"
1617
#include "shared-bindings/bitmapfilter/__init__.h"
1718
#include "shared-module/bitmapfilter/__init__.h"
1819

@@ -421,3 +422,37 @@ void shared_module_bitmapfilter_lookup(
421422
}
422423
}
423424
}
425+
426+
void shared_module_bitmapfilter_false_color(
427+
displayio_bitmap_t *bitmap,
428+
displayio_bitmap_t *mask,
429+
_displayio_color_t palette[256]) {
430+
431+
uint16_t table[256];
432+
for (int i = 0; i < 256; i++) {
433+
uint32_t rgb888 = palette[i].rgb888;
434+
int r = rgb888 >> 16;
435+
int g = (rgb888 >> 8) & 0xff;
436+
int b = rgb888 & 0xff;
437+
table[i] = COLOR_R8_G8_B8_TO_RGB565(r, g, b);
438+
}
439+
440+
switch (bitmap->bits_per_value) {
441+
default:
442+
mp_raise_ValueError(MP_ERROR_TEXT("unsupported bitmap depth"));
443+
case 16: {
444+
for (int y = 0, yy = bitmap->height; y < yy; y++) {
445+
uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(bitmap, y);
446+
for (int x = 0, xx = bitmap->width; x < xx; x++) {
447+
if (mask && common_hal_displayio_bitmap_get_pixel(mask, x, y)) {
448+
continue; // Short circuit.
449+
}
450+
int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x);
451+
int y = COLOR_RGB565_TO_Y(pixel);
452+
pixel = table[y];
453+
IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, pixel);
454+
}
455+
}
456+
}
457+
}
458+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from displayio import Bitmap
2+
import bitmapfilter
3+
import ulab
4+
from dump_bitmap import dump_bitmap_rgb_swapped
5+
from blinka_image import decode_resource
6+
from ironbow import ironbow_palette
7+
8+
9+
def test_pattern():
10+
return decode_resource("testpattern", 2)
11+
12+
13+
def make_quadrant_bitmap():
14+
b = Bitmap(17, 17, 1)
15+
for i in range(b.height):
16+
for j in range(b.width):
17+
b[i, j] = (i < 8) ^ (j < 8)
18+
return b
19+
20+
21+
q = make_quadrant_bitmap()
22+
b = test_pattern()
23+
dump_bitmap_rgb_swapped(b)
24+
25+
sepia_weights = [0.393, 0.769, 0.189, 0.349, 0.686, 0.168, 0.272, 0.534, 0.131]
26+
27+
print("ironbow (masked)")
28+
bitmapfilter.false_color(b, ironbow_palette, mask=q)
29+
dump_bitmap_rgb_swapped(b)

0 commit comments

Comments
 (0)