| | |
| | |
| | |
| | |
| | |
| | |
| | import PIL.Image |
| | import os |
| | os.environ["OPENCV_IO_ENABLE_OPENEXR"] = "1" |
| | import cv2 |
| | import numpy as np |
| | from src.utils.geometry import colmap_to_opencv_intrinsics, opencv_to_colmap_intrinsics |
| | try: |
| | lanczos = PIL.Image.Resampling.LANCZOS |
| | bicubic = PIL.Image.Resampling.BICUBIC |
| | except AttributeError: |
| | lanczos = PIL.Image.LANCZOS |
| | bicubic = PIL.Image.BICUBIC |
| |
|
| |
|
| | class ImageList: |
| | """ Convenience class to aply the same operation to a whole set of images. |
| | """ |
| |
|
| | def __init__(self, images): |
| | if not isinstance(images, (tuple, list, set)): |
| | images = [images] |
| | self.images = [] |
| | for image in images: |
| | if not isinstance(image, PIL.Image.Image): |
| | image = PIL.Image.fromarray(image) |
| | self.images.append(image) |
| |
|
| | def __len__(self): |
| | return len(self.images) |
| |
|
| | def to_pil(self): |
| | return tuple(self.images) if len(self.images) > 1 else self.images[0] |
| |
|
| | @property |
| | def size(self): |
| | sizes = [im.size for im in self.images] |
| | assert all(sizes[0] == s for s in sizes) |
| | return sizes[0] |
| |
|
| | def resize(self, *args, **kwargs): |
| | return ImageList(self._dispatch('resize', *args, **kwargs)) |
| |
|
| | def crop(self, *args, **kwargs): |
| | return ImageList(self._dispatch('crop', *args, **kwargs)) |
| |
|
| | def _dispatch(self, func, *args, **kwargs): |
| | return [getattr(im, func)(*args, **kwargs) for im in self.images] |
| |
|
| |
|
| | def rescale_image(image, camera_intrinsics, output_resolution, force=True): |
| | """ Jointly rescale a (image, depthmap) |
| | so that (out_width, out_height) >= output_res |
| | """ |
| | image = ImageList(image) |
| | input_resolution = np.array(image.size) |
| | output_resolution = np.array(output_resolution) |
| | |
| | assert output_resolution.shape == (2,) |
| | scale_final = max(output_resolution / image.size) + 1e-8 |
| | if scale_final >= 1 and not force: |
| | return (image.to_pil(), camera_intrinsics) |
| | output_resolution = np.floor(input_resolution * scale_final).astype(int) |
| |
|
| | |
| | image = image.resize(tuple(output_resolution), resample=lanczos if scale_final < 1 else bicubic) |
| |
|
| | |
| | camera_intrinsics = camera_matrix_of_crop( |
| | camera_intrinsics, input_resolution, output_resolution, scaling=scale_final) |
| |
|
| | return image.to_pil(), camera_intrinsics |
| |
|
| |
|
| | def camera_matrix_of_crop(input_camera_matrix, input_resolution, output_resolution, scaling=1, offset_factor=0.5, offset=None): |
| | |
| | margins = np.asarray(input_resolution) * scaling - output_resolution |
| | assert np.all(margins >= 0.0) |
| | if offset is None: |
| | offset = offset_factor * margins |
| |
|
| | |
| | output_camera_matrix_colmap = opencv_to_colmap_intrinsics(input_camera_matrix) |
| | output_camera_matrix_colmap[:2, :] *= scaling |
| | output_camera_matrix_colmap[:2, 2] -= offset |
| | output_camera_matrix = colmap_to_opencv_intrinsics(output_camera_matrix_colmap) |
| |
|
| | return output_camera_matrix |
| |
|
| |
|
| | def crop_image(image, camera_intrinsics, crop_bbox): |
| | """ |
| | Return a crop of the input view. |
| | """ |
| | image = ImageList(image) |
| | l, t, r, b = crop_bbox |
| |
|
| | image = image.crop((l, t, r, b)) |
| |
|
| | camera_intrinsics = camera_intrinsics.copy() |
| | camera_intrinsics[0, 2] -= l |
| | camera_intrinsics[1, 2] -= t |
| |
|
| | return image.to_pil(), camera_intrinsics |
| |
|
| |
|
| | def bbox_from_intrinsics_in_out(input_camera_matrix, output_camera_matrix, output_resolution): |
| | out_width, out_height = output_resolution |
| | l, t = np.int32(np.round(input_camera_matrix[:2, 2] - output_camera_matrix[:2, 2])) |
| | crop_bbox = (l, t, l + out_width, t + out_height) |
| | return crop_bbox |
| |
|
| | def rescale_image_depthmap(image, depthmap, camera_intrinsics, output_resolution, force=True): |
| | """ Jointly rescale a (image, depthmap) |
| | so that (out_width, out_height) >= output_res |
| | """ |
| | image = ImageList(image) |
| | input_resolution = np.array(image.size) |
| | output_resolution = np.array(output_resolution) |
| | if depthmap is not None: |
| | |
| | assert tuple(depthmap.shape[:2]) == image.size[::-1] |
| |
|
| | |
| | assert output_resolution.shape == (2,) |
| | scale_final = max(output_resolution / image.size) + 1e-8 |
| | if scale_final >= 1 and not force: |
| | return (image.to_pil(), depthmap, camera_intrinsics) |
| | output_resolution = np.floor(input_resolution * scale_final).astype(int) |
| |
|
| | |
| | |
| | image = image.resize(tuple(output_resolution), resample=lanczos if scale_final < 1 else bicubic) |
| | if depthmap is not None: |
| | depthmap = cv2.resize(depthmap, tuple(output_resolution), fx=scale_final, |
| | fy=scale_final, interpolation=cv2.INTER_NEAREST) |
| |
|
| | |
| | camera_intrinsics = camera_matrix_of_crop( |
| | camera_intrinsics, input_resolution, tuple(output_resolution), scaling=scale_final) |
| |
|
| | return image.to_pil(), depthmap, camera_intrinsics |
| |
|
| | def crop_image_depthmap(image, depthmap, camera_intrinsics, crop_bbox): |
| | """ |
| | Return a crop of the input view. |
| | """ |
| | image = ImageList(image) |
| | l, t, r, b = crop_bbox |
| |
|
| | image = image.crop((l, t, r, b)) |
| | depthmap = depthmap[t:b, l:r] |
| |
|
| | camera_intrinsics = camera_intrinsics.copy() |
| | camera_intrinsics[0, 2] -= l |
| | camera_intrinsics[1, 2] -= t |
| |
|
| | return image.to_pil(), depthmap, camera_intrinsics |