4
4
"""Routines for performing image manipulation"""
5
5
6
6
import struct
7
+ from adafruit_ticks import ticks_ms , ticks_diff
7
8
9
+ from micropython import const
8
10
import ulab .numpy as np
9
11
12
+ # Optionally enable reporting of time taken inside tagged functions
13
+ _DO_TIME_REPORT = const (0 )
14
+
15
+ if _DO_TIME_REPORT :
16
+
17
+ def _timereport (func ):
18
+ """Report time taken within the function"""
19
+ name = str (func ).split ()[1 ]
20
+
21
+ def inner (* args , ** kw ):
22
+ start = ticks_ms ()
23
+ try :
24
+ return func (* args , ** kw )
25
+ finally :
26
+ end = ticks_ms ()
27
+ duration = ticks_diff (end , start )
28
+ print (f"{ name } : { duration } ms" )
29
+
30
+ return inner
31
+
32
+ else :
33
+
34
+ def _timereport (func ):
35
+ """A do-nothing decorator for when timing report is not desired"""
36
+ return func
37
+
10
38
11
39
def _bytes_per_row (source_width : int ) -> int :
12
40
"""Internal function to determine bitmap bytes per row"""
@@ -83,11 +111,14 @@ def _array_cast(arr, dtype):
83
111
return np .frombuffer (arr , dtype = dtype ).reshape (arr .shape )
84
112
85
113
114
+ @_timereport
86
115
def bitmap_to_components_rgb565 (bitmap ):
87
116
"""Convert a RGB565_BYTESWAPPED image to int16 components in the [0,255] inclusive range
88
117
89
118
This requires higher memory than uint8, but allows more arithmetic on pixel values;
90
- converting back to bitmap clamps values to the appropriate range.
119
+ but values are masked (not clamped) back down to the 0-255 range, so while intermediate
120
+ values can be -32768..32767 the values passed into bitmap_from_components_inplace_rgb565
121
+ muts be 0..255
91
122
92
123
This only works on images whose width is a multiple of 2 pixels.
93
124
"""
@@ -100,17 +131,20 @@ def bitmap_to_components_rgb565(bitmap):
100
131
return r , g , b
101
132
102
133
134
+ @_timereport
103
135
def bitmap_from_components_inplace_rgb565 (
104
136
bitmap , r , g , b
105
137
): # pylint: disable=invalid-name
106
138
"""Update a bitmap in-place with new RGB values"""
107
139
dest = _bitmap_as_array (bitmap )
108
- r = _array_cast (np .maximum (np .minimum (r , 255 ), 0 ), np .uint16 )
109
- g = _array_cast (np .maximum (np .minimum (g , 255 ), 0 ), np .uint16 )
110
- b = _array_cast (np .maximum (np .minimum (b , 255 ), 0 ), np .uint16 )
111
- dest [:] = np .left_shift (r & 0xF8 , 8 )
112
- dest [:] |= np .left_shift (g & 0xFC , 3 )
113
- dest [:] |= np .right_shift (b , 3 )
140
+ r = _array_cast (r , np .uint16 )
141
+ g = _array_cast (g , np .uint16 )
142
+ b = _array_cast (b , np .uint16 )
143
+ dest [:] = (
144
+ np .left_shift (r & 0xF8 , 8 )
145
+ | np .left_shift (g & 0xFC , 3 )
146
+ | np .right_shift (b & 0xF8 , 3 )
147
+ )
114
148
dest .byteswap (inplace = True )
115
149
return bitmap
116
150
@@ -125,13 +159,10 @@ def buffer_from_components_rgb888(r, g, b):
125
159
r = _as_flat (r )
126
160
g = _as_flat (g )
127
161
b = _as_flat (b )
128
- r = np .maximum (np .minimum (r , 0x3F ), 0 )
129
- g = np .maximum (np .minimum (g , 0x3F ), 0 )
130
- b = np .maximum (np .minimum (b , 0x3F ), 0 )
131
162
result = np .zeros (3 * len (r ), dtype = np .uint8 )
132
- result [2 ::3 ] = r
133
- result [1 ::3 ] = g
134
- result [0 ::3 ] = b
163
+ result [2 ::3 ] = r & 0xFF
164
+ result [1 ::3 ] = g & 0xFF
165
+ result [0 ::3 ] = b & 0xFF
135
166
return result
136
167
137
168
@@ -146,13 +177,15 @@ def symmetric_filter_inplace(data, coeffs, scale):
146
177
column_filter_inplace (data , coeffs , scale )
147
178
148
179
180
+ @_timereport
149
181
def row_filter_inplace (data , coeffs , scale ):
150
182
"""Apply a filter to data in rows, changing it in place"""
151
183
n_rows = data .shape [0 ]
152
184
for i in range (n_rows ):
153
185
data [i , :] = _np_convolve_same (data [i , :], coeffs ) // scale
154
186
155
187
188
+ @_timereport
156
189
def column_filter_inplace (data , coeffs , scale ):
157
190
"""Apply a filter to data in columns, changing it in place"""
158
191
n_cols = data .shape [1 ]
@@ -169,6 +202,7 @@ def bitmap_symmetric_filter_inplace(bitmap, coeffs, scale):
169
202
return bitmap_from_components_inplace_rgb565 (bitmap , r , g , b )
170
203
171
204
205
+ @_timereport
172
206
def bitmap_channel_filter3_inplace (
173
207
bitmap , r_func = lambda r , g , b : r , g_func = lambda r , g , b : g , b_func = lambda r , g , b : b
174
208
):
@@ -182,6 +216,7 @@ def bitmap_channel_filter3_inplace(
182
216
return bitmap_from_components_inplace_rgb565 (bitmap , r , g , b )
183
217
184
218
219
+ @_timereport
185
220
def bitmap_channel_filter1_inplace (
186
221
bitmap , r_func = lambda r : r , g_func = lambda g : g , b_func = lambda b : b
187
222
):
0 commit comments