vprdb.core.database      
                
                        
                        
                        1# Copyright (c) 2023, Ivan Moskalenko, Anastasiia Kornilova 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14import numpy as np 15import open3d as o3d 16 17from dataclasses import dataclass 18from functools import cached_property 19from nptyping import Float, NDArray, Shape 20from pathlib import Path 21 22from vprdb.core.voxel_grid import VoxelGrid 23from vprdb.providers import ColorImageProvider, DepthImageProvider, PointCloudProvider 24 25 26@dataclass(frozen=True) 27class Database: 28 """ 29 Class for easy storage and processing of color images, depth images 30 and trajectory and their further use for the VPR task 31 """ 32 33 color_images: list[ColorImageProvider] 34 point_clouds: list[DepthImageProvider | PointCloudProvider] 35 trajectory: list[NDArray[Shape["4, 4"], Float]] 36 37 def __post_init__(self): 38 if not (len(self.trajectory) == len(self.point_clouds) == len(self.trajectory)): 39 raise ValueError( 40 "Trajectory, RGB images and point clouds should have equal length" 41 ) 42 43 @classmethod 44 def from_depth_images( 45 cls, 46 color_images_paths: list[Path], 47 depth_images_paths: list[Path], 48 depth_scale: int, 49 intrinsics: NDArray[Shape["3, 3"], Float], 50 trajectory: list[NDArray[Shape["4, 4"], Float]], 51 ): 52 """ 53 The method allows to construct the Database from scanning sequence 54 :param color_images_paths: List of paths to color images 55 :param depth_images_paths: List of paths to depth images 56 :param depth_scale: Depth scale for transforming depth image into point clouds 57 :param intrinsics: Intrinsic camera parameters 58 :param trajectory: List of camera poses 59 :return: Constructed database 60 """ 61 color_images_providers = [ 62 ColorImageProvider(path_to_image) for path_to_image in color_images_paths 63 ] 64 depth_images_providers = [ 65 DepthImageProvider(path_to_image, intrinsics, depth_scale) 66 for path_to_image in depth_images_paths 67 ] 68 return cls(color_images_providers, depth_images_providers, trajectory) 69 70 @classmethod 71 def from_point_clouds( 72 cls, 73 color_images_paths: list[Path], 74 point_clouds_paths: list[Path], 75 trajectory: list[NDArray[Shape["4, 4"], Float]], 76 ): 77 """ 78 The method allows to construct the Database from point clouds, color images and trajectory 79 :param color_images_paths: List of paths to color images 80 :param point_clouds_paths: List of paths to point clouds 81 :param trajectory: List of camera poses 82 :return: Constructed database 83 """ 84 color_images_providers = [ 85 ColorImageProvider(path_to_image) for path_to_image in color_images_paths 86 ] 87 point_clouds_providers = [ 88 PointCloudProvider(path_to_pcd) for path_to_pcd in point_clouds_paths 89 ] 90 return cls(color_images_providers, point_clouds_providers, trajectory) 91 92 def __len__(self): 93 return len(self.trajectory) 94 95 @cached_property 96 def bounds( 97 self, 98 ) -> tuple[NDArray[Shape["3"], Float], NDArray[Shape["3"], Float]]: 99 """ 100 Gets bounds of the DB scene 101 :return: Min and max bounds of the scene 102 """ 103 min_bounds = [] 104 max_bounds = [] 105 106 for i in range(len(self)): 107 pcd = self.point_clouds[i].point_cloud.transform(self.trajectory[i]) 108 min_bounds.append(pcd.get_min_bound()) 109 max_bounds.append(pcd.get_max_bound()) 110 111 min_bound = np.amin(np.asarray(min_bounds), axis=0) 112 max_bound = np.amax(np.asarray(max_bounds), axis=0) 113 return min_bound, max_bound 114 115 def build_sparse_map( 116 self, 117 voxel_grid: VoxelGrid, 118 down_sample_step: int, 119 ) -> o3d.geometry.PointCloud: 120 """ 121 Builds sparse map of the whole DB scene 122 :param voxel_grid: Voxel grid for down sampling 123 :param down_sample_step: Voxel down sampling step for reducing RAM usage 124 :return: Resulting point cloud of the scene 125 """ 126 map_pcd = o3d.geometry.PointCloud() 127 for i, (pose, pcd_raw) in enumerate(zip(self.trajectory, self.point_clouds)): 128 pcd = pcd_raw.point_cloud.transform(pose) 129 map_pcd += pcd 130 if i % down_sample_step == 0: 131 map_pcd = voxel_grid.voxel_down_sample(map_pcd) 132 return voxel_grid.voxel_down_sample(map_pcd)
