@@ -61,13 +61,16 @@ def from_pixelformat(cls, fmt: PixelFormat):
6161 else :
6262 bpp = int (name [5 :]) # Direct BPP value
6363
64- return cls (bayer_pattern = BayerPattern .from_pattern (pattern ),
65- bits_per_pixel = bpp ,
66- is_packed = is_packed )
64+ return cls (
65+ bayer_pattern = BayerPattern .from_pattern (pattern ),
66+ bits_per_pixel = bpp ,
67+ is_packed = is_packed ,
68+ )
6769
6870
69- def prepare_packed_raw (data : npt .NDArray [np .uint8 ], width : int , height : int ,
70- bits_per_pixel : int , bytesperline : int ) -> npt .NDArray [np .uint16 ]:
71+ def prepare_packed_raw (
72+ data : npt .NDArray [np .uint8 ], width : int , height : int , bits_per_pixel : int , bytesperline : int
73+ ) -> npt .NDArray [np .uint16 ]:
7174 assert bits_per_pixel in [10 , 12 ], 'Only 10 and 12 bpp are supported'
7275
7376 # Reshape into rows if bytesperline is provided
@@ -107,9 +110,9 @@ def _unpack_12bit(arr16: npt.NDArray[np.uint16]) -> npt.NDArray[np.uint16]:
107110 return np .delete (arr16_shifted , np .s_ [2 ::3 ], 1 )
108111
109112
110- def prepare_unpacked_raw (data : npt . NDArray [ np . uint8 ], width : int , height : int ,
111- bits_per_pixel : int , bytesperline : int ) -> npt . NDArray [ np . uint16 ]:
112-
113+ def prepare_unpacked_raw (
114+ data : npt . NDArray [ np . uint8 ], width : int , height : int , bits_per_pixel : int , bytesperline : int
115+ ) -> npt . NDArray [ np . uint16 ]:
113116 # Reshape into rows if bytesperline is provided
114117 if bytesperline :
115118 data = data .reshape ((len (data ) // bytesperline , bytesperline ))
@@ -151,15 +154,17 @@ def mosaic(data: npt.NDArray[np.uint16], pattern: BayerPattern) -> npt.NDArray[n
151154 # Create an empty RGB image with 3 channels
152155 rgb = np .zeros (data .shape + (3 ,), dtype = data .dtype )
153156
154- rgb [pattern .r0 [1 ]:: 2 , pattern .r0 [0 ]:: 2 , 0 ] = data [pattern .r0 [1 ]:: 2 , pattern .r0 [0 ]:: 2 ]
155- rgb [pattern .g0 [1 ]:: 2 , pattern .g0 [0 ]:: 2 , 1 ] = data [pattern .g0 [1 ]:: 2 , pattern .g0 [0 ]:: 2 ]
156- rgb [pattern .g1 [1 ]:: 2 , pattern .g1 [0 ]:: 2 , 1 ] = data [pattern .g1 [1 ]:: 2 , pattern .g1 [0 ]:: 2 ]
157- rgb [pattern .b0 [1 ]:: 2 , pattern .b0 [0 ]:: 2 , 2 ] = data [pattern .b0 [1 ]:: 2 , pattern .b0 [0 ]:: 2 ]
157+ rgb [pattern .r0 [1 ] :: 2 , pattern .r0 [0 ] :: 2 , 0 ] = data [pattern .r0 [1 ] :: 2 , pattern .r0 [0 ] :: 2 ]
158+ rgb [pattern .g0 [1 ] :: 2 , pattern .g0 [0 ] :: 2 , 1 ] = data [pattern .g0 [1 ] :: 2 , pattern .g0 [0 ] :: 2 ]
159+ rgb [pattern .g1 [1 ] :: 2 , pattern .g1 [0 ] :: 2 , 1 ] = data [pattern .g1 [1 ] :: 2 , pattern .g1 [0 ] :: 2 ]
160+ rgb [pattern .b0 [1 ] :: 2 , pattern .b0 [0 ] :: 2 , 2 ] = data [pattern .b0 [1 ] :: 2 , pattern .b0 [0 ] :: 2 ]
158161
159162 return rgb
160163
161164
162- def demosaic (data : npt .NDArray [np .uint16 ], pattern : BayerPattern , options : None | dict = None ) -> npt .NDArray [np .uint16 ]:
165+ def demosaic (
166+ data : npt .NDArray [np .uint16 ], pattern : BayerPattern , options : None | dict = None
167+ ) -> npt .NDArray [np .uint16 ]:
163168 # Select demosaic algorithm based on options
164169 method = options .get ('demosaic_method' , '3x3' ) if options else '3x3'
165170 h , w = data .shape
@@ -174,7 +179,9 @@ def demosaic(data: npt.NDArray[np.uint16], pattern: BayerPattern, options: None
174179 raise ValueError (f'Unknown demosaic method: { method } ' )
175180
176181
177- def _demosaic_3x3_window (data : npt .NDArray [np .uint16 ], pattern : BayerPattern , h : int , w : int ) -> npt .NDArray [np .uint16 ]:
182+ def _demosaic_3x3_window (
183+ data : npt .NDArray [np .uint16 ], pattern : BayerPattern , h : int , w : int
184+ ) -> npt .NDArray [np .uint16 ]:
178185 """3x3 window demosaic algorithm using pure numpy"""
179186 # Separate the components from the Bayer data to RGB planes
180187 rgb = np .zeros ((h , w , 3 ), dtype = data .dtype )
@@ -204,22 +211,31 @@ def _demosaic_3x3_window(data: npt.NDArray[np.uint16], pattern: BayerPattern, h:
204211 borders = (window [0 ] - 1 , window [1 ] - 1 )
205212 border = (borders [0 ] // 2 , borders [1 ] // 2 )
206213
207- rgb = np .pad (rgb , [
208- (border [0 ], border [0 ]),
209- (border [1 ], border [1 ]),
210- (0 , 0 ),
211- ], 'constant' )
212- bayer = np .pad (bayer , [
213- (border [0 ], border [0 ]),
214- (border [1 ], border [1 ]),
215- (0 , 0 ),
216- ], 'constant' )
214+ rgb = np .pad (
215+ rgb ,
216+ [
217+ (border [0 ], border [0 ]),
218+ (border [1 ], border [1 ]),
219+ (0 , 0 ),
220+ ],
221+ 'constant' ,
222+ )
223+ bayer = np .pad (
224+ bayer ,
225+ [
226+ (border [0 ], border [0 ]),
227+ (border [1 ], border [1 ]),
228+ (0 , 0 ),
229+ ],
230+ 'constant' ,
231+ )
217232
218233 return _compute_demosaic_planes (rgb , bayer , h , w )
219234
220235
221- def _compute_demosaic_planes (rgb : npt .NDArray [np .uint16 ], bayer : npt .NDArray [np .uint8 ],
222- output_height : int , output_width : int ) -> npt .NDArray [np .uint16 ]:
236+ def _compute_demosaic_planes (
237+ rgb : npt .NDArray [np .uint16 ], bayer : npt .NDArray [np .uint8 ], output_height : int , output_width : int
238+ ) -> npt .NDArray [np .uint16 ]:
223239 # For each plane in the RGB data, we calculate the 3x3 window sum
224240 # and divide it with the weighted average. This version uses direct
225241 # computation of the sum, instead of using numpy's as_strided()
@@ -232,32 +248,51 @@ def _compute_demosaic_planes(rgb: npt.NDArray[np.uint16], bayer: npt.NDArray[np.
232248 b = bayer [..., plane ]
233249
234250 # Direct computation of 3x3 window sum
235- psum = (p [:- 2 , :- 2 ] + p [:- 2 , 1 :- 1 ] + p [:- 2 , 2 :] +
236- p [1 :- 1 , :- 2 ] + p [1 :- 1 , 1 :- 1 ] + p [1 :- 1 , 2 :] +
237- p [2 :, :- 2 ] + p [2 :, 1 :- 1 ] + p [2 :, 2 :])
238-
239- bsum = (b [:- 2 , :- 2 ] + b [:- 2 , 1 :- 1 ] + b [:- 2 , 2 :] +
240- b [1 :- 1 , :- 2 ] + b [1 :- 1 , 1 :- 1 ] + b [1 :- 1 , 2 :] +
241- b [2 :, :- 2 ] + b [2 :, 1 :- 1 ] + b [2 :, 2 :])
251+ psum = (
252+ p [:- 2 , :- 2 ]
253+ + p [:- 2 , 1 :- 1 ]
254+ + p [:- 2 , 2 :]
255+ + p [1 :- 1 , :- 2 ]
256+ + p [1 :- 1 , 1 :- 1 ]
257+ + p [1 :- 1 , 2 :]
258+ + p [2 :, :- 2 ]
259+ + p [2 :, 1 :- 1 ]
260+ + p [2 :, 2 :]
261+ )
262+
263+ bsum = (
264+ b [:- 2 , :- 2 ]
265+ + b [:- 2 , 1 :- 1 ]
266+ + b [:- 2 , 2 :]
267+ + b [1 :- 1 , :- 2 ]
268+ + b [1 :- 1 , 1 :- 1 ]
269+ + b [1 :- 1 , 2 :]
270+ + b [2 :, :- 2 ]
271+ + b [2 :, 1 :- 1 ]
272+ + b [2 :, 2 :]
273+ )
242274
243275 output [..., plane ] = psum // bsum
244276
245277 return output
246278
247279
248- def raw_to_bgr888 (data : npt .NDArray [np .uint8 ], width : int , height : int ,
249- bytesperline : int , fmt : PixelFormat ,
250- options : None | dict = None ) -> npt .NDArray [np .uint8 ]:
280+ def raw_to_bgr888 (
281+ data : npt .NDArray [np .uint8 ],
282+ width : int ,
283+ height : int ,
284+ bytesperline : int ,
285+ fmt : PixelFormat ,
286+ options : None | dict = None ,
287+ ) -> npt .NDArray [np .uint8 ]:
251288 # Parse the format
252289 raw_fmt = RawFormat .from_pixelformat (fmt )
253290
254291 # Prepare the raw data into a common 16-bit format
255292 if raw_fmt .is_packed :
256- arr16 = prepare_packed_raw (data , width , height , raw_fmt .bits_per_pixel ,
257- bytesperline )
293+ arr16 = prepare_packed_raw (data , width , height , raw_fmt .bits_per_pixel , bytesperline )
258294 else :
259- arr16 = prepare_unpacked_raw (data , width , height , raw_fmt .bits_per_pixel ,
260- bytesperline )
295+ arr16 = prepare_unpacked_raw (data , width , height , raw_fmt .bits_per_pixel , bytesperline )
261296
262297 # Perform demosaic
263298 rgb = demosaic (arr16 , raw_fmt .bayer_pattern , options )
0 commit comments