Commit 41b18fd8 authored by zhe chen's avatar zhe chen
Browse files

Use pre-commit to reformat code


Use pre-commit to reformat code
parent ff20ea39
from .epoch_based_runner import EpochBasedRunner_video
\ No newline at end of file
from .epoch_based_runner import EpochBasedRunner_video
# Copyright (c) OpenMMLab. All rights reserved.
# ---------------------------------------------
# Modified by Zhiqi Li
# ---------------------------------------------
import os.path as osp
import torch
import mmcv
from mmcv.runner.base_runner import BaseRunner
from mmcv.runner.epoch_based_runner import EpochBasedRunner
from mmcv.runner.builder import RUNNERS
from mmcv.runner.checkpoint import save_checkpoint
from mmcv.runner.utils import get_host_info
from pprint import pprint
from mmcv.parallel.data_container import DataContainer
@RUNNERS.register_module()
class EpochBasedRunner_video(EpochBasedRunner):
'''
# basic logic
input_sequence = [a, b, c] # given a sequence of samples
prev_bev = None
for each in input_sequcene[:-1]
prev_bev = eval_model(each, prev_bev)) # inference only.
model(input_sequcene[-1], prev_bev) # train the last sample.
'''
def __init__(self,
model,
eval_model=None,
batch_processor=None,
optimizer=None,
work_dir=None,
logger=None,
meta=None,
keys=['gt_bboxes_3d', 'gt_labels_3d', 'img'],
max_iters=None,
max_epochs=None):
super().__init__(model,
batch_processor,
optimizer,
work_dir,
logger,
meta,
max_iters,
max_epochs)
keys.append('img_metas')
self.keys = keys
self.eval_model = eval_model
self.eval_model.eval()
def run_iter(self, data_batch, train_mode, **kwargs):
if self.batch_processor is not None:
assert False
# outputs = self.batch_processor(
# self.model, data_batch, train_mode=train_mode, **kwargs)
elif train_mode:
num_samples = data_batch['img'].data[0].size(1)
data_list = []
prev_bev = None
for i in range(num_samples):
data = {}
for key in self.keys:
if key not in ['img_metas', 'img', 'points']:
data[key] = data_batch[key]
else:
if key == 'img':
data['img'] = DataContainer(data=[data_batch['img'].data[0][:, i]], cpu_only=data_batch['img'].cpu_only, stack=True)
elif key == 'img_metas':
data['img_metas'] = DataContainer(data=[[each[i] for each in data_batch['img_metas'].data[0]]], cpu_only=data_batch['img_metas'].cpu_only)
else:
assert False
data_list.append(data)
with torch.no_grad():
for i in range(num_samples-1):
if data_list[i]['img_metas'].data[0][0]['prev_bev_exists']:
data_list[i]['prev_bev'] = DataContainer(data=[prev_bev], cpu_only=False)
prev_bev = self.eval_model.val_step(data_list[i], self.optimizer, **kwargs)
if data_list[-1]['img_metas'].data[0][0]['prev_bev_exists']:
data_list[-1]['prev_bev'] = DataContainer(data=[prev_bev], cpu_only=False)
outputs = self.model.train_step(data_list[-1], self.optimizer, **kwargs)
else:
assert False
# outputs = self.model.val_step(data_batch, self.optimizer, **kwargs)
if not isinstance(outputs, dict):
raise TypeError('"batch_processor()" or "model.train_step()"'
'and "model.val_step()" must return a dict')
if 'log_vars' in outputs:
self.log_buffer.update(outputs['log_vars'], outputs['num_samples'])
self.outputs = outputs
\ No newline at end of file
# Copyright (c) OpenMMLab. All rights reserved.
# ---------------------------------------------
# Modified by Zhiqi Li
# ---------------------------------------------
import torch
from mmcv.parallel.data_container import DataContainer
from mmcv.runner.builder import RUNNERS
from mmcv.runner.epoch_based_runner import EpochBasedRunner
@RUNNERS.register_module()
class EpochBasedRunner_video(EpochBasedRunner):
'''
# basic logic
input_sequence = [a, b, c] # given a sequence of samples
prev_bev = None
for each in input_sequcene[:-1]
prev_bev = eval_model(each, prev_bev)) # inference only.
model(input_sequcene[-1], prev_bev) # train the last sample.
'''
def __init__(self,
model,
eval_model=None,
batch_processor=None,
optimizer=None,
work_dir=None,
logger=None,
meta=None,
keys=['gt_bboxes_3d', 'gt_labels_3d', 'img'],
max_iters=None,
max_epochs=None):
super().__init__(model,
batch_processor,
optimizer,
work_dir,
logger,
meta,
max_iters,
max_epochs)
keys.append('img_metas')
self.keys = keys
self.eval_model = eval_model
self.eval_model.eval()
def run_iter(self, data_batch, train_mode, **kwargs):
if self.batch_processor is not None:
assert False
# outputs = self.batch_processor(
# self.model, data_batch, train_mode=train_mode, **kwargs)
elif train_mode:
num_samples = data_batch['img'].data[0].size(1)
data_list = []
prev_bev = None
for i in range(num_samples):
data = {}
for key in self.keys:
if key not in ['img_metas', 'img', 'points']:
data[key] = data_batch[key]
else:
if key == 'img':
data['img'] = DataContainer(data=[data_batch['img'].data[0][:, i]],
cpu_only=data_batch['img'].cpu_only, stack=True)
elif key == 'img_metas':
data['img_metas'] = DataContainer(
data=[[each[i] for each in data_batch['img_metas'].data[0]]],
cpu_only=data_batch['img_metas'].cpu_only)
else:
assert False
data_list.append(data)
with torch.no_grad():
for i in range(num_samples - 1):
if data_list[i]['img_metas'].data[0][0]['prev_bev_exists']:
data_list[i]['prev_bev'] = DataContainer(data=[prev_bev], cpu_only=False)
prev_bev = self.eval_model.val_step(data_list[i], self.optimizer, **kwargs)
if data_list[-1]['img_metas'].data[0][0]['prev_bev_exists']:
data_list[-1]['prev_bev'] = DataContainer(data=[prev_bev], cpu_only=False)
outputs = self.model.train_step(data_list[-1], self.optimizer, **kwargs)
else:
assert False
# outputs = self.model.val_step(data_batch, self.optimizer, **kwargs)
if not isinstance(outputs, dict):
raise TypeError('"batch_processor()" or "model.train_step()"'
'and "model.val_step()" must return a dict')
if 'log_vars' in outputs:
self.log_buffer.update(outputs['log_vars'], outputs['num_samples'])
self.outputs = outputs
import torch
from mmdet.core.bbox.assigners import AssignResult, BaseAssigner
from mmdet.core.bbox.builder import BBOX_ASSIGNERS
from mmdet.core.bbox.assigners import AssignResult
from mmdet.core.bbox.assigners import BaseAssigner
from mmdet.core.bbox.match_costs import build_match_cost
from mmdet.models.utils.transformer import inverse_sigmoid
from projects.mmdet3d_plugin.core.bbox.util import normalize_bbox
try:
......@@ -52,7 +49,7 @@ class HungarianAssigner3D(BaseAssigner):
def assign(self,
bbox_pred,
cls_pred,
gt_bboxes,
gt_bboxes,
gt_labels,
gt_bboxes_ignore=None,
eps=1e-7):
......@@ -89,10 +86,10 @@ class HungarianAssigner3D(BaseAssigner):
num_gts, num_bboxes = gt_bboxes.size(0), bbox_pred.size(0)
# 1. assign -1 by default
assigned_gt_inds = bbox_pred.new_full((num_bboxes, ),
assigned_gt_inds = bbox_pred.new_full((num_bboxes,),
-1,
dtype=torch.long)
assigned_labels = bbox_pred.new_full((num_bboxes, ),
assigned_labels = bbox_pred.new_full((num_bboxes,),
-1,
dtype=torch.long)
if num_gts == 0 or num_bboxes == 0:
......@@ -107,14 +104,14 @@ class HungarianAssigner3D(BaseAssigner):
# classification and bboxcost.
cls_cost = self.cls_cost(cls_pred, gt_labels)
# regression L1 cost
normalized_gt_bboxes = normalize_bbox(gt_bboxes, self.pc_range)
reg_cost = self.reg_cost(bbox_pred[:, :8], normalized_gt_bboxes[:, :8])
# weighted sum of above two costs
cost = cls_cost + reg_cost
# 3. do Hungarian matching on CPU using linear_sum_assignment
cost = cost.detach().cpu()
if linear_sum_assignment is None:
......@@ -133,4 +130,4 @@ class HungarianAssigner3D(BaseAssigner):
assigned_gt_inds[matched_row_inds] = matched_col_inds + 1
assigned_labels[matched_row_inds] = gt_labels[matched_col_inds]
return AssignResult(
num_gts, assigned_gt_inds, None, labels=assigned_labels)
\ No newline at end of file
num_gts, assigned_gt_inds, None, labels=assigned_labels)
import torch
from mmdet.core.bbox import BaseBBoxCoder
from mmdet.core.bbox.builder import BBOX_CODERS
from projects.mmdet3d_plugin.core.bbox.util import denormalize_bbox
import numpy as np
@BBOX_CODERS.register_module()
......@@ -56,10 +54,10 @@ class NMSFreeCoder(BaseBBoxCoder):
labels = indexs % self.num_classes
bbox_index = indexs // self.num_classes
bbox_preds = bbox_preds[bbox_index]
final_box_preds = denormalize_bbox(bbox_preds, self.pc_range)
final_scores = scores
final_preds = labels
final_box_preds = denormalize_bbox(bbox_preds, self.pc_range)
final_scores = scores
final_preds = labels
# use score threshold
if self.score_threshold is not None:
......@@ -113,10 +111,9 @@ class NMSFreeCoder(BaseBBoxCoder):
"""
all_cls_scores = preds_dicts['all_cls_scores'][-1]
all_bbox_preds = preds_dicts['all_bbox_preds'][-1]
batch_size = all_cls_scores.size()[0]
predictions_list = []
for i in range(batch_size):
predictions_list.append(self.decode_single(all_cls_scores[i], all_bbox_preds[i]))
return predictions_list
from mmdet.core.bbox.match_costs import build_match_cost
from .match_cost import BBox3DL1Cost
__all__ = ['build_match_cost', 'BBox3DL1Cost']
\ No newline at end of file
__all__ = ['build_match_cost', 'BBox3DL1Cost']
......@@ -24,4 +24,4 @@ class BBox3DL1Cost(object):
torch.Tensor: bbox_cost value with weight
"""
bbox_cost = torch.cdist(bbox_pred, gt_bboxes, p=1)
return bbox_cost * self.weight
\ No newline at end of file
return bbox_cost * self.weight
import torch
import torch
def normalize_bbox(bboxes, pc_range):
cx = bboxes[..., 0:1]
cy = bboxes[..., 1:2]
cz = bboxes[..., 2:3]
......@@ -12,7 +11,7 @@ def normalize_bbox(bboxes, pc_range):
rot = bboxes[..., 6:7]
if bboxes.size(-1) > 7:
vx = bboxes[..., 7:8]
vx = bboxes[..., 7:8]
vy = bboxes[..., 8:9]
normalized_bboxes = torch.cat(
(cx, cy, w, l, cz, h, rot.sin(), rot.cos(), vx, vy), dim=-1
......@@ -23,8 +22,9 @@ def normalize_bbox(bboxes, pc_range):
)
return normalized_bboxes
def denormalize_bbox(normalized_bboxes, pc_range):
# rotation
# rotation
rot_sine = normalized_bboxes[..., 6:7]
rot_cosine = normalized_bboxes[..., 7:8]
......@@ -34,20 +34,20 @@ def denormalize_bbox(normalized_bboxes, pc_range):
cx = normalized_bboxes[..., 0:1]
cy = normalized_bboxes[..., 1:2]
cz = normalized_bboxes[..., 4:5]
# size
w = normalized_bboxes[..., 2:3]
l = normalized_bboxes[..., 3:4]
h = normalized_bboxes[..., 5:6]
w = w.exp()
l = l.exp()
h = h.exp()
w = w.exp()
l = l.exp()
h = h.exp()
if normalized_bboxes.size(-1) > 8:
# velocity
# velocity
vx = normalized_bboxes[:, 8:9]
vy = normalized_bboxes[:, 9:10]
denormalized_bboxes = torch.cat([cx, cy, cz, w, l, h, rot, vx, vy], dim=-1)
else:
denormalized_bboxes = torch.cat([cx, cy, cz, w, l, h, rot], dim=-1)
return denormalized_bboxes
\ No newline at end of file
return denormalized_bboxes
from .eval_hooks import CustomDistEvalHook
\ No newline at end of file
from .eval_hooks import CustomDistEvalHook
# Note: Considering that MMCV's EvalHook updated its interface in V1.3.16,
# in order to avoid strong version dependency, we did not directly
# inherit EvalHook but BaseDistEvalHook.
......@@ -9,9 +8,7 @@ import os.path as osp
import mmcv
import torch.distributed as dist
from mmcv.runner import DistEvalHook as BaseDistEvalHook
from mmcv.runner import EvalHook as BaseEvalHook
from torch.nn.modules.batchnorm import _BatchNorm
from mmdet.core.evaluation.eval_hooks import DistEvalHook
def _calc_dynamic_intervals(start_interval, dynamic_interval_list):
......@@ -28,7 +25,7 @@ def _calc_dynamic_intervals(start_interval, dynamic_interval_list):
class CustomDistEvalHook(BaseDistEvalHook):
def __init__(self, *args, dynamic_intervals=None, **kwargs):
def __init__(self, *args, dynamic_intervals=None, **kwargs):
super(CustomDistEvalHook, self).__init__(*args, **kwargs)
self.use_dynamic_intervals = dynamic_intervals is not None
if self.use_dynamic_intervals:
......@@ -73,7 +70,8 @@ class CustomDistEvalHook(BaseDistEvalHook):
if tmpdir is None:
tmpdir = osp.join(runner.work_dir, '.eval_hook')
from projects.mmdet3d_plugin.bevformer.apis.test import custom_multi_gpu_test # to solve circlur import
from projects.mmdet3d_plugin.bevformer.apis.test import \
custom_multi_gpu_test # to solve circlur import
results = custom_multi_gpu_test(
runner.model,
......@@ -86,7 +84,6 @@ class CustomDistEvalHook(BaseDistEvalHook):
# key_score = self.evaluate(runner, results)
self.dataloader.dataset.evaluate_miou(results,
runner=runner)
runner=runner)
# if self.save_best:
# self._save_ckpt(runner, key_score)
from .builder import custom_build_dataset
from .nuscenes_dataset import CustomNuScenesDataset
from .nuscenes_occ import NuSceneOcc
from .builder import custom_build_dataset
__all__ = [
'CustomNuScenesDataset'
......
# Copyright (c) OpenMMLab. All rights reserved.
import copy
import platform
......@@ -8,13 +7,14 @@ from functools import partial
import numpy as np
from mmcv.parallel import collate
from mmcv.runner import get_dist_info
from mmcv.utils import Registry, build_from_cfg
from torch.utils.data import DataLoader
from mmdet.datasets.samplers import GroupSampler
from projects.mmdet3d_plugin.datasets.samplers.group_sampler import DistributedGroupSampler
from projects.mmdet3d_plugin.datasets.samplers.distributed_sampler import DistributedSampler
from projects.mmdet3d_plugin.datasets.samplers.distributed_sampler import \
DistributedSampler
from projects.mmdet3d_plugin.datasets.samplers.group_sampler import \
DistributedGroupSampler
from projects.mmdet3d_plugin.datasets.samplers.sampler import build_sampler
from torch.utils.data import DataLoader
def build_dataloader(dataset,
samples_per_gpu,
......@@ -48,24 +48,26 @@ def build_dataloader(dataset,
# DistributedGroupSampler will definitely shuffle the data to satisfy
# that images on each GPU are in the same group
if shuffle:
sampler = build_sampler(shuffler_sampler if shuffler_sampler is not None else dict(type='DistributedGroupSampler'),
dict(
dataset=dataset,
samples_per_gpu=samples_per_gpu,
num_replicas=world_size,
rank=rank,
seed=seed)
)
sampler = build_sampler(
shuffler_sampler if shuffler_sampler is not None else dict(type='DistributedGroupSampler'),
dict(
dataset=dataset,
samples_per_gpu=samples_per_gpu,
num_replicas=world_size,
rank=rank,
seed=seed)
)
else:
sampler = build_sampler(nonshuffler_sampler if nonshuffler_sampler is not None else dict(type='DistributedSampler'),
dict(
dataset=dataset,
num_replicas=world_size,
rank=rank,
shuffle=shuffle,
seed=seed)
)
sampler = build_sampler(
nonshuffler_sampler if nonshuffler_sampler is not None else dict(type='DistributedSampler'),
dict(
dataset=dataset,
num_replicas=world_size,
rank=rank,
shuffle=shuffle,
seed=seed)
)
batch_size = samples_per_gpu
num_workers = workers_per_gpu
......@@ -103,14 +105,15 @@ def worker_init_fn(worker_id, num_workers, rank, seed):
# Copyright (c) OpenMMLab. All rights reserved.
import platform
from mmcv.utils import Registry, build_from_cfg
from mmcv.utils import Registry, build_from_cfg
from mmdet.datasets import DATASETS
from mmdet.datasets.builder import _concat_dataset
if platform.system() != 'Windows':
# https://github.com/pytorch/pytorch/issues/973
import resource
rlimit = resource.getrlimit(resource.RLIMIT_NOFILE)
base_soft_limit = rlimit[0]
hard_limit = rlimit[1]
......
import copy
import random
from os import path as osp
import mmcv
import numpy as np
from mmdet.datasets import DATASETS
import torch
from mmcv.parallel import DataContainer as DC
from mmdet3d.core.bbox import LiDARInstance3DBoxes
from mmdet3d.datasets import NuScenesDataset
import mmcv
from os import path as osp
from mmdet.datasets import DATASETS
import torch
import numpy as np
from nuscenes.eval.common.utils import quaternion_yaw, Quaternion
from mmdet3d.core.bbox import Box3DMode, Coord3DMode, LiDARInstance3DBoxes
from nuscenes.eval.common.utils import Quaternion, quaternion_yaw
from .nuscnes_eval import NuScenesEval_custom
from projects.mmdet3d_plugin.models.utils.visual import save_tensor
from mmcv.parallel import DataContainer as DC
import random
@DATASETS.register_module()
......@@ -28,7 +26,7 @@ class CustomNuScenesDataset(NuScenesDataset):
self.queue_length = queue_length
self.overlap_test = overlap_test
self.bev_size = bev_size
def prepare_train_data(self, index):
"""
Training data preparation.
......@@ -38,7 +36,7 @@ class CustomNuScenesDataset(NuScenesDataset):
dict: Training data dict of the corresponding index.
"""
queue = []
index_list = list(range(index-self.queue_length, index))
index_list = list(range(index - self.queue_length, index))
random.shuffle(index_list)
index_list = sorted(index_list[1:])
index_list.append(index)
......@@ -55,7 +53,6 @@ class CustomNuScenesDataset(NuScenesDataset):
queue.append(example)
return self.union2one(queue)
def union2one(self, queue):
imgs_list = [each['img'].data for each in queue]
metas_map = {}
......@@ -127,8 +124,6 @@ class CustomNuScenesDataset(NuScenesDataset):
box_dim=gt_bboxes_3d.shape[-1],
origin=(0.5, 0.5, 0.5)).convert_to(self.box_mode_3d)
anns_results = dict(
gt_bboxes_3d=gt_bboxes_3d,
gt_labels_3d=gt_labels_3d,
......@@ -180,7 +175,7 @@ class CustomNuScenesDataset(NuScenesDataset):
# obtain lidar to image transformation matrix
lidar2cam_r = np.linalg.inv(cam_info['sensor2lidar_rotation'])
lidar2cam_t = cam_info[
'sensor2lidar_translation'] @ lidar2cam_r.T
'sensor2lidar_translation'] @ lidar2cam_r.T
lidar2cam_rt = np.eye(4)
lidar2cam_rt[:3, :3] = lidar2cam_r.T
lidar2cam_rt[3, :3] = -lidar2cam_t
......
import copy
import os
import numpy as np
from tqdm import tqdm
from mmdet.datasets import DATASETS
from mmdet3d.datasets import NuScenesDataset
import random
import mmcv
from os import path as osp
from mmdet.datasets import DATASETS
import torch
import numpy as np
from nuscenes.eval.common.utils import quaternion_yaw, Quaternion
from .nuscnes_eval import NuScenesEval_custom
from projects.mmdet3d_plugin.models.utils.visual import save_tensor
import torch
from mmcv.parallel import DataContainer as DC
import random
from mmdet3d.datasets import NuScenesDataset
from mmdet.datasets import DATASETS
from nuscenes.eval.common.utils import Quaternion, quaternion_yaw
from nuscenes.utils.geometry_utils import transform_matrix
from .occ_metrics import Metric_mIoU, Metric_FScore
from tqdm import tqdm
from .occ_metrics import Metric_FScore, Metric_mIoU
@DATASETS.register_module()
......@@ -209,8 +206,8 @@ class NuSceneOcc(NuScenesDataset):
if not os.path.exists(show_dir):
os.mkdir(show_dir)
print('\nSaving output and gt in {} for visualization.'.format(show_dir))
begin=eval_kwargs.get('begin',None)
end=eval_kwargs.get('end',None)
begin = eval_kwargs.get('begin', None)
end = eval_kwargs.get('end', None)
self.occ_eval_metrics = Metric_mIoU(
num_classes=18,
use_lidar_mask=False,
......@@ -233,15 +230,14 @@ class NuSceneOcc(NuScenesDataset):
occ_gt = np.load(os.path.join(self.data_root, info['occ_gt_path']))
if show_dir is not None:
if begin is not None and end is not None:
if index>= begin and index<end:
if index >= begin and index < end:
sample_token = info['token']
save_path = os.path.join(show_dir,str(index).zfill(4))
save_path = os.path.join(show_dir, str(index).zfill(4))
np.savez_compressed(save_path, pred=occ_pred, gt=occ_gt, sample_token=sample_token)
else:
sample_token=info['token']
save_path=os.path.join(show_dir,str(index).zfill(4))
np.savez_compressed(save_path,pred=occ_pred,gt=occ_gt,sample_token=sample_token)
sample_token = info['token']
save_path = os.path.join(show_dir, str(index).zfill(4))
np.savez_compressed(save_path, pred=occ_pred, gt=occ_gt, sample_token=sample_token)
gt_semantics = occ_gt['semantics']
mask_lidar = occ_gt['mask_lidar'].astype(bool)
......@@ -254,6 +250,3 @@ class NuSceneOcc(NuScenesDataset):
self.occ_eval_metrics.count_miou()
if self.eval_fscore:
self.fscore_eval_metrics.count_fscore()
......@@ -3,74 +3,42 @@ import copy
import json
import os
import time
from typing import Tuple, Dict, Any
import torch
import numpy as np
from typing import Any, Dict, Tuple
import numpy as np
import tqdm
from matplotlib import pyplot as plt
from nuscenes import NuScenes
from nuscenes.eval.common.config import config_factory
from nuscenes.eval.common.data_classes import EvalBoxes
from nuscenes.eval.detection.data_classes import DetectionConfig
from nuscenes.eval.common.loaders import (add_center_dist, filter_eval_boxes,
load_gt, load_prediction)
from nuscenes.eval.common.render import setup_axis
from nuscenes.eval.detection.algo import accumulate, calc_ap, calc_tp
from nuscenes.eval.detection.constants import (DETECTION_NAMES,
PRETTY_DETECTION_NAMES,
PRETTY_TP_METRICS, TP_METRICS,
TP_METRICS_UNITS)
from nuscenes.eval.detection.data_classes import (DetectionBox,
DetectionConfig,
DetectionMetricDataList,
DetectionMetrics)
from nuscenes.eval.detection.evaluate import NuScenesEval
from pyquaternion import Quaternion
from nuscenes import NuScenes
from nuscenes.eval.common.data_classes import EvalBoxes
from nuscenes.eval.detection.data_classes import DetectionBox
from nuscenes.eval.detection.render import (class_pr_curve, dist_pr_curve,
summary_plot)
from nuscenes.eval.detection.utils import category_to_detection_name
from nuscenes.eval.tracking.data_classes import TrackingBox
from nuscenes.utils.data_classes import Box
from nuscenes.utils.geometry_utils import points_in_box
from nuscenes.utils.geometry_utils import (BoxVisibility, transform_matrix,
view_points)
from nuscenes.utils.splits import create_splits_scenes
from nuscenes.eval.common.loaders import load_prediction, add_center_dist, filter_eval_boxes
import tqdm
from nuscenes.utils.geometry_utils import view_points, box_in_image, BoxVisibility, transform_matrix
from torchvision.transforms.functional import rotate
import pycocotools.mask as mask_util
# from projects.mmdet3d_plugin.models.utils.visual import save_tensor
from torchvision.transforms.functional import rotate
import cv2
import argparse
import json
import os
import random
import time
from typing import Tuple, Dict, Any
import numpy as np
from nuscenes import NuScenes
from nuscenes.eval.common.config import config_factory
from nuscenes.eval.common.data_classes import EvalBoxes
from nuscenes.eval.common.loaders import load_prediction, load_gt, add_center_dist, filter_eval_boxes
from nuscenes.eval.detection.algo import accumulate, calc_ap, calc_tp
from nuscenes.eval.detection.constants import TP_METRICS
from nuscenes.eval.detection.data_classes import DetectionConfig, DetectionMetrics, DetectionBox, \
DetectionMetricDataList
from nuscenes.eval.detection.render import summary_plot, class_pr_curve, dist_pr_curve, visualize_sample
from nuscenes.eval.common.utils import quaternion_yaw, Quaternion
from mmdet3d.core.bbox.iou_calculators import BboxOverlaps3D
from IPython import embed
import json
from typing import Any
import numpy as np
from matplotlib import pyplot as plt
from nuscenes import NuScenes
from nuscenes.eval.common.data_classes import EvalBoxes
from nuscenes.eval.common.render import setup_axis
from nuscenes.eval.common.utils import boxes_to_sensor
from nuscenes.eval.detection.constants import TP_METRICS, DETECTION_NAMES, DETECTION_COLORS, TP_METRICS_UNITS, \
PRETTY_DETECTION_NAMES, PRETTY_TP_METRICS
from nuscenes.eval.detection.data_classes import DetectionMetrics, DetectionMetricData, DetectionMetricDataList
from nuscenes.utils.data_classes import LidarPointCloud
from nuscenes.utils.geometry_utils import view_points
from pyquaternion import Quaternion
# from projects.mmdet3d_plugin.models.utils.visual import save_tensor
Axis = Any
def class_tp_curve(md_list: DetectionMetricDataList,
metrics: DetectionMetrics,
detection_name: str,
......@@ -124,7 +92,7 @@ def class_tp_curve(md_list: DetectionMetricDataList,
label = '{}: {:.2f} ({})'.format(PRETTY_TP_METRICS[metric], tp, TP_METRICS_UNITS[metric])
if metric == 'trans_err':
label += f' ({md.max_recall_ind})' # add recall
print(f'Recall: {detection_name}: {md.max_recall_ind/100}')
print(f'Recall: {detection_name}: {md.max_recall_ind / 100}')
ax.plot(recall, error, label=label)
ax.axvline(x=md.max_recall, linestyle='-.', color=(0, 0, 0, 0.3))
ax.legend(loc='best')
......@@ -211,7 +179,7 @@ def center_in_image(box, intrinsic: np.ndarray, imsize: Tuple[int, int], vis_lev
elif vis_level == BoxVisibility.NONE:
return True
else:
raise ValueError("vis_level: {} not valid".format(vis_level))
raise ValueError('vis_level: {} not valid'.format(vis_level))
def exist_corners_in_image_but_not_all(box, intrinsic: np.ndarray, imsize: Tuple[int, int],
......@@ -259,7 +227,7 @@ def load_gt(nusc: NuScenes, eval_split: str, box_cls, verbose: bool = False):
print('Loading annotations for {} split from nuScenes version: {}'.format(eval_split, nusc.version))
# Read out all sample_tokens in DB.
sample_tokens_all = [s['token'] for s in nusc.sample]
assert len(sample_tokens_all) > 0, "Error: Database has no samples!"
assert len(sample_tokens_all) > 0, 'Error: Database has no samples!'
# Only keep samples from this split.
splits = create_splits_scenes()
......@@ -354,7 +322,7 @@ def load_gt(nusc: NuScenes, eval_split: str, box_cls, verbose: bool = False):
all_annotations.add_boxes(sample_token, sample_boxes)
if verbose:
print("Loaded ground truth annotations for {} samples.".format(len(all_annotations.sample_tokens)))
print('Loaded ground truth annotations for {} samples.'.format(len(all_annotations.sample_tokens)))
return all_annotations
......@@ -385,8 +353,8 @@ def filter_eval_boxes_by_id(nusc: NuScenes,
eval_boxes.boxes[sample_token] = filtered_boxes
if verbose:
print("=> Original number of boxes: %d" % total)
print("=> After anns based filtering: %d" % anns_filter)
print('=> Original number of boxes: %d' % total)
print('=> After anns based filtering: %d' % anns_filter)
return eval_boxes
......@@ -417,13 +385,13 @@ def filter_eval_boxes_by_visibility(
eval_boxes.boxes[sample_token] = filtered_boxes
if verbose:
print("=> Original number of boxes: %d" % total)
print("=> After visibility based filtering: %d" % anns_filter)
print('=> Original number of boxes: %d' % total)
print('=> After visibility based filtering: %d' % anns_filter)
return eval_boxes
def filter_by_sample_token(ori_eval_boxes, valid_sample_tokens=[], verbose=False):
def filter_by_sample_token(ori_eval_boxes, valid_sample_tokens=[], verbose=False):
eval_boxes = copy.deepcopy(ori_eval_boxes)
for sample_token in eval_boxes.sample_tokens:
if sample_token not in valid_sample_tokens:
......@@ -498,8 +466,8 @@ def filter_eval_boxes_by_overlap(nusc: NuScenes,
verbose = True
if verbose:
print("=> Original number of boxes: %d" % total)
print("=> After anns based filtering: %d" % anns_filter)
print('=> Original number of boxes: %d' % total)
print('=> After anns based filtering: %d' % anns_filter)
return eval_boxes
......@@ -620,7 +588,6 @@ class NuScenesEval_custom(NuScenesEval):
self.pred_boxes = filter_by_sample_token(self.all_preds, valid_tokens)
self.sample_tokens = self.gt_boxes.sample_tokens
def evaluate(self) -> Tuple[DetectionMetrics, DetectionMetricDataList]:
"""
Performs the actual evaluation.
......@@ -698,7 +665,7 @@ class NuScenesEval_custom(NuScenesEval):
savepath=savepath('dist_pr_' + str(dist_th)))
if __name__ == "__main__":
if __name__ == '__main__':
# Settings.
parser = argparse.ArgumentParser(description='Evaluate nuScenes detection results.',
......@@ -746,6 +713,6 @@ if __name__ == "__main__":
nusc_eval.update_gt(type_='vis', visibility=vis)
print(f'================ {vis} ===============')
nusc_eval.main(plot_examples=plot_examples_, render_curves=render_curves_)
#for index in range(1, 41):
# for index in range(1, 41):
# nusc_eval.update_gt(type_='ord', index=index)
#
import numpy as np
import os
from pathlib import Path
from tqdm import tqdm
import pickle as pkl
import argparse
import time
import torch
import sys, platform
from sklearn.neighbors import KDTree
from termcolor import colored
from pathlib import Path
from copy import deepcopy
from functools import reduce
np.seterr(divide='ignore', invalid='ignore')
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
def pcolor(string, color, on_color=None, attrs=None):
"""
Produces a colored string for printing
Parameters
----------
string : str
String that will be colored
color : str
Color to use
on_color : str
Background color to use
attrs : list of str
Different attributes for the string
Returns
-------
string: str
Colored string
"""
return colored(string, color, on_color, attrs)
def getCellCoordinates(points, voxelSize):
return (points / voxelSize).astype(np.int)
def getNumUniqueCells(cells):
M = cells.max() + 1
return np.unique(cells[:, 0] + M * cells[:, 1] + M ** 2 * cells[:, 2]).shape[0]
class Metric_mIoU():
def __init__(self,
save_dir='.',
num_classes=18,
use_lidar_mask=False,
use_image_mask=False,
):
self.class_names = ['others','barrier', 'bicycle', 'bus', 'car', 'construction_vehicle',
'motorcycle', 'pedestrian', 'traffic_cone', 'trailer', 'truck',
'driveable_surface', 'other_flat', 'sidewalk',
'terrain', 'manmade', 'vegetation','free']
self.save_dir = save_dir
self.use_lidar_mask = use_lidar_mask
self.use_image_mask = use_image_mask
self.num_classes = num_classes
self.point_cloud_range = [-40.0, -40.0, -1.0, 40.0, 40.0, 5.4]
self.occupancy_size = [0.4, 0.4, 0.4]
self.voxel_size = 0.4
self.occ_xdim = int((self.point_cloud_range[3] - self.point_cloud_range[0]) / self.occupancy_size[0])
self.occ_ydim = int((self.point_cloud_range[4] - self.point_cloud_range[1]) / self.occupancy_size[1])
self.occ_zdim = int((self.point_cloud_range[5] - self.point_cloud_range[2]) / self.occupancy_size[2])
self.voxel_num = self.occ_xdim * self.occ_ydim * self.occ_zdim
self.hist = np.zeros((self.num_classes, self.num_classes))
self.cnt = 0
def hist_info(self, n_cl, pred, gt):
"""
build confusion matrix
# empty classes:0
non-empty class: 0-16
free voxel class: 17
Args:
n_cl (int): num_classes_occupancy
pred (1-d array): pred_occupancy_label
gt (1-d array): gt_occupancu_label
Returns:
tuple:(hist, correctly number_predicted_labels, num_labelled_sample)
"""
assert pred.shape == gt.shape
k = (gt >= 0) & (gt < n_cl) # exclude 255
labeled = np.sum(k)
correct = np.sum((pred[k] == gt[k]))
return (
np.bincount(
n_cl * gt[k].astype(int) + pred[k].astype(int), minlength=n_cl ** 2
).reshape(n_cl, n_cl),
correct,
labeled,
)
def per_class_iu(self, hist):
return np.diag(hist) / (hist.sum(1) + hist.sum(0) - np.diag(hist))
def compute_mIoU(self, pred, label, n_classes):
hist = np.zeros((n_classes, n_classes))
new_hist, correct, labeled = self.hist_info(n_classes, pred.flatten(), label.flatten())
hist += new_hist
mIoUs = self.per_class_iu(hist)
# for ind_class in range(n_classes):
# print(str(round(mIoUs[ind_class] * 100, 2)))
# print('===> mIoU: ' + str(round(np.nanmean(mIoUs) * 100, 2)))
return round(np.nanmean(mIoUs) * 100, 2), hist
def add_batch(self,semantics_pred,semantics_gt,mask_lidar,mask_camera):
self.cnt += 1
if self.use_image_mask:
masked_semantics_gt = semantics_gt[mask_camera]
masked_semantics_pred = semantics_pred[mask_camera]
elif self.use_lidar_mask:
masked_semantics_gt = semantics_gt[mask_lidar]
masked_semantics_pred = semantics_pred[mask_lidar]
else:
masked_semantics_gt = semantics_gt
masked_semantics_pred = semantics_pred
# # pred = np.random.randint(low=0, high=17, size=masked_semantics.shape)
_, _hist = self.compute_mIoU(masked_semantics_pred, masked_semantics_gt, self.num_classes)
self.hist += _hist
def count_miou(self):
mIoU = self.per_class_iu(self.hist)
# assert cnt == num_samples, 'some samples are not included in the miou calculation'
print(f'===> per class IoU of {self.cnt} samples:')
for ind_class in range(self.num_classes-1):
print(f'===> {self.class_names[ind_class]} - IoU = ' + str(round(mIoU[ind_class] * 100, 2)))
print(f'===> mIoU of {self.cnt} samples: ' + str(round(np.nanmean(mIoU[:self.num_classes-1]) * 100, 2)))
# print(f'===> sample-wise averaged mIoU of {cnt} samples: ' + str(round(np.nanmean(mIoU_avg), 2)))
# return mIoU
class Metric_FScore():
def __init__(self,
leaf_size=10,
threshold_acc=0.6,
threshold_complete=0.6,
voxel_size=[0.4, 0.4, 0.4],
range=[-40, -40, -1, 40, 40, 5.4],
void=[17, 255],
use_lidar_mask=False,
use_image_mask=False, ) -> None:
self.leaf_size = leaf_size
self.threshold_acc = threshold_acc
self.threshold_complete = threshold_complete
self.voxel_size = voxel_size
self.range = range
self.void = void
self.use_lidar_mask = use_lidar_mask
self.use_image_mask = use_image_mask
self.cnt=0
self.tot_acc = 0.
self.tot_cmpl = 0.
self.tot_f1_mean = 0.
self.eps = 1e-8
def voxel2points(self, voxel):
# occIdx = torch.where(torch.logical_and(voxel != FREE, voxel != NOT_OBSERVED))
# if isinstance(voxel, np.ndarray): voxel = torch.from_numpy(voxel)
mask = np.logical_not(reduce(np.logical_or, [voxel == self.void[i] for i in range(len(self.void))]))
occIdx = np.where(mask)
points = np.concatenate((occIdx[0][:, None] * self.voxel_size[0] + self.voxel_size[0] / 2 + self.range[0], \
occIdx[1][:, None] * self.voxel_size[1] + self.voxel_size[1] / 2 + self.range[1], \
occIdx[2][:, None] * self.voxel_size[2] + self.voxel_size[2] / 2 + self.range[2]),
axis=1)
return points
def add_batch(self,semantics_pred,semantics_gt,mask_lidar,mask_camera ):
# for scene_token in tqdm(preds_dict.keys()):
self.cnt += 1
if self.use_image_mask:
semantics_gt[mask_camera == False] = 255
semantics_pred[mask_camera == False] = 255
elif self.use_lidar_mask:
semantics_gt[mask_lidar == False] = 255
semantics_pred[mask_lidar == False] = 255
else:
pass
ground_truth = self.voxel2points(semantics_gt)
prediction = self.voxel2points(semantics_pred)
if prediction.shape[0] == 0:
accuracy=0
completeness=0
fmean=0
else:
prediction_tree = KDTree(prediction, leaf_size=self.leaf_size)
ground_truth_tree = KDTree(ground_truth, leaf_size=self.leaf_size)
complete_distance, _ = prediction_tree.query(ground_truth)
complete_distance = complete_distance.flatten()
accuracy_distance, _ = ground_truth_tree.query(prediction)
accuracy_distance = accuracy_distance.flatten()
# evaluate completeness
complete_mask = complete_distance < self.threshold_complete
completeness = complete_mask.mean()
# evalute accuracy
accuracy_mask = accuracy_distance < self.threshold_acc
accuracy = accuracy_mask.mean()
fmean = 2.0 / (1 / (accuracy+self.eps) + 1 / (completeness+self.eps))
self.tot_acc += accuracy
self.tot_cmpl += completeness
self.tot_f1_mean += fmean
def count_fscore(self,):
base_color, attrs = 'red', ['bold', 'dark']
print(pcolor('\n######## F score: {} #######'.format(self.tot_f1_mean / self.cnt), base_color, attrs=attrs))
import os
from functools import reduce
import numpy as np
from sklearn.neighbors import KDTree
from termcolor import colored
np.seterr(divide='ignore', invalid='ignore')
os.environ['KMP_DUPLICATE_LIB_OK'] = 'TRUE'
def pcolor(string, color, on_color=None, attrs=None):
"""
Produces a colored string for printing
Parameters
----------
string : str
String that will be colored
color : str
Color to use
on_color : str
Background color to use
attrs : list of str
Different attributes for the string
Returns
-------
string: str
Colored string
"""
return colored(string, color, on_color, attrs)
def getCellCoordinates(points, voxelSize):
return (points / voxelSize).astype(np.int)
def getNumUniqueCells(cells):
M = cells.max() + 1
return np.unique(cells[:, 0] + M * cells[:, 1] + M ** 2 * cells[:, 2]).shape[0]
class Metric_mIoU():
def __init__(self,
save_dir='.',
num_classes=18,
use_lidar_mask=False,
use_image_mask=False,
):
self.class_names = ['others', 'barrier', 'bicycle', 'bus', 'car', 'construction_vehicle',
'motorcycle', 'pedestrian', 'traffic_cone', 'trailer', 'truck',
'driveable_surface', 'other_flat', 'sidewalk',
'terrain', 'manmade', 'vegetation', 'free']
self.save_dir = save_dir
self.use_lidar_mask = use_lidar_mask
self.use_image_mask = use_image_mask
self.num_classes = num_classes
self.point_cloud_range = [-40.0, -40.0, -1.0, 40.0, 40.0, 5.4]
self.occupancy_size = [0.4, 0.4, 0.4]
self.voxel_size = 0.4
self.occ_xdim = int((self.point_cloud_range[3] - self.point_cloud_range[0]) / self.occupancy_size[0])
self.occ_ydim = int((self.point_cloud_range[4] - self.point_cloud_range[1]) / self.occupancy_size[1])
self.occ_zdim = int((self.point_cloud_range[5] - self.point_cloud_range[2]) / self.occupancy_size[2])
self.voxel_num = self.occ_xdim * self.occ_ydim * self.occ_zdim
self.hist = np.zeros((self.num_classes, self.num_classes))
self.cnt = 0
def hist_info(self, n_cl, pred, gt):
"""
build confusion matrix
# empty classes:0
non-empty class: 0-16
free voxel class: 17
Args:
n_cl (int): num_classes_occupancy
pred (1-d array): pred_occupancy_label
gt (1-d array): gt_occupancu_label
Returns:
tuple:(hist, correctly number_predicted_labels, num_labelled_sample)
"""
assert pred.shape == gt.shape
k = (gt >= 0) & (gt < n_cl) # exclude 255
labeled = np.sum(k)
correct = np.sum((pred[k] == gt[k]))
return (
np.bincount(
n_cl * gt[k].astype(int) + pred[k].astype(int), minlength=n_cl ** 2
).reshape(n_cl, n_cl),
correct,
labeled,
)
def per_class_iu(self, hist):
return np.diag(hist) / (hist.sum(1) + hist.sum(0) - np.diag(hist))
def compute_mIoU(self, pred, label, n_classes):
hist = np.zeros((n_classes, n_classes))
new_hist, correct, labeled = self.hist_info(n_classes, pred.flatten(), label.flatten())
hist += new_hist
mIoUs = self.per_class_iu(hist)
# for ind_class in range(n_classes):
# print(str(round(mIoUs[ind_class] * 100, 2)))
# print('===> mIoU: ' + str(round(np.nanmean(mIoUs) * 100, 2)))
return round(np.nanmean(mIoUs) * 100, 2), hist
def add_batch(self, semantics_pred, semantics_gt, mask_lidar, mask_camera):
self.cnt += 1
if self.use_image_mask:
masked_semantics_gt = semantics_gt[mask_camera]
masked_semantics_pred = semantics_pred[mask_camera]
elif self.use_lidar_mask:
masked_semantics_gt = semantics_gt[mask_lidar]
masked_semantics_pred = semantics_pred[mask_lidar]
else:
masked_semantics_gt = semantics_gt
masked_semantics_pred = semantics_pred
# # pred = np.random.randint(low=0, high=17, size=masked_semantics.shape)
_, _hist = self.compute_mIoU(masked_semantics_pred, masked_semantics_gt, self.num_classes)
self.hist += _hist
def count_miou(self):
mIoU = self.per_class_iu(self.hist)
# assert cnt == num_samples, 'some samples are not included in the miou calculation'
print(f'===> per class IoU of {self.cnt} samples:')
for ind_class in range(self.num_classes - 1):
print(f'===> {self.class_names[ind_class]} - IoU = ' + str(round(mIoU[ind_class] * 100, 2)))
print(f'===> mIoU of {self.cnt} samples: ' + str(round(np.nanmean(mIoU[:self.num_classes - 1]) * 100, 2)))
# print(f'===> sample-wise averaged mIoU of {cnt} samples: ' + str(round(np.nanmean(mIoU_avg), 2)))
# return mIoU
class Metric_FScore():
def __init__(self,
leaf_size=10,
threshold_acc=0.6,
threshold_complete=0.6,
voxel_size=[0.4, 0.4, 0.4],
range=[-40, -40, -1, 40, 40, 5.4],
void=[17, 255],
use_lidar_mask=False,
use_image_mask=False, ) -> None:
self.leaf_size = leaf_size
self.threshold_acc = threshold_acc
self.threshold_complete = threshold_complete
self.voxel_size = voxel_size
self.range = range
self.void = void
self.use_lidar_mask = use_lidar_mask
self.use_image_mask = use_image_mask
self.cnt = 0
self.tot_acc = 0.
self.tot_cmpl = 0.
self.tot_f1_mean = 0.
self.eps = 1e-8
def voxel2points(self, voxel):
# occIdx = torch.where(torch.logical_and(voxel != FREE, voxel != NOT_OBSERVED))
# if isinstance(voxel, np.ndarray): voxel = torch.from_numpy(voxel)
mask = np.logical_not(reduce(np.logical_or, [voxel == self.void[i] for i in range(len(self.void))]))
occIdx = np.where(mask)
points = np.concatenate((occIdx[0][:, None] * self.voxel_size[0] + self.voxel_size[0] / 2 + self.range[0], \
occIdx[1][:, None] * self.voxel_size[1] + self.voxel_size[1] / 2 + self.range[1], \
occIdx[2][:, None] * self.voxel_size[2] + self.voxel_size[2] / 2 + self.range[2]),
axis=1)
return points
def add_batch(self, semantics_pred, semantics_gt, mask_lidar, mask_camera):
# for scene_token in tqdm(preds_dict.keys()):
self.cnt += 1
if self.use_image_mask:
semantics_gt[mask_camera == False] = 255
semantics_pred[mask_camera == False] = 255
elif self.use_lidar_mask:
semantics_gt[mask_lidar == False] = 255
semantics_pred[mask_lidar == False] = 255
else:
pass
ground_truth = self.voxel2points(semantics_gt)
prediction = self.voxel2points(semantics_pred)
if prediction.shape[0] == 0:
accuracy = 0
completeness = 0
fmean = 0
else:
prediction_tree = KDTree(prediction, leaf_size=self.leaf_size)
ground_truth_tree = KDTree(ground_truth, leaf_size=self.leaf_size)
complete_distance, _ = prediction_tree.query(ground_truth)
complete_distance = complete_distance.flatten()
accuracy_distance, _ = ground_truth_tree.query(prediction)
accuracy_distance = accuracy_distance.flatten()
# evaluate completeness
complete_mask = complete_distance < self.threshold_complete
completeness = complete_mask.mean()
# evalute accuracy
accuracy_mask = accuracy_distance < self.threshold_acc
accuracy = accuracy_mask.mean()
fmean = 2.0 / (1 / (accuracy + self.eps) + 1 / (completeness + self.eps))
self.tot_acc += accuracy
self.tot_cmpl += completeness
self.tot_f1_mean += fmean
def count_fscore(self, ):
base_color, attrs = 'red', ['bold', 'dark']
print(pcolor('\n######## F score: {} #######'.format(self.tot_f1_mean / self.cnt), base_color, attrs=attrs))
from .transform_3d import (
PadMultiViewImage, NormalizeMultiviewImage,
PhotoMetricDistortionMultiViewImage, CustomCollect3D, RandomScaleImageMultiViewImage)
from .formating import CustomDefaultFormatBundle3D
from .loading import LoadOccGTFromFile
from .transform_3d import (CustomCollect3D, NormalizeMultiviewImage,
PadMultiViewImage,
PhotoMetricDistortionMultiViewImage,
RandomScaleImageMultiViewImage)
__all__ = [
'PadMultiViewImage', 'NormalizeMultiviewImage',
'PhotoMetricDistortionMultiViewImage', 'CustomDefaultFormatBundle3D', 'CustomCollect3D', 'RandomScaleImageMultiViewImage'
]
\ No newline at end of file
'PadMultiViewImage', 'NormalizeMultiviewImage',
'PhotoMetricDistortionMultiViewImage', 'CustomDefaultFormatBundle3D', 'CustomCollect3D',
'RandomScaleImageMultiViewImage'
]
# Copyright (c) OpenMMLab. All rights reserved.
import numpy as np
from mmcv.parallel import DataContainer as DC
from mmdet3d.core.bbox import BaseInstance3DBoxes
from mmdet3d.core.points import BasePoints
from mmdet.datasets.builder import PIPELINES
from mmdet.datasets.pipelines import to_tensor
from mmdet3d.datasets.pipelines import DefaultFormatBundle3D
@PIPELINES.register_module()
class CustomDefaultFormatBundle3D(DefaultFormatBundle3D):
"""Default formatting bundle.
It simplifies the pipeline of formatting common fields for voxels,
including "proposals", "gt_bboxes", "gt_labels", "gt_masks" and
"gt_semantic_seg".
These fields are formatted as follows.
- img: (1)transpose, (2)to tensor, (3)to DataContainer (stack=True)
- proposals: (1)to tensor, (2)to DataContainer
- gt_bboxes: (1)to tensor, (2)to DataContainer
- gt_bboxes_ignore: (1)to tensor, (2)to DataContainer
- gt_labels: (1)to tensor, (2)to DataContainer
"""
def __call__(self, results):
"""Call function to transform and format common fields in results.
Args:
results (dict): Result dict contains the data to convert.
Returns:
dict: The result dict contains the data that is formatted with
default bundle.
"""
# Format 3D data
results = super(CustomDefaultFormatBundle3D, self).__call__(results)
results['gt_map_masks'] = DC(
to_tensor(results['gt_map_masks']), stack=True)
return results
\ No newline at end of file
# Copyright (c) OpenMMLab. All rights reserved.
from mmcv.parallel import DataContainer as DC
from mmdet3d.datasets.pipelines import DefaultFormatBundle3D
from mmdet.datasets.builder import PIPELINES
from mmdet.datasets.pipelines import to_tensor
@PIPELINES.register_module()
class CustomDefaultFormatBundle3D(DefaultFormatBundle3D):
"""Default formatting bundle.
It simplifies the pipeline of formatting common fields for voxels,
including "proposals", "gt_bboxes", "gt_labels", "gt_masks" and
"gt_semantic_seg".
These fields are formatted as follows.
- img: (1)transpose, (2)to tensor, (3)to DataContainer (stack=True)
- proposals: (1)to tensor, (2)to DataContainer
- gt_bboxes: (1)to tensor, (2)to DataContainer
- gt_bboxes_ignore: (1)to tensor, (2)to DataContainer
- gt_labels: (1)to tensor, (2)to DataContainer
"""
def __call__(self, results):
"""Call function to transform and format common fields in results.
Args:
results (dict): Result dict contains the data to convert.
Returns:
dict: The result dict contains the data that is formatted with
default bundle.
"""
# Format 3D data
results = super(CustomDefaultFormatBundle3D, self).__call__(results)
results['gt_map_masks'] = DC(
to_tensor(results['gt_map_masks']), stack=True)
return results
import numpy as np
from numpy import random
import mmcv
from mmdet.datasets.builder import PIPELINES
from mmcv.parallel import DataContainer as DC
import os
@PIPELINES.register_module()
class LoadOccGTFromFile(object):
"""Load multi channel images from a list of separate channel files.
Expects results['img_filename'] to be a list of filenames.
note that we read image in BGR style to align with opencv.imread
Args:
to_float32 (bool): Whether to convert the img to float32.
Defaults to False.
color_type (str): Color type of the file. Defaults to 'unchanged'.
"""
def __init__(
self,
data_root,
):
self.data_root = data_root
def __call__(self, results):
# print(results.keys())
occ_gt_path = results['occ_gt_path']
occ_gt_path = os.path.join(self.data_root,occ_gt_path)
occ_labels = np.load(occ_gt_path)
semantics = occ_labels['semantics']
mask_lidar = occ_labels['mask_lidar']
mask_camera = occ_labels['mask_camera']
results['voxel_semantics'] = semantics
results['mask_lidar'] = mask_lidar
results['mask_camera'] = mask_camera
return results
def __repr__(self):
"""str: Return a string that describes the module."""
return "{} (data_root={}')".format(
self.__class__.__name__, self.data_root)
\ No newline at end of file
import os
import numpy as np
from mmdet.datasets.builder import PIPELINES
@PIPELINES.register_module()
class LoadOccGTFromFile(object):
"""Load multi channel images from a list of separate channel files.
Expects results['img_filename'] to be a list of filenames.
note that we read image in BGR style to align with opencv.imread
Args:
to_float32 (bool): Whether to convert the img to float32.
Defaults to False.
color_type (str): Color type of the file. Defaults to 'unchanged'.
"""
def __init__(
self,
data_root,
):
self.data_root = data_root
def __call__(self, results):
# print(results.keys())
occ_gt_path = results['occ_gt_path']
occ_gt_path = os.path.join(self.data_root, occ_gt_path)
occ_labels = np.load(occ_gt_path)
semantics = occ_labels['semantics']
mask_lidar = occ_labels['mask_lidar']
mask_camera = occ_labels['mask_camera']
results['voxel_semantics'] = semantics
results['mask_lidar'] = mask_lidar
results['mask_camera'] = mask_camera
return results
def __repr__(self):
"""str: Return a string that describes the module."""
return "{} (data_root={}')".format(
self.__class__.__name__, self.data_root)
import numpy as np
from numpy import random
import mmcv
from mmdet.datasets.builder import PIPELINES
import numpy as np
from mmcv.parallel import DataContainer as DC
import os
from mmdet.datasets.builder import PIPELINES
from numpy import random
@PIPELINES.register_module()
......@@ -36,7 +33,7 @@ class PadMultiViewImage(object):
elif self.size_divisor is not None:
padded_img = [mmcv.impad_to_multiple(
img, self.size_divisor, pad_val=self.pad_val) for img in results['img']]
results['ori_shape'] = [img.shape for img in results['img']]
results['img'] = padded_img
results['img_shape'] = [img.shape for img in padded_img]
......@@ -78,7 +75,6 @@ class NormalizeMultiviewImage(object):
self.std = np.array(std, dtype=np.float32)
self.to_rgb = to_rgb
def __call__(self, results):
"""Call function to normalize images.
Args:
......@@ -140,12 +136,12 @@ class PhotoMetricDistortionMultiViewImage:
new_imgs = []
for img in imgs:
assert img.dtype == np.float32, \
'PhotoMetricDistortion needs the input image of dtype np.float32,'\
'PhotoMetricDistortion needs the input image of dtype np.float32,' \
' please set "to_float32=True" in "LoadImageFromFile" pipeline'
# random brightness
if random.randint(2):
delta = random.uniform(-self.brightness_delta,
self.brightness_delta)
self.brightness_delta)
img += delta
# mode == 0 --> do random contrast first
......@@ -154,7 +150,7 @@ class PhotoMetricDistortionMultiViewImage:
if mode == 1:
if random.randint(2):
alpha = random.uniform(self.contrast_lower,
self.contrast_upper)
self.contrast_upper)
img *= alpha
# convert color from BGR to HSV
......@@ -163,7 +159,7 @@ class PhotoMetricDistortionMultiViewImage:
# random saturation
if random.randint(2):
img[..., 1] *= random.uniform(self.saturation_lower,
self.saturation_upper)
self.saturation_upper)
# random hue
if random.randint(2):
......@@ -178,7 +174,7 @@ class PhotoMetricDistortionMultiViewImage:
if mode == 0:
if random.randint(2):
alpha = random.uniform(self.contrast_lower,
self.contrast_upper)
self.contrast_upper)
img *= alpha
# randomly swap channels
......@@ -199,7 +195,6 @@ class PhotoMetricDistortionMultiViewImage:
return repr_str
@PIPELINES.register_module()
class CustomCollect3D(object):
"""Collect data from the loader relevant to the specific task.
......@@ -247,7 +242,7 @@ class CustomCollect3D(object):
def __init__(self,
keys,
meta_keys=('filename', 'ori_shape', 'img_shape', 'lidar2img','ego2lidar',
meta_keys=('filename', 'ori_shape', 'img_shape', 'lidar2img', 'ego2lidar',
'depth2img', 'cam2img', 'pad_shape',
'scale_factor', 'flip', 'pcd_horizontal_flip',
'pcd_vertical_flip', 'box_mode_3d', 'box_type_3d',
......@@ -269,10 +264,10 @@ class CustomCollect3D(object):
- keys in ``self.keys``
- ``img_metas``
"""
data = {}
img_metas = {}
for key in self.meta_keys:
if key in results:
img_metas[key] = results[key]
......@@ -285,8 +280,7 @@ class CustomCollect3D(object):
def __repr__(self):
"""str: Return a string that describes the module."""
return self.__class__.__name__ + \
f'(keys={self.keys}, meta_keys={self.meta_keys})'
f'(keys={self.keys}, meta_keys={self.meta_keys})'
@PIPELINES.register_module()
......@@ -298,7 +292,7 @@ class RandomScaleImageMultiViewImage(object):
def __init__(self, scales=[]):
self.scales = scales
assert len(self.scales)==1
assert len(self.scales) == 1
def __call__(self, results):
"""Call function to pad images, masks, semantic segmentation maps.
......@@ -324,8 +318,7 @@ class RandomScaleImageMultiViewImage(object):
return results
def __repr__(self):
repr_str = self.__class__.__name__
repr_str += f'(size={self.scales}, '
return repr_str
\ No newline at end of file
return repr_str
from .group_sampler import DistributedGroupSampler
from .distributed_sampler import DistributedSampler
from .group_sampler import DistributedGroupSampler
from .sampler import SAMPLER, build_sampler
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment