Skip to content

Commit 415432e

Browse files
committed
Fix solarize to operate in YUV, add test
1 parent 790e890 commit 415432e

3 files changed

Lines changed: 142 additions & 6 deletions

File tree

shared-module/bitmapfilter/__init__.c

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ static void scratch_bitmap16(displayio_bitmap_t *buf, int rows, int cols) {
9494
((rowptr)[(x)] = __builtin_bswap16((val)))
9595
#define COLOR_R5_G6_B5_TO_RGB565(r, g, b) \
9696
(((r) << 11) | ((g) << 5) | (b))
97+
#define COLOR_R8_G8_B8_TO_RGB565(r8, g8, b8) ((((r8) & 0xF8) << 8) | (((g8) & 0xFC) << 3) | ((b8) >> 3))
9798

9899
#define COLOR_RGB565_TO_R5(pixel) (((pixel) >> 11) & 0x1F)
99100
#define COLOR_RGB565_TO_R8(pixel) \
@@ -121,6 +122,12 @@ static void scratch_bitmap16(displayio_bitmap_t *buf, int rows, int cols) {
121122
#define COLOR_R5_MAX (0x1F)
122123
#define COLOR_G6_MAX (0x3F)
123124
#define COLOR_B5_MAX (0x1F)
125+
#define COLOR_R8_MIN 0
126+
#define COLOR_R8_MAX 255
127+
#define COLOR_G8_MIN 0
128+
#define COLOR_G8_MAX 255
129+
#define COLOR_B8_MIN 0
130+
#define COLOR_B8_MAX 255
124131

125132
#define COLOR_RGB565_BINARY_MAX (0xffff)
126133
#define COLOR_RGB565_BINARY_MIN (0x0000)
@@ -135,6 +142,40 @@ static void scratch_bitmap16(displayio_bitmap_t *buf, int rows, int cols) {
135142
COLOR_RGB888_TO_Y(r, g, b); \
136143
})
137144

145+
#define COLOR_RGB888_TO_U(r8, g8, b8) ((((r8) * -21) - ((g8) * 43) + ((b8) * 64)) >> 7) // -0.168736R - 0.331264G + 0.5B
146+
#define COLOR_RGB565_TO_U(rgb565) \
147+
({ \
148+
__typeof__ (rgb565) __rgb565 = (rgb565); \
149+
int r = COLOR_RGB565_TO_R8(__rgb565); \
150+
int g = COLOR_RGB565_TO_G8(__rgb565); \
151+
int b = COLOR_RGB565_TO_B8(__rgb565); \
152+
COLOR_RGB888_TO_U(r, g, b); \
153+
})
154+
155+
#define COLOR_RGB888_TO_V(r8, g8, b8) ((((r8) * 64) - ((g8) * 54) - ((b8) * 10)) >> 7) // 0.5R - 0.418688G - 0.081312B
156+
#define COLOR_RGB565_TO_V(rgb565) \
157+
({ \
158+
__typeof__ (rgb565) __rgb565 = (rgb565); \
159+
int r = COLOR_RGB565_TO_R8(__rgb565); \
160+
int g = COLOR_RGB565_TO_G8(__rgb565); \
161+
int b = COLOR_RGB565_TO_B8(__rgb565); \
162+
COLOR_RGB888_TO_V(r, g, b); \
163+
})
164+
165+
// https://en.wikipedia.org/wiki/YCbCr -> JPEG Conversion
166+
STATIC uint16_t imlib_yuv_to_rgb(uint8_t y, int8_t u, int8_t v) {
167+
uint32_t r = IM_MAX(IM_MIN(y + ((91881 * v) >> 16), COLOR_R8_MAX), COLOR_R8_MIN);
168+
uint32_t g = IM_MAX(IM_MIN(y - (((22554 * u) + (46802 * v)) >> 16), COLOR_G8_MAX), COLOR_G8_MIN);
169+
uint32_t b = IM_MAX(IM_MIN(y + ((116130 * u) >> 16), COLOR_B8_MAX), COLOR_B8_MIN);
170+
171+
return COLOR_R8_G8_B8_TO_RGB565(r, g, b);
172+
}
173+
174+
// CIRCUITPY-CHANGE (vs openmv): an offset is removed so that the Y value is the
175+
// same as from COLOR_RGB565_TO_Y.
176+
#define COLOR_YUV_TO_RGB565(y, u, v) imlib_yuv_to_rgb((y), u, v)
177+
178+
138179
void shared_module_bitmapfilter_morph(
139180
displayio_bitmap_t *bitmap,
140181
displayio_bitmap_t *mask,
@@ -333,12 +374,12 @@ void shared_module_bitmapfilter_solarize(
333374
continue; // Short circuit.
334375
}
335376
int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x);
336-
if (COLOR_RGB565_TO_Y(pixel) > threshold_i) {
337-
int r = COLOR_R5_MAX - COLOR_RGB565_TO_R5(pixel);
338-
int g = COLOR_G6_MAX - COLOR_RGB565_TO_G6(pixel);
339-
int b = COLOR_B5_MAX - COLOR_RGB565_TO_B5(pixel);
340-
341-
pixel = COLOR_R5_G6_B5_TO_RGB565(r, g, b);
377+
int y = COLOR_RGB565_TO_Y(pixel);
378+
if (y > threshold_i) {
379+
y = MIN(255, MAX(0, 2 * threshold_i - y));
380+
int u = COLOR_RGB565_TO_U(pixel);
381+
int v = COLOR_RGB565_TO_V(pixel);
382+
pixel = COLOR_YUV_TO_RGB565(y, u, v);
342383
IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, pixel);
343384
}
344385
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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+
7+
8+
def test_pattern():
9+
return decode_resource("testpattern", 2)
10+
11+
12+
def make_quadrant_bitmap():
13+
b = Bitmap(17, 17, 1)
14+
for i in range(b.height):
15+
for j in range(b.width):
16+
b[i, j] = (i < 8) ^ (j < 8)
17+
return b
18+
19+
20+
q = make_quadrant_bitmap()
21+
b = test_pattern()
22+
dump_bitmap_rgb_swapped(b)
23+
24+
sepia_weights = [0.393, 0.769, 0.189, 0.349, 0.686, 0.168, 0.272, 0.534, 0.131]
25+
26+
print("solarize (masked)")
27+
bitmapfilter.solarize(b, mask=q)
28+
dump_bitmap_rgb_swapped(b)

0 commit comments

Comments
 (0)