168 def run(self, input_images: Iterable[tuple[NDArray, SkyWcs, Box2I]], healpix_id) -> Struct:
169 """Main execution method for generating HealPix tiles.
173 input_images : Iterable[tuple[NDArray, SkyWcs, Box2I]]
174 Iterable of tuples containing image data, WCS, and bounding box information.
176 The HealPix order 8 ID to process.
181 Output structure containing the processed HealPix order 8 tile.
182 This has been downsampled to 256x256 corresponding to a quarter of a healpix
188 target_wcs = makeHpxWcs(8, healpix_id, 12,
False)
193 output_array_hpx = np.zeros((4096, 4096, 3), dtype=np.float32)
194 output_array_hpx[:, :, :] = np.nan
196 self.log.info(
"Warping input exposures and populating hpx8 super tile.")
199 for input_image, in_wcs, in_box
in input_images:
200 tmp_image = ImageF(in_box)
201 in_image: NDArray = input_image
204 match in_image.dtype:
206 in_image = in_image.astype(np.float32) / 255.0
208 in_image = in_image.astype(np.float32) / 65535
210 in_image = in_image.astype(np.float32)
213 for channel
in ColorChannel:
215 existing = output_array_hpx[..., channel.value]
218 channel_array = in_image[..., channel.value]
219 tmp_image.array[:, :] = channel_array
222 warpped = self.
warper.warpImage(target_wcs, tmp_image, in_wcs, maxBBox=exp_bbox)
223 warpped_box_slices = warpped.getBBox().slices
226 are_warpped = np.isfinite(warpped.array)
228 pre_populated = np.isfinite(existing[warpped_box_slices])
229 new_info = np.logical_not(pre_populated)
230 new_and_warp = np.logical_and(new_info, are_warpped)
231 pre_and_warp = np.logical_and(pre_populated, are_warpped)
232 existing[warpped_box_slices][new_and_warp] = warpped.array[new_and_warp]
233 existing[warpped_box_slices][pre_and_warp] = (
234 warpped.array[pre_and_warp] + existing[warpped_box_slices][pre_and_warp]
238 output_array_hpx[np.isnan(output_array_hpx)] = 0
241 output_array_hpx = output_array_hpx[::-1, :, :]
254 for zoom, hips_level, factor
in zip((0, 2, 4, 8), (11, 10, 9, 8), (3, 2, 1, 0)):
255 self.log.info(
"Generating tiles for hxp level %d", hips_level)
258 binned_array = cv2.resize(output_array_hpx, (size, size), interpolation=cv2.INTER_LANCZOS4)
260 binned_array = output_array_hpx
270 tmp_pixels = np.array([[healpix_id]])
271 for _
in range(factor):
272 tmp_array = np.zeros(np.array(tmp_pixels.shape) * 2)
273 for ii
in range(tmp_pixels.shape[0]):
274 for jj
in range(tmp_pixels.shape[1]):
275 tmp_array_view = tmp_array[ii * 2 : ii * 2 + 2, jj * 2 : jj * 2 + 2]
276 tmp_range_set = RangeSet(int(tmp_pixels[ii, jj]))
277 tmp_array_view[:, :] = (
278 np.array([x
for x
in range(*tmp_range_set.scaled(4)[0])], dtype=int)[[0, 2, 1, 3]]
280 tmp_pixels = tmp_array
283 hpx_id_array = tmp_pixels
284 for i
in range(binned_array.shape[0] // 512):
285 for j
in range(binned_array.shape[1] // 512):
286 pixel_id = int(hpx_id_array[i, j])
287 sub_pixel = binned_array[i * 512 : i * 512 + 512, j * 512 : j * 512 + 512, :]
288 self.log.info(f
"writing sub_pixel {pixel_id}")
294 self.config.file_extension,
295 self.config.array_type,
300 zoomed = cv2.resize(output_array_hpx, (256, 256), interpolation=cv2.INTER_LANCZOS4)
302 return Struct(output_hpx=zoomed)
305 self, tract_patch: dict[int, Iterable[tuple[DeferredDatasetHandle, SkyWcs, Box2I]]], patch_grow: int
306 ) -> list[tuple[NDArray, SkyWcs, Box2I]]:
307 """Assemble all the patches in each tract into images.
309 This function takes in an input keyed by tract, with values
310 corresponding the patches in that tract that overlap the quatum's
311 healpix value. It assembles each of these into a single image such
312 that the return values is a list of images (and metadata) one element
313 for each input tract.
317 tract_patch : `dict` of `int` to `iterable` of `tuple` of
318 `DeferredDatasetHandle`, `SkyWcs` and `Box2I`
319 Input images and metadata organized into corresponding tracts.
321 Amount to grow patches by
325 output_list : `list` of `tuple` of `NDArray` `SkyWcs` and `Box2I`
326 List of assembled images and metadata, one element for each tract
331 for _, iterable
in tract_patch.items():
334 for _, _, bbox
in iterable:
335 new_box.include(bbox)
337 new_array = np.zeros((new_box.getHeight(), new_box.getWidth(), 3), dtype=np.float32)
338 for handle, skyWcs, box
in iterable:
341 localOrigin = box.getBegin() - new_box.getBegin()
343 x=int(np.floor(localOrigin.x)),
344 y=int(np.floor(localOrigin.y)),
348 x=int(np.floor(box.getWidth())),
349 y=int(np.floor(box.getHeight())),
351 tmpBox =
Box2I(localOrigin, localExtent)
355 mosaic_maker.add_to_image(new_array, image.array, tmp_new_box, tmpBox, reverse=
False)
357 boxes.append((new_array, skyWcs, new_box))
362 butlerQC: QuantumContext,
363 inputRefs: InputQuantizedConnection,
364 outputRefs: OutputQuantizedConnection,
367 healpix_id = butlerQC.quantum.dataId[
"healpix8"]
370 skymap: BaseSkyMap = butlerQC.get(inputRefs.skymap)
375 for input_image_ref
in inputRefs.input_images:
376 tract = input_image_ref.dataId[
"tract"]
377 patch = input_image_ref.dataId[
"patch"]
380 imageWcs = skymap[tract][patch].getWcs()
381 box = skymap[tract][patch].getOuterBBox()
382 patch_grow = skymap[tract][patch].getCellInnerDimensions().getX()
383 imageHandle = butlerQC.get(input_image_ref)
384 container = inputs_by_tract.setdefault(tract, list())
385 container.append((imageHandle, imageWcs, box))
389 outputs = self.
run(input_images, healpix_id)
390 butlerQC.put(outputs, outputRefs)