【mmrotate】中dataloader加载DOTA数据集,可视化加载的数据
时间:2022年8月9日
mmortate和mmdetection在使用的时候有这样一个问题:
原始数据集加载后,并经过数据增强后,图片和对应标签被处理成什么样了并不能直观的看到。所以写个脚本可视化dataloader加载的DOTA数据集。
参考:
http://t.csdn.cn/LYypc
http://t.csdn.cn/meOlQ
/mmrotate/tools/misc/browse_dataset.py也有类似功能。
datasets的构建参考/mmrotate/tools/train.py
data_loaders的构建参考/mmrotate/mmrotate/apis/train.py
画框参考mmcv.imshow_det_bboxes()
注意:
datasets载入的数据就已经是数据增强后的了,已经是经过缩放、翻转、正则化、填充后的了。可以在配置文件中修改RResize值,看看载入后的图片尺寸是不是刚才修改的。
代码如下:
import argparse
import os
import mmcv
from mmcv import Config, DictAction, imdenormalize
from mmdet.datasets import build_dataloader
import torch.distributed as dist
from mmrotate.datasets import build_dataset
from mmdet.apis import init_random_seed, set_random_seed
import numpy as np
from mmcv.visualization import color_val
import cv2
def parse_args():
parser = argparse.ArgumentParser(description='Train a detector')
parser.add_argument('--config', default='./configs/oriented_rcnn/oriented_rcnn_r50_fpn_1x_dota_le90.py', help='train config file path')
parser.add_argument('--work-dir', help='the dir to save logs and models')
parser.add_argument(
'--resume-from', help='the checkpoint file to resume from')
parser.add_argument(
'--auto-resume',
action='store_true',
help='resume from the latest checkpoint automatically')
parser.add_argument(
'--no-validate',
action='store_true',
help='whether not to evaluate the checkpoint during training')
group_gpus = parser.add_mutually_exclusive_group()
group_gpus.add_argument(
'--gpus',
type=int,
help='number of gpus to use '
'(only applicable to non-distributed training)')
group_gpus.add_argument(
'--gpu-ids',
type=int,
nargs='+',
help='ids of gpus to use '
'(only applicable to non-distributed training)')
parser.add_argument('--seed', type=int, default=None, help='random seed')
parser.add_argument(
'--diff-seed',
action='store_true',
help='Whether or not set different seeds for different ranks')
parser.add_argument(
'--deterministic',
action='store_true',
help='whether to set deterministic options for CUDNN backend.')
parser.add_argument(
'--cfg-options',
nargs='+',
action=DictAction,
help='override some settings in the used config, the key-value pair '
'in xxx=yyy format will be merged into config file. If the value to '
'be overwritten is a list, it should be like key="[a,b]" or key=a,b '
'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" '
'Note that the quotation marks are necessary and that no white space '
'is allowed.')
parser.add_argument(
'--launcher',
choices=['none', 'pytorch', 'slurm', 'mpi'],
default='none',
help='job launcher')
parser.add_argument('--local_rank', type=int, default=0)
args = parser.parse_args()
if 'LOCAL_RANK' not in os.environ:
os.environ['LOCAL_RANK'] = str(args.local_rank)
return args
def main():
args = parse_args()
cfg = Config.fromfile(args.config)
'''
{'type': 'DOTADataset', 'ann_file': 'data/split_1024_dota1_0/trainval/annfiles/', 'img_prefix': 'data/split_1024_dota1_0/trainval/images/', 'pipeline': [{'type': 'LoadImageFromFile'}, {'type': 'LoadAnnotations', 'with_bbox': True}, {'type': 'RResize', 'img_scale': (1024, 1024)}, {'type': 'RRandomFlip', 'flip_ratio': [0.25, 0.25, 0.25], 'direction': ['horizontal', 'vertical', 'diagonal'], 'version': 'le90'}, {'type': 'Normalize', 'mean': [123.675, 116.28, 103.53], 'std': [58.395, 57.12, 57.375], 'to_rgb': True}, {'type': 'Pad', 'size_divisor': 32}, {'type': 'DefaultFormatBundle'}, {'type': 'Collect', 'keys': ['img', 'gt_bboxes', 'gt_labels']}], 'version': 'le90'}
'''
datasets = build_dataset(cfg.data.train)
print(datasets)
print('datasets build finish!')
runner_type = 'EpochBasedRunner' if 'runner' not in cfg else cfg.runner[
'type']
# set random seeds
seed = init_random_seed(args.seed)
seed = seed + dist.get_rank() if args.diff_seed else seed
set_random_seed(seed, deterministic=args.deterministic)
cfg.seed = seed
# set gpu_ids
if args.gpu_ids is not None:
cfg.gpu_ids = args.gpu_ids
else:
cfg.gpu_ids = range(1) if args.gpus is None else range(args.gpus)
data_loaders = build_dataloader(dataset=datasets,
samples_per_gpu=2,
workers_per_gpu=2,
num_gpus=len(cfg.gpu_ids),
dist=False,
seed=cfg.seed,
runner_type=runner_type,
persistent_workers=False
)
print('data_loaders build finish!')
for i, data_batch in enumerate(data_loaders): # data_batch ['img_metas', 'img', 'gt_bboxes', 'gt_labels']
img_metas_batch = data_batch['img_metas'].data[0] # len = 2
img_batch = data_batch['img'].data[0] # [2, 3, 1024, 1024]
gt_bboxes_batch = data_batch['gt_bboxes'].data[0] # ([n, 5], [n, 5]) = ([n, [x, y, w, h, angle]], [n, [x, y, w, h, angle]])
gt_labels_batch = data_batch['gt_labels'].data[0] # ([n], [n])
mean = np.array(cfg.img_norm_cfg['mean'])
std = np.array(cfg.img_norm_cfg['std'])
for j in range(len(img_metas_batch)):
ori_filename = str(img_metas_batch[j]['ori_filename'])
print(ori_filename)
bboxes = np.array(gt_bboxes_batch[j])
labels = np.array(gt_labels_batch[j])
img_hwc = np.transpose(img_batch[j].numpy(), [1, 2, 0])
img_numpy_float = imdenormalize(img_hwc, mean, std)
img_numpy_uint8 = np.array(img_numpy_float, np.uint8)
assert bboxes.ndim == 2
assert labels.ndim == 1
assert bboxes.shape[0] == labels.shape[0]
assert bboxes.shape[1] == 4 or bboxes.shape[1] == 5
img = np.ascontiguousarray(img_numpy_uint8)
score_thr = 0
bbox_color = 'green'
text_color = 'green'
class_names = None
font_scale = 0.5
if score_thr > 0:
assert bboxes.shape[1] == 5
scores = bboxes[:, -1]
inds = scores > score_thr
bboxes = bboxes[inds, :]
labels = labels[inds]
bbox_color = color_val(bbox_color)
text_color = color_val(text_color)
for bbox, label in zip(bboxes, labels):
bbox_int = bbox.astype(np.int32)
obb = [[bbox[0], bbox[1]], [bbox[2], bbox[3]], bbox[4]*57.2957]
obb = np.int0(cv2.boxPoints(obb))
cv2.drawContours(img, [obb], 0, bbox_color)
label_text = class_names[
label] if class_names is not None else f'cls {label}'
if len(bbox) > 4:
label_text += f'|{bbox[-1]:.02f}'
cv2.putText(img, label_text, (bbox_int[0], bbox_int[1] - 2),
cv2.FONT_HERSHEY_COMPLEX, font_scale, text_color)
mmcv.imwrite(img, ori_filename)
if i == 0:
break
if __name__ == '__main__':
main()
效果如下: