det_3d_reader.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. # Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
  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.
  14. import os
  15. from typing import Generic
  16. import numpy as np
  17. from ...utils.benchmark import benchmark
  18. class _EasyDict(dict):
  19. def __getattr__(self, key: str):
  20. if key in self:
  21. return self[key]
  22. return super().__getattr__(self, key)
  23. def __setattr__(self, key: str, value: Generic):
  24. self[key] = value
  25. class SampleMeta(_EasyDict):
  26. # yapf: disable
  27. __slots__ = [
  28. "camera_intrinsic",
  29. # bgr or rgb
  30. "image_format",
  31. # pillow or cv2
  32. "image_reader",
  33. # chw or hwc
  34. "channel_order",
  35. # Unique ID of the sample
  36. "id",
  37. "time_lag",
  38. "ref_from_curr"
  39. ]
  40. # yapf: enable
  41. def __init__(self, **kwargs):
  42. for key, value in kwargs.items():
  43. setattr(self, key, value)
  44. class Sample(_EasyDict):
  45. """Data structure containing sample data information"""
  46. _VALID_MODALITIES = ["image", "lidar", "radar", "multimodal", "multiview"]
  47. def __init__(self, path: str, modality: str):
  48. if modality not in self._VALID_MODALITIES:
  49. raise ValueError(
  50. "Only modality {} is supported, but got {}".format(
  51. self._VALID_MODALITIES, modality
  52. )
  53. )
  54. self.meta = SampleMeta()
  55. self.path = path
  56. self.data = None
  57. self.modality = modality.lower()
  58. self.bboxes_2d = None
  59. self.bboxes_3d = None
  60. self.labels = None
  61. self.sweeps = []
  62. self.attrs = None
  63. @benchmark.timeit_with_options(name=None, is_read_operation=True)
  64. class ReadNuscenesData:
  65. def __init__(
  66. self,
  67. dataset_root="",
  68. load_interval=1,
  69. noise_sensor_type="camera",
  70. drop_frames=False,
  71. drop_set=[0, "discrete"],
  72. modality="multimodal",
  73. extrinsics_noise=False,
  74. extrinsics_noise_type="single",
  75. ):
  76. self.load_interval = load_interval
  77. self.noise_data = None
  78. self.noise_sensor_type = noise_sensor_type
  79. self.drop_frames = drop_frames
  80. self.drop_ratio = drop_set[0]
  81. self.drop_type = drop_set[1]
  82. self.modality = modality
  83. self.extrinsics_noise = extrinsics_noise
  84. self.extrinsics_noise_type = extrinsics_noise_type
  85. self.dataset_root = dataset_root
  86. def get_data_info(self, info):
  87. """Get data info.
  88. Returns:
  89. dict: Data information that will be passed to the data \
  90. preprocessing pipelines. It includes the following keys:
  91. - sample_idx (str): Sample index.
  92. - pts_filename (str): Filename of point clouds.
  93. - sweeps (list[dict]): Infos of sweeps.
  94. - timestamp (float): Sample timestamp.
  95. - img_filename (str, optional): Image filename.
  96. - lidar2img (list[np.ndarray], optional): Transformations \
  97. from lidar to different cameras.
  98. - ann_info (dict): Annotation info.
  99. """
  100. sample = Sample(path=None, modality=self.modality)
  101. sample.sample_idx = info["token"]
  102. sample.meta.id = info["token"]
  103. sample.pts_filename = os.path.join(self.dataset_root, info["lidar_path"])
  104. sample.sweeps = info["sweeps"]
  105. sample.timestamp = info["timestamp"] / 1e6
  106. if self.noise_sensor_type == "lidar":
  107. if self.drop_frames:
  108. pts_filename = sample.pts_filename
  109. file_name = pts_filename.split("/")[-1]
  110. if self.noise_data[file_name]["noise"]["drop_frames"][self.drop_ratio][
  111. self.drop_type
  112. ]["stuck"]:
  113. replace_file = self.noise_data[file_name]["noise"]["drop_frames"][
  114. self.drop_ratio
  115. ][self.drop_type]["replace"]
  116. if replace_file != "":
  117. pts_filename = pts_filename.replace(file_name, replace_file)
  118. sample.pts_filename = pts_filename
  119. sample.sweeps = self.noise_data[replace_file]["mmdet_info"][
  120. "sweeps"
  121. ]
  122. sample.timestamp = (
  123. self.noise_data[replace_file]["mmdet_info"]["timestamp"]
  124. / 1e6
  125. )
  126. cam_orders = [
  127. "CAM_FRONT_LEFT",
  128. "CAM_FRONT",
  129. "CAM_FRONT_RIGHT",
  130. "CAM_BACK_RIGHT",
  131. "CAM_BACK",
  132. "CAM_BACK_LEFT",
  133. ]
  134. if self.modality == "multiview" or self.modality == "multimodal":
  135. image_paths = []
  136. lidar2img_rts = []
  137. caminfos = []
  138. for cam_type in cam_orders:
  139. cam_info = info["cams"][cam_type]
  140. cam_data_path = cam_info["data_path"]
  141. cam_data_path = os.path.join(self.dataset_root, cam_data_path)
  142. file_name = cam_data_path.split("/")[-1]
  143. if self.noise_sensor_type == "camera":
  144. if self.drop_frames:
  145. if self.noise_data[file_name]["noise"]["drop_frames"][
  146. self.drop_ratio
  147. ][self.drop_type]["stuck"]:
  148. replace_file = self.noise_data[file_name]["noise"][
  149. "drop_frames"
  150. ][self.drop_ratio][self.drop_type]["replace"]
  151. if replace_file != "":
  152. cam_data_path = cam_data_path.replace(
  153. file_name, replace_file
  154. )
  155. image_paths.append(cam_data_path)
  156. # obtain lidar to image transformation matrix
  157. if self.extrinsics_noise:
  158. sensor2lidar_rotation = self.noise_data[file_name]["noise"][
  159. "extrinsics_noise"
  160. ][f"{self.extrinsics_noise_type}_noise_sensor2lidar_rotation"]
  161. sensor2lidar_translation = self.noise_data[file_name]["noise"][
  162. "extrinsics_noise"
  163. ][f"{self.extrinsics_noise_type}_noise_sensor2lidar_translation"]
  164. else:
  165. sensor2lidar_rotation = cam_info["sensor2lidar_rotation"]
  166. sensor2lidar_translation = cam_info["sensor2lidar_translation"]
  167. lidar2cam_r = np.linalg.inv(sensor2lidar_rotation)
  168. lidar2cam_t = sensor2lidar_translation @ lidar2cam_r.T
  169. lidar2cam_rt = np.eye(4)
  170. lidar2cam_rt[:3, :3] = lidar2cam_r.T
  171. lidar2cam_rt[3, :3] = -lidar2cam_t
  172. intrinsic = cam_info["cam_intrinsic"]
  173. viewpad = np.eye(4)
  174. viewpad[: intrinsic.shape[0], : intrinsic.shape[1]] = intrinsic
  175. lidar2img_rt = viewpad @ lidar2cam_rt.T
  176. lidar2img_rts.append(lidar2img_rt)
  177. caminfos.append(
  178. {
  179. "sensor2lidar_translation": sensor2lidar_translation,
  180. "sensor2lidar_rotation": sensor2lidar_rotation,
  181. "cam_intrinsic": cam_info["cam_intrinsic"],
  182. }
  183. )
  184. sample.update(
  185. dict(
  186. img_filename=image_paths, lidar2img=lidar2img_rts, caminfo=caminfos
  187. )
  188. )
  189. return sample
  190. def prepare_test_data(self, info):
  191. sample = self.get_data_info(info)
  192. sample = self.add_new_fields(sample)
  193. return sample
  194. def add_new_fields(self, sample):
  195. sample["img_fields"] = []
  196. sample["bbox3d_fields"] = []
  197. sample["pts_mask_fields"] = []
  198. sample["pts_seg_fields"] = []
  199. sample["bbox_fields"] = []
  200. sample["mask_fields"] = []
  201. sample["seg_fields"] = []
  202. return sample
  203. def __call__(self, batch_data):
  204. return [self.prepare_test_data(data_info) for data_info in batch_data]