@dataclass(frozen=True)
    class
    Database:
                
    27@dataclass(frozen=True) 28class Database: 29 """ 30 Class for easy storage and processing of color images, depth images 31 and trajectory and their further use for the VPR task 32 """ 33 34 color_images: list[ColorImageProvider] 35 point_clouds: list[DepthImageProvider | PointCloudProvider] 36 trajectory: list[NDArray[Shape["4, 4"], Float]] 37 38 def __post_init__(self): 39 if not (len(self.trajectory) == len(self.point_clouds) == len(self.trajectory)): 40 raise ValueError( 41 "Trajectory, RGB images and point clouds should have equal length" 42 ) 43 44 @classmethod 45 def from_depth_images( 46 cls, 47 color_images_paths: list[Path], 48 depth_images_paths: list[Path], 49 depth_scale: int, 50 intrinsics: NDArray[Shape["3, 3"], Float], 51 trajectory: list[NDArray[Shape["4, 4"], Float]], 52 ): 53 """ 54 The method allows to construct the Database from scanning sequence 55 :param color_images_paths: List of paths to color images 56 :param depth_images_paths: List of paths to depth images 57 :param depth_scale: Depth scale for transforming depth image into point clouds 58 :param intrinsics: Intrinsic camera parameters 59 :param trajectory: List of camera poses 60 :return: Constructed database 61 """ 62 color_images_providers = [ 63 ColorImageProvider(path_to_image) for path_to_image in color_images_paths 64 ] 65 depth_images_providers = [ 66 DepthImageProvider(path_to_image, intrinsics, depth_scale) 67 for path_to_image in depth_images_paths 68 ] 69 return cls(color_images_providers, depth_images_providers, trajectory) 70 71 @classmethod 72 def from_point_clouds( 73 cls, 74 color_images_paths: list[Path], 75 point_clouds_paths: list[Path], 76 trajectory: list[NDArray[Shape["4, 4"], Float]], 77 ): 78 """ 79 The method allows to construct the Database from point clouds, color images and trajectory 80 :param color_images_paths: List of paths to color images 81 :param point_clouds_paths: List of paths to point clouds 82 :param trajectory: List of camera poses 83 :return: Constructed database 84 """ 85 color_images_providers = [ 86 ColorImageProvider(path_to_image) for path_to_image in color_images_paths 87 ] 88 point_clouds_providers = [ 89 PointCloudProvider(path_to_pcd) for path_to_pcd in point_clouds_paths 90 ] 91 return cls(color_images_providers, point_clouds_providers, trajectory) 92 93 def __len__(self): 94 return len(self.trajectory) 95 96 @cached_property 97 def bounds( 98 self, 99 ) -> tuple[NDArray[Shape["3"], Float], NDArray[Shape["3"], Float]]: 100 """ 101 Gets bounds of the DB scene 102 :return: Min and max bounds of the scene 103 """ 104 min_bounds = [] 105 max_bounds = [] 106 107 for i in range(len(self)): 108 pcd = self.point_clouds[i].point_cloud.transform(self.trajectory[i]) 109 min_bounds.append(pcd.get_min_bound()) 110 max_bounds.append(pcd.get_max_bound()) 111 112 min_bound = np.amin(np.asarray(min_bounds), axis=0) 113 max_bound = np.amax(np.asarray(max_bounds), axis=0) 114 return min_bound, max_bound 115 116 def build_sparse_map( 117 self, 118 voxel_grid: VoxelGrid, 119 down_sample_step: int, 120 ) -> o3d.geometry.PointCloud: 121 """ 122 Builds sparse map of the whole DB scene 123 :param voxel_grid: Voxel grid for down sampling 124 :param down_sample_step: Voxel down sampling step for reducing RAM usage 125 :return: Resulting point cloud of the scene 126 """ 127 map_pcd = o3d.geometry.PointCloud() 128 for i, (pose, pcd_raw) in enumerate(zip(self.trajectory, self.point_clouds)): 129 pcd = pcd_raw.point_cloud.transform(pose) 130 map_pcd += pcd 131 if i % down_sample_step == 0: 132 map_pcd = voxel_grid.voxel_down_sample(map_pcd) 133 return voxel_grid.voxel_down_sample(map_pcd)
