mmdet3D中文表明

打印 上一主题 下一主题

主题 520|帖子 520|积分 1560

  1. # 版权声明: 本代码版权所有 (c) OpenMMLab。
  2. import os
  3. from collections import OrderedDict
  4. from os import path as osp
  5. from typing import List, Tuple, Union
  6. import mmcv
  7. import numpy as np
  8. from nuscenes.nuscenes import NuScenes
  9. from nuscenes.utils.geometry_utils import view_points
  10. from pyquaternion import Quaternion
  11. from shapely.geometry import MultiPoint, box
  12. from mmdet3d.core.bbox import points_cam2img
  13. from mmdet3d.datasets import NuScenesDataset
  14. # 定义nuScenes数据集的类别和属性
  15. nus_categories = ('car', 'truck', 'trailer', 'bus', 'construction_vehicle',
  16.                   'bicycle', 'motorcycle', 'pedestrian', 'traffic_cone',
  17.                   'barrier')
  18. nus_attributes = ('cycle.with_rider', 'cycle.without_rider',
  19.                   'pedestrian.moving', 'pedestrian.standing',
  20.                   'pedestrian.sitting_lying_down', 'vehicle.moving',
  21.                   'vehicle.parked', 'vehicle.stopped', 'None')
  22. def create_nuscenes_infos(root_path,
  23.                           info_prefix,
  24.                           version='v1.0-trainval',
  25.                           max_sweeps=10):
  26.     """
  27.     创建nuScenes数据集的信息文件。
  28.     给定原始数据,生成相关的信息文件,并以pkl格式保存。
  29.     参数:
  30.         root_path (str): 数据根目录路径。
  31.         info_prefix (str): 要生成的信息文件的前缀。
  32.         version (str, 可选): 数据版本,默认为'v1.0-trainval'。
  33.         max_sweeps (int, 可选): 最大sweeps数量,默认为10。
  34.     """
  35.     from nuscenes.nuscenes import NuScenes
  36.     nusc = NuScenes(version=version, dataroot=root_path, verbose=True)
  37.     from nuscenes.utils import splits
  38.     available_vers = ['v1.0-trainval', 'v1.0-test', 'v1.0-mini']
  39.     assert version in available_vers
  40.     if version == 'v1.0-trainval':
  41.         train_scenes = splits.train
  42.         val_scenes = splits.val
  43.     elif version == 'v1.0-test':
  44.         train_scenes = splits.test
  45.         val_scenes = []
  46.     elif version == 'v1.0-mini':
  47.         train_scenes = splits.mini_train
  48.         val_scenes = splits.mini_val
  49.     else:
  50.         raise ValueError('未知版本')
  51.     # 过滤现有场景
  52.     available_scenes = get_available_scenes(nusc)
  53.     available_scene_names = [s['name'] for s in available_scenes]
  54.     train_scenes = list(
  55.         filter(lambda x: x in available_scene_names, train_scenes))
  56.     val_scenes = list(filter(lambda x: x in available_scene_names, val_scenes))
  57.     train_scenes = set([
  58.         available_scenes[available_scene_names.index(s)]['token']
  59.         for s in train_scenes
  60.     ])
  61.     val_scenes = set([
  62.         available_scenes[available_scene_names.index(s)]['token']
  63.         for s in val_scenes
  64.     ])
  65.     test = 'test' in version
  66.     if test:
  67.         print('测试场景数量: {}'.format(len(train_scenes)))
  68.     else:
  69.         print('训练场景数量: {},验证场景数量: {}'.format(
  70.             len(train_scenes), len(val_scenes)))
  71.     train_nusc_infos, val_nusc_infos = _fill_trainval_infos(
  72.         nusc, train_scenes, val_scenes, test, max_sweeps=max_sweeps)
  73.     metadata = dict(version=version)
  74.     if test:
  75.         print('测试样本数量: {}'.format(len(train_nusc_infos)))
  76.         data = dict(infos=train_nusc_infos, metadata=metadata)
  77.         info_path = osp.join(root_path,
  78.                              '{}_infos_test.pkl'.format(info_prefix))
  79.         mmcv.dump(data, info_path)
  80.     else:
  81.         print('训练样本数量: {},验证样本数量: {}'.format(
  82.             len(train_nusc_infos), len(val_nusc_infos)))
  83.         data = dict(infos=train_nusc_infos, metadata=metadata)
  84.         info_path = osp.join(root_path,
  85.                              '{}_infos_train.pkl'.format(info_prefix))
  86.         mmcv.dump(data, info_path)
  87.         data['infos'] = val_nusc_infos
  88.         info_val_path = osp.join(root_path,
  89.                                  '{}_infos_val.pkl'.format(info_prefix))
  90.         mmcv.dump(data, info_val_path)
  91. def get_available_scenes(nusc):
  92.     """
  93.     从输入的nuScenes类中获取可用场景。
  94.     给定原始数据,获取可用场景的信息以便生成进一步的信息。
  95.     参数:
  96.         nusc (class): nuScenes数据集的类。
  97.     返回:
  98.         available_scenes (list[dict]): 可用场景的基本信息列表。
  99.     """
  100.     available_scenes = []
  101.     print('总场景数量: {}'.format(len(nusc.scene)))
  102.     for scene in nusc.scene:
  103.         scene_token = scene['token']
  104.         scene_rec = nusc.get('scene', scene_token)
  105.         sample_rec = nusc.get('sample', scene_rec['first_sample_token'])
  106.         sd_rec = nusc.get('sample_data', sample_rec['data']['LIDAR_TOP'])
  107.         has_more_frames = True
  108.         scene_not_exist = False
  109.         while has_more_frames:
  110.             lidar_path, boxes, _ = nusc.get_sample_data(sd_rec['token'])
  111.             lidar_path = str(lidar_path)
  112.             if os.getcwd() in lidar_path:
  113.                 # 从lyftdataset获取的路径是绝对路径
  114.                 lidar_path = lidar_path.split(f'{os.getcwd()}/')[-1]
  115.                 # 相对路径
  116.             if not mmcv.is_filepath(lidar_path):
  117.                 scene_not_exist = True
  118.                 break
  119.             else:
  120.                 break
  121.         if scene_not_exist:
  122.             continue
  123.         available_scenes.append(scene)
  124.     print('存在的场景数量: {}'.format(len(available_scenes)))
  125.     return available_scenes
  126. def _fill_trainval_infos(nusc,
  127.                          train_scenes,
  128.                          val_scenes,
  129.                          test=False,
  130.                          max_sweeps=10):
  131.     """
  132.     从原始数据生成训练/验证信息。
  133.     参数:
  134.         nusc (:obj:`NuScenes`): nuScenes数据集类。
  135.         train_scenes (list[str]): 训练场景的基本信息。
  136.         val_scenes (list[str]): 验证场景的基本信息。
  137.         test (bool, 可选): 是否使用测试模式。在测试模式中,不能访问注释。默认为False。
  138.         max_sweeps (int, 可选): 最大sweeps数量。默认为10。
  139.     返回:
  140.         tuple[list[dict]]: 将保存到信息文件的训练集和验证集信息。
  141.     """
  142.     train_nusc_infos = []
  143.     val_nusc_infos = []
  144.     for sample in mmcv.track_iter_progress(nusc.sample):
  145.         lidar_token = sample['data']['LIDAR_TOP']
  146.         sd_rec = nusc.get('sample_data', sample['data']['LIDAR_TOP'])
  147.         cs_record = nusc.get('calibrated_sensor',
  148.                              sd_rec['calibrated_sensor_token'])
  149.         pose_record = nusc.get('ego_pose', sd_rec['ego_pose_token'])
  150.         lidar_path, boxes, _ = nusc.get_sample_data(lidar_token)
  151.         mmcv.check_file_exist(lidar_path)
  152.         info = {
  153.             'lidar_path': lidar_path,
  154.             'token': sample['token'],
  155.             'sweeps': [],
  156.             'cams': dict(),
  157.             'lidar2ego_translation': cs_record['translation'],
  158.             'lidar2ego_rotation': cs_record['rotation'],
  159.             'ego2global_translation': pose_record['translation'],
  160.             'ego2global_rotation': pose_record['rotation'],
  161.             'timestamp': sample['timestamp'],
  162.         }
  163.         l2e_r = info['lidar2ego_rotation']
  164.         l2e_t = info['lidar2ego_translation']
  165.         e2g_r = info['ego2global_rotation']
  166.         e2g_t = info['ego2global_translation']
  167.         l2e_r_mat = Quaternion(l2e_r).rotation_matrix
  168.         e2g_r_mat = Quaternion(e2g_r).rotation_matrix
  169.         # 获取每帧的6个图像的信息
  170.         camera_types = [
  171.             'CAM_FRONT',
  172.             'CAM_FRONT_RIGHT',
  173.             'CAM_FRONT_LEFT',
  174.             'CAM_BACK',
  175.             'CAM_BACK_LEFT',
  176.             'CAM_BACK_RIGHT',
  177.         ]
  178.         for cam in camera_types:
  179.             cam_token = sample['data'][cam]
  180.             cam_path, _, cam_intrinsic = nusc.get_sample_data(cam_token)
  181.             cam_info = obtain_sensor2top(nusc, cam_token, l2e_t, l2e_r_mat,
  182.                                          e2g_t, e2g_r_mat, cam)
  183.             cam_info.update(cam_intrinsic=cam_intrinsic)
  184.             info['cams'].update({cam: cam_info})
  185.         # 获取单个关键帧的sweeps
  186.         sd_rec = nusc.get('sample_data', sample['data']['LIDAR_TOP'])
  187.         sweeps = []
  188.         while len(sweeps) < max_sweeps:
  189.             if not sd_rec['prev'] == '':
  190.                 sweep = obtain_sensor2top(nusc, sd_rec['prev'], l2e_t,
  191.                                           l2e_r_mat, e2g_t, e2g_r_mat, 'lidar')
  192.                 sweeps.append(sweep)
  193.                 sd_rec = nusc.get('sample_data
  194. ', sd_rec['prev'])
  195.             else:
  196.                 break
  197.         info['sweeps'] = sweeps
  198.         # 获取注释
  199.         if not test:
  200.             annotations = [
  201.                 nusc.get('sample_annotation', token)
  202.                 for token in sample['anns']
  203.             ]
  204.             locs = np.array([b.center for b in boxes]).reshape(-1, 3)
  205.             dims = np.array([b.wlh for b in boxes]).reshape(-1, 3)
  206.             rots = np.array([b.orientation.yaw_pitch_roll[0]
  207.                              for b in boxes]).reshape(-1, 1)
  208.             velocity = np.array(
  209.                 [nusc.box_velocity(token)[:2] for token in sample['anns']])
  210.             valid_flag = np.array(
  211.                 [(anno['num_lidar_pts'] + anno['num_radar_pts']) > 0
  212.                  for anno in annotations],
  213.                 dtype=bool).reshape(-1)
  214.             # 将速度从全局转换为激光雷达
  215.             for i in range(len(boxes)):
  216.                 velo = np.array([*velocity[i], 0.0])
  217.                 velo = velo @ np.linalg.inv(e2g_r_mat).T @ np.linalg.inv(
  218.                     l2e_r_mat).T
  219.                 velocity[i] = velo[:2]
  220.             names = [b.name for b in boxes]
  221.             for i in range(len(names)):
  222.                 if names[i] in NuScenesDataset.NameMapping:
  223.                     names[i] = NuScenesDataset.NameMapping[names[i]]
  224.             names = np.array(names)
  225.             # 我们需要将box尺寸转换为
  226.             # 我们激光雷达坐标系的格式
  227.             # 即x_size, y_size, z_size(对应于l, w, h)
  228.             gt_boxes = np.concatenate([locs, dims[:, [1, 0, 2]], rots], axis=1)
  229.             assert len(gt_boxes) == len(
  230.                 annotations), f'{len(gt_boxes)}, {len(annotations)}'
  231.             info['gt_boxes'] = gt_boxes
  232.             info['gt_names'] = names
  233.             info['gt_velocity'] = velocity.reshape(-1, 2)
  234.             info['num_lidar_pts'] = np.array(
  235.                 [a['num_lidar_pts'] for a in annotations])
  236.             info['num_radar_pts'] = np.array(
  237.                 [a['num_radar_pts'] for a in annotations])
  238.             info['valid_flag'] = valid_flag
  239.         if sample['scene_token'] in train_scenes:
  240.             train_nusc_infos.append(info)
  241.         else:
  242.             val_nusc_infos.append(info)
  243.     return train_nusc_infos, val_nusc_infos
  244. def obtain_sensor2top(nusc,
  245.                       sensor_token,
  246.                       l2e_t,
  247.                       l2e_r_mat,
  248.                       e2g_t,
  249.                       e2g_r_mat,
  250.                       sensor_type='lidar'):
  251.     """
  252.     获取从一般传感器到顶部激光雷达的RT矩阵信息。
  253.     参数:
  254.         nusc (class): nuScenes数据集类。
  255.         sensor_token (str): 与特定传感器类型对应的样本数据token。
  256.         l2e_t (np.ndarray): 从激光雷达到ego的平移向量,形状为(1, 3)。
  257.         l2e_r_mat (np.ndarray): 从激光雷达到ego的旋转矩阵,形状为(3, 3)。
  258.         e2g_t (np.ndarray): 从ego到全局的平移向量,形状为(1, 3)。
  259.         e2g_r_mat (np.ndarray): 从ego到全局的旋转矩阵,形状为(3, 3)。
  260.         sensor_type (str, 可选): 要校准的传感器类型。默认为'lidar'。
  261.     返回:
  262.         sweep (dict): 经过转换后的sweep信息。
  263.     """
  264.     sd_rec = nusc.get('sample_data', sensor_token)
  265.     cs_record = nusc.get('calibrated_sensor',
  266.                          sd_rec['calibrated_sensor_token'])
  267.     pose_record = nusc.get('ego_pose', sd_rec['ego_pose_token'])
  268.     data_path = str(nusc.get_sample_data_path(sd_rec['token']))
  269.     if os.getcwd() in data_path:  # 从lyftdataset获取的路径是绝对路径
  270.         data_path = data_path.split(f'{os.getcwd()}/')[-1]  # 相对路径
  271.     sweep = {
  272.         'data_path': data_path,
  273.         'type': sensor_type,
  274.         'sample_data_token': sd_rec['token'],
  275.         'sensor2ego_translation': cs_record['translation'],
  276.         'sensor2ego_rotation': cs_record['rotation'],
  277.         'ego2global_translation': pose_record['translation'],
  278.         'ego2global_rotation': pose_record['rotation'],
  279.         'timestamp': sd_rec['timestamp']
  280.     }
  281.     l2e_r_s = sweep['sensor2ego_rotation']
  282.     l2e_t_s = sweep['sensor2ego_translation']
  283.     e2g_r_s = sweep['ego2global_rotation']
  284.     e2g_t_s = sweep['ego2global_translation']
  285.     # 获取从传感器到顶部激光雷达的RT
  286.     # sweep->ego->global->ego'->lidar
  287.     l2e_r_s_mat = Quaternion(l2e_r_s).rotation_matrix
  288.     e2g_r_s_mat = Quaternion(e2g_r_s).rotation_matrix
  289.     R = (l2e_r_s_mat.T @ e2g_r_s_mat.T) @ (
  290.         np.linalg.inv(e2g_r_mat).T @ np.linalg.inv(l2e_r_mat).T)
  291.     T = (l2e_t_s @ e2g_r_s_mat.T + e2g_t_s) @ (
  292.         np.linalg.inv(e2g_r_mat).T @ np.linalg.inv(l2e_r_mat).T)
  293.     T -= e2g_t @ (np.linalg.inv(e2g_r_mat).T @ np.linalg.inv(l2e_r_mat).T
  294.                   ) + l2e_t @ np.linalg.inv(l2e_r_mat).T
  295.     sweep['sensor2lidar_rotation'] = R.T  # points @ R.T + T
  296.     sweep['sensor2lidar_translation'] = T
  297.     return sweep
  298. def export_2d_annotation(root_path, info_path, version, mono3d=True):
  299.     """
  300.     从信息文件和原始数据导出2D注释。
  301.     参数:
  302.         root_path (str): 原始数据的根路径。
  303.         info_path (str): 信息文件的路径。
  304.         version (str): 数据集版本。
  305.         mono3d (bool, 可选): 是否导出mono3d注释。默认为True。
  306.     """
  307.     # 获取相机的bbox注释
  308.     camera_types = [
  309.         'CAM_FRONT',
  310.         'CAM_FRONT_RIGHT',
  311.         'CAM_FRONT_LEFT',
  312.         'CAM_BACK',
  313.         'CAM_BACK_LEFT',
  314.         'CAM_BACK_RIGHT',
  315.     ]
  316.     nusc_infos = mmcv.load(info_path)['infos']
  317.     nusc = NuScenes(version=version, dataroot=root_path, verbose=True)
  318.     # info_2d_list = []
  319.     cat2Ids = [
  320.         dict(id=nus_categories.index(cat_name), name=cat_name)
  321.         for cat_name in nus_categories
  322.     ]
  323.     coco_ann_id = 0
  324.     coco_2d_dict = dict(annotations=[], images=[], categories=cat2Ids)
  325.     for info in mmcv.track_iter_progress(nusc_infos):
  326.         for cam in camera_types:
  327.             cam_info = info['cams'][cam]
  328.             coco_infos = get_2d_boxes(
  329.                 nusc,
  330.                 cam_info['sample_data_token'],
  331.                 visibilities=['', '1', '2', '3', '4'],
  332.                 mono3d=mono3d)
  333.             (height, width, _) = mmcv.imread(cam_info['data_path']).shape
  334.             coco_2d_dict['images'].append(
  335.                 dict(
  336.                     file_name=cam_info['data_path'].split('data/nuscenes/')
  337.                     [-1],
  338.                     id=cam_info['sample_data_token'],
  339.                     token=info['token'],
  340.                     cam2ego_rotation=cam_info['sensor2ego_rotation'],
  341.                     cam2ego_translation=cam_info['sensor2ego_translation'],
  342.                     ego2global_rotation=info['ego2global_rotation'],
  343.                     ego2global_translation=info['ego2global_translation'],
  344.                     cam_intrinsic=cam_info['cam_intrinsic'],
  345.                     width=width,
  346.                     height=height))
  347.             for coco_info in coco_infos:
  348.                 if coco_info is None:
  349.                     continue
  350.                 # 添加一个空键用于coco格式
  351.                 coco_info['segmentation'] = []
  352.                 coco_info['id'] = coco_ann_id
  353.                 coco_2d_dict['annotations'].append(coco_info)
  354.                 coco_ann_id += 1
  355.     if mono3d:
  356.         json_prefix = f'{info_path[:-4]}_mono3d'
  357.     else:
  358.         json_prefix = f'{info_path[:-4]}'
  359.     mmcv.dump(coco_2d_dict, f'{json_prefix}.coco.json')
  360. def get_2d_boxes(nusc,
  361.                  sample_data_token: str,
  362.                  visibilities: List[str],
  363.                  mono3d=True):
  364.     """
  365.     获取给定sample_data_token的2D注释记录。
  366.     参数:
  367.         sample_data_token (str): 属于相机关键帧的样本数据token。
  368.         visibilities (list[str]): 可见性过滤器。
  369.         mono3d (bool): 是否获取带有mono3d注释的box。
  370.     返回:
  371.         list[dict]: 属于输入
  372. sample_data_token的2D注释记录列表。
  373.     """
  374.     # 获取样本数据和与该样本数据对应的样本。
  375.     sd_rec = nusc.get('sample_data', sample_data_token)
  376.     assert sd_rec[
  377.         'sensor_modality'] == 'camera', '错误: get_2d_boxes仅适用于相机样本数据!'
  378.     if not sd_rec['is_key_frame']:
  379.         raise ValueError(
  380.             '2D重新投影仅适用于关键帧。')
  381.     s_rec = nusc.get('sample', sd_rec['sample_token'])
  382.     # 获取校准传感器和自我姿态记录,以获取转换矩阵。
  383.     cs_rec = nusc.get('calibrated_sensor', sd_rec['calibrated_sensor_token'])
  384.     pose_rec = nusc.get('ego_pose', sd_rec['ego_pose_token'])
  385.     camera_intrinsic = np.array(cs_rec['camera_intrinsic'])
  386.     # 获取所有具有指定可见性的注释。
  387.     ann_recs = [
  388.         nusc.get('sample_annotation', token) for token in s_rec['anns']
  389.     ]
  390.     ann_recs = [
  391.         ann_rec for ann_rec in ann_recs
  392.         if (ann_rec['visibility_token'] in visibilities)
  393.     ]
  394.     repro_recs = []
  395.     for ann_rec in ann_recs:
  396.         # 增加sample_annotation的token信息。
  397.         ann_rec['sample_annotation_token'] = ann_rec['token']
  398.         ann_rec['sample_data_token'] = sample_data_token
  399.         # 获取全局坐标中的box。
  400.         box = nusc.get_box(ann_rec['token'])
  401.         # 将它们移动到自我姿态框架。
  402.         box.translate(-np.array(pose_rec['translation']))
  403.         box.rotate(Quaternion(pose_rec['rotation']).inverse)
  404.         # 将它们移动到校准传感器框架。
  405.         box.translate(-np.array(cs_rec['translation']))
  406.         box.rotate(Quaternion(cs_rec['rotation']).inverse)
  407.         # 过滤掉不在校准传感器前面的角。
  408.         corners_3d = box.corners()
  409.         in_front = np.argwhere(corners_3d[2, :] > 0).flatten()
  410.         corners_3d = corners_3d[:, in_front]
  411.         # 将3D box投影到2D。
  412.         corner_coords = view_points(corners_3d, camera_intrinsic,
  413.                                     True).T[:, :2].tolist()
  414.         # 仅保留落在图像内的角。
  415.         final_coords = post_process_coords(corner_coords)
  416.         # 如果重新投影的角的凸包不与图像画布相交,则跳过。
  417.         if final_coords is None:
  418.             continue
  419.         else:
  420.             min_x, min_y, max_x, max_y = final_coords
  421.         # 生成要包含在.json文件中的字典记录。
  422.         repro_rec = generate_record(ann_rec, min_x, min_y, max_x, max_y,
  423.                                     sample_data_token, sd_rec['filename'])
  424.         # 如果mono3d=True,则在相机坐标中添加3D注释
  425.         if mono3d and (repro_rec is not None):
  426.             loc = box.center.tolist()
  427.             dim = box.wlh
  428.             dim[[0, 1, 2]] = dim[[1, 2, 0]]  # 将wlh转换为我们的lhw
  429.             dim = dim.tolist()
  430.             rot = box.orientation.yaw_pitch_roll[0]
  431.             rot = [-rot]  # 将旋转转换为我们的相机坐标
  432.             global_velo2d = nusc.box_velocity(box.token)[:2]
  433.             global_velo3d = np.array([*global_velo2d, 0.0])
  434.             e2g_r_mat = Quaternion(pose_rec['rotation']).rotation_matrix
  435.             c2e_r_mat = Quaternion(cs_rec['rotation']).rotation_matrix
  436.             cam_velo3d = global_velo3d @ np.linalg.inv(
  437.                 e2g_r_mat).T @ np.linalg.inv(c2e_r_mat).T
  438.             velo = cam_velo3d[0::2].tolist()
  439.             repro_rec['bbox_cam3d'] = loc + dim + rot
  440.             repro_rec['velo_cam3d'] = velo
  441.             center3d = np.array(loc).reshape([1, 3])
  442.             center2d = points_cam2img(
  443.                 center3d, camera_intrinsic, with_depth=True)
  444.             repro_rec['center2d'] = center2d.squeeze().tolist()
  445.             # 标准化center2D + 深度
  446.             # 如果深度小于0的样本将被移除
  447.             if repro_rec['center2d'][2] <= 0:
  448.                 continue
  449.             ann_token = nusc.get('sample_annotation',
  450.                                  box.token)['attribute_tokens']
  451.             if len(ann_token) == 0:
  452.                 attr_name = 'None'
  453.             else:
  454.                 attr_name = nusc.get('attribute', ann_token[0])['name']
  455.             attr_id = nus_attributes.index(attr_name)
  456.             repro_rec['attribute_name'] = attr_name
  457.             repro_rec['attribute_id'] = attr_id
  458.         repro_recs.append(repro_rec)
  459.     return repro_recs
  460. def post_process_coords(
  461.     corner_coords: List, imsize: Tuple[int, int] = (1600, 900)
  462. ) -> Union[Tuple[float, float, float, float], None]:
  463.     """
  464.     获取重新投影的bbox角的凸包和图像画布的交集,如果没有交集则返回None。
  465.     参数:
  466.         corner_coords (list[int]): 重新投影的bbox角的坐标。
  467.         imsize (tuple[int]): 图像画布的尺寸。
  468.     返回:
  469.         tuple[float]: 2D box角的凸包和图像画布的交集。
  470.     """
  471.     polygon_from_2d_box = MultiPoint(corner_coords).convex_hull
  472.     img_canvas = box(0, 0, imsize[0], imsize[1])
  473.     if polygon_from_2d_box.intersects(img_canvas):
  474.         img_intersection = polygon_from_2d_box.intersection(img_canvas)
  475.         intersection_coords = np.array(
  476.             [coord for coord in img_intersection.exterior.coords])
  477.         min_x = min(intersection_coords[:, 0])
  478.         min_y = min(intersection_coords[:, 1])
  479.         max_x = max(intersection_coords[:, 0])
  480.         max_y = max(intersection_coords[:, 1])
  481.         return min_x, min_y, max_x, max_y
  482.     else:
  483.         return None
  484. def generate_record(ann_rec: dict, x1: float, y1: float, x2: float, y2: float,
  485.                     sample_data_token: str, filename: str) -> OrderedDict:
  486.     """
  487.     给定各种信息和2D边界框坐标,生成一个2D注释记录。
  488.     参数:
  489.         ann_rec (dict): 原始3d注释记录。
  490.         x1 (float): x坐标的最小值。
  491.         y1 (float): y坐标的最小值。
  492.         x2 (float): x坐标的最大值。
  493.         y2 (float): y坐标的最大值。
  494.         sample_data_token (str): 样本数据token。
  495.         filename (str): 注释所在的对应图像文件。
  496.     返回:
  497.         dict: 一个2D注释记录。
  498.             - file_name (str): 文件名
  499.             - image_id (str): 样本数据token
  500.             - area (float): 2d box的面积
  501.             - category_name (str): 类别名称
  502.             - category_id (int): 类别id
  503.             - bbox (list[float]): 2d box的左x, 顶y, dx, dy
  504.             - iscrowd (int): 区域是否是拥挤的
  505.     """
  506.     repro_rec = OrderedDict()
  507.     repro_rec['sample_data_token'] = sample_data_token
  508.     coco_rec = dict()
  509.     relevant_keys = [
  510.         'attribute_tokens',
  511.         'category_name',
  512.         'instance_token',
  513.         'next',
  514.         'num_lidar_pts',
  515.         'num_radar_pts',
  516.         'prev',
  517.         'sample_annotation_token',
  518.         'sample_data_token',
  519.         'visibility_token',
  520.     ]
  521.     for key, value in ann_rec.items():
  522.         if key in relevant_keys:
  523.             repro_rec[key] = value
  524.     repro_rec['bbox_corners'] = [x1, y1, x2, y2]
  525.     repro_rec['filename'] = filename
  526.     coco_rec['file_name'] = filename
  527.     coco_rec['image_id'] = sample_data_token
  528.     coco_rec['area'] = (y2 - y1) * (x2 - x1)
  529.     if repro_rec['category_name'] not in NuScenesDataset.NameMapping:
  530.         return None
  531.     cat_name = NuScenesDataset.NameMapping[repro_rec['category_name']]
  532.     coco_rec['category_name'] = cat_name
  533.     coco_rec['category_id'] = nus_categories.index(cat_name)
  534.     coco_rec['bbox'] = [x1, y1, x2 - x1, y2 - y1]
  535.     coco_rec['iscrowd'] = 0
  536.     return coco_rec
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

我爱普洱茶

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表