Class for easy storage and processing of color images, depth images and trajectory and their further use for the VPR task
            
        Database(	color_images: list[vprdb.providers.color_image_provider.ColorImageProvider],	point_clouds: list[vprdb.providers.depth_image_provider.DepthImageProvider | vprdb.providers.point_cloud_provider.PointCloudProvider],	trajectory: list[typing.NDArray])
        
    
    
    
    
                            
            color_images: list[vprdb.providers.color_image_provider.ColorImageProvider]
        
    
    
    
    
                            
            point_clouds: list[vprdb.providers.depth_image_provider.DepthImageProvider | vprdb.providers.point_cloud_provider.PointCloudProvider]
        
    
    
    
    
                            @classmethod
        def
        from_depth_images(	cls,	color_images_paths: list[pathlib.Path],	depth_images_paths: list[pathlib.Path],	depth_scale: int,	intrinsics: NDArray[Shape['3, 3'], Float],	trajectory: list[typing.NDArray]):
                
    44 @classmethod 45 def from_depth_images( 46 cls, 47 color_images_paths: list[Path], 48 depth_images_paths: list[Path], 49 depth_scale: int, 50 intrinsics: NDArray[Shape["3, 3"], Float], 51 trajectory: list[NDArray[Shape["4, 4"], Float]], 52 ): 53 """ 54 The method allows to construct the Database from scanning sequence 55 :param color_images_paths: List of paths to color images 56 :param depth_images_paths: List of paths to depth images 57 :param depth_scale: Depth scale for transforming depth image into point clouds 58 :param intrinsics: Intrinsic camera parameters 59 :param trajectory: List of camera poses 60 :return: Constructed database 61 """ 62 color_images_providers = [ 63 ColorImageProvider(path_to_image) for path_to_image in color_images_paths 64 ] 65 depth_images_providers = [ 66 DepthImageProvider(path_to_image, intrinsics, depth_scale) 67 for path_to_image in depth_images_paths 68 ] 69 return cls(color_images_providers, depth_images_providers, trajectory)
The method allows to construct the Database from scanning sequence
Parameters
- color_images_paths: List of paths to color images
 - depth_images_paths: List of paths to depth images
 - depth_scale: Depth scale for transforming depth image into point clouds
 - intrinsics: Intrinsic camera parameters
 - trajectory: List of camera poses
 
Returns
Constructed database
@classmethod
        def
        from_point_clouds(	cls,	color_images_paths: list[pathlib.Path],	point_clouds_paths: list[pathlib.Path],	trajectory: list[typing.NDArray]):
                
    71 @classmethod 72 def from_point_clouds( 73 cls, 74 color_images_paths: list[Path], 75 point_clouds_paths: list[Path], 76 trajectory: list[NDArray[Shape["4, 4"], Float]], 77 ): 78 """ 79 The method allows to construct the Database from point clouds, color images and trajectory 80 :param color_images_paths: List of paths to color images 81 :param point_clouds_paths: List of paths to point clouds 82 :param trajectory: List of camera poses 83 :return: Constructed database 84 """ 85 color_images_providers = [ 86 ColorImageProvider(path_to_image) for path_to_image in color_images_paths 87 ] 88 point_clouds_providers = [ 89 PointCloudProvider(path_to_pcd) for path_to_pcd in point_clouds_paths 90 ] 91 return cls(color_images_providers, point_clouds_providers, trajectory)
The method allows to construct the Database from point clouds, color images and trajectory
Parameters
- color_images_paths: List of paths to color images
 - point_clouds_paths: List of paths to point clouds
 - trajectory: List of camera poses
 
Returns
Constructed database
            bounds: tuple[typing.NDArray, typing.NDArray]
        
    
    
    
            Gets bounds of the DB scene
Returns
Min and max bounds of the scene
            
        def
        build_sparse_map(	self,	voxel_grid: vprdb.core.voxel_grid.VoxelGrid,	down_sample_step: int) -> open3d.cpu.pybind.geometry.PointCloud:
                
    
    
            116 def build_sparse_map( 117 self, 118 voxel_grid: VoxelGrid, 119 down_sample_step: int, 120 ) -> o3d.geometry.PointCloud: 121 """ 122 Builds sparse map of the whole DB scene 123 :param voxel_grid: Voxel grid for down sampling 124 :param down_sample_step: Voxel down sampling step for reducing RAM usage 125 :return: Resulting point cloud of the scene 126 """ 127 map_pcd = o3d.geometry.PointCloud() 128 for i, (pose, pcd_raw) in enumerate(zip(self.trajectory, self.point_clouds)): 129 pcd = pcd_raw.point_cloud.transform(pose) 130 map_pcd += pcd 131 if i % down_sample_step == 0: 132 map_pcd = voxel_grid.voxel_down_sample(map_pcd) 133 return voxel_grid.voxel_down_sample(map_pcd)
Builds sparse map of the whole DB scene
Parameters
- voxel_grid: Voxel grid for down sampling
 - down_sample_step: Voxel down sampling step for reducing RAM usage
 
Returns
Resulting point cloud of the scene