├── requirements ├── optional.txt ├── build.txt ├── mminstall.txt ├── runtime.txt ├── readthedocs.txt ├── docs.txt └── tests.txt ├── basic_patterns ├── hrsc │ ├── properties.txt │ └── 0.png ├── sku110k │ ├── properties.txt │ └── 0.png ├── dior │ ├── 0.png │ ├── 10.png │ ├── 11.png │ ├── 13.png │ ├── 14.png │ ├── 15.png │ ├── 16.png │ ├── 18.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ ├── 9.png │ └── properties.txt ├── dota │ ├── 0.png │ ├── 1.png │ ├── 10.png │ ├── 11.png │ ├── 12.png │ ├── 13.png │ ├── 14.png │ ├── 15.png │ ├── 16.png │ ├── 17.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ ├── 6.png │ ├── 7.png │ ├── 8.png │ ├── 9.png │ └── properties.txt └── fair │ ├── 0.png │ ├── 1.png │ ├── 10.png │ ├── 11.png │ ├── 12.png │ ├── 13.png │ ├── 14.png │ ├── 15.png │ ├── 16.png │ ├── 17.png │ ├── 18.png │ ├── 19.png │ ├── 2.png │ ├── 20.png │ ├── 21.png │ ├── 22.png │ ├── 23.png │ ├── 24.png │ ├── 25.png │ ├── 26.png │ ├── 27.png │ ├── 28.png │ ├── 29.png │ ├── 3.png │ ├── 30.png │ ├── 31.png │ ├── 32.png │ ├── 33.png │ ├── 4.png │ ├── 5.png │ ├── 6.png │ ├── 7.png │ ├── 8.png │ ├── 9.png │ └── properties.txt ├── resources ├── h2rbox.png ├── h2rbox_v2.png ├── point2rbox.png ├── whollywood.png └── point2rbox_v2.png ├── third_parties └── ted │ └── ted.pth ├── mmrotate ├── structures │ ├── __init__.py │ └── bbox │ │ └── __init__.py ├── version.py ├── models │ ├── necks │ │ └── __init__.py │ ├── backbones │ │ └── __init__.py │ ├── roi_heads │ │ ├── roi_extractors │ │ │ └── __init__.py │ │ ├── __init__.py │ │ └── bbox_heads │ │ │ └── __init__.py │ ├── layers │ │ └── __init__.py │ ├── task_modules │ │ ├── __init__.py │ │ ├── prior_generators │ │ │ ├── __init__.py │ │ │ └── anchor_generator.py │ │ ├── assigners │ │ │ └── __init__.py │ │ └── coders │ │ │ ├── __init__.py │ │ │ ├── delta_xywh_qbbox_coder.py │ │ │ └── delta_xywh_hbbox_coder.py │ ├── utils │ │ ├── __init__.py │ │ ├── ripool.py │ │ └── misc.py │ ├── __init__.py │ ├── detectors │ │ └── __init__.py │ ├── losses │ │ ├── __init__.py │ │ ├── h2rbox_v2_consistency_loss.py │ │ ├── spatial_border_loss.py │ │ └── h2rbox_consistency_loss.py │ └── dense_heads │ │ └── __init__.py ├── evaluation │ ├── functional │ │ └── __init__.py │ ├── __init__.py │ └── metrics │ │ └── __init__.py ├── apis │ └── __init__.py ├── visualization │ ├── __init__.py │ └── palette.py ├── testing │ └── __init__.py ├── utils │ ├── patch │ │ ├── __init__.py │ │ └── split.py │ ├── __init__.py │ ├── collect_env.py │ ├── misc.py │ └── setup_env.py ├── datasets │ ├── transforms │ │ ├── __init__.py │ │ └── loading.py │ └── __init__.py ├── __init__.py └── registry.py ├── requirements.txt ├── pyvenv.cfg ├── configs ├── h2rbox │ ├── h2rbox-le90_r50_fpn_adamw-1x_dota-ms.py │ ├── h2rbox-le90_r50_fpn_adamw-3x_dota.py │ ├── dotav2 │ │ └── h2rbox-le90_r50_fpn_adamw-3x_dotav2.py │ ├── dotav15 │ │ ├── h2rbox-le90_r50_fpn_adamw-3x_dotav15.py │ │ └── h2rbox-le90_r50_fpn_adamw-1x_dotav15.py │ └── h2rbox-le90_r50_fpn_adamw-1x_dota.py ├── _base_ │ ├── schedules │ │ ├── schedule_1x.py │ │ ├── schedule_3x.py │ │ ├── schedule_6x.py │ │ └── schedule_40e.py │ ├── default_runtime.py │ └── datasets │ │ ├── sardet100k.py │ │ ├── diatom.py │ │ ├── hrsc.py │ │ ├── rsdd.py │ │ ├── ssdd.py │ │ ├── hrsid.py │ │ ├── srsdd.py │ │ ├── sku110k.py │ │ ├── dior.py │ │ ├── dota_qbox.py │ │ ├── fair.py │ │ ├── dotav2.py │ │ ├── dotav15.py │ │ ├── dota.py │ │ ├── dota_ms.py │ │ ├── ocdpcb.py │ │ └── dota_coco.py ├── whollywood │ ├── whollywood-ms_rr-1x-dota-using-pseudo.py │ └── whollywood-ms_rr-1x-dota-p2r-pseudo.py ├── h2rbox_v2 │ ├── h2rbox_v2-le90_r50_fpn_rr-6x_hrsc.py │ ├── h2rbox_v2p-le90_r50_fpn-ms_rr_1x_dota.py │ ├── h2rbox_v2-le90_r50_fpn_ms_rr-1x_dota.py │ └── metafile.yml ├── point2rbox_v2 │ ├── point2rbox_v2-pseudo-generator-dota.py │ ├── point2rbox_v2-pseudo-generator-fair.py │ ├── point2rbox_v2-pseudo-generator-hrsc.py │ ├── point2rbox_v2-pseudo-generator-sku110k.py │ ├── point2rbox_v2-pseudo-generator-dior.py │ ├── rotated-fcos-1x-dota-using-pseudo.py │ ├── rotated-fcos-1x-fair-using-pseudo.py │ ├── rotated-fcos-1x-sku110k-using-pseudo.py │ ├── rotated-fcos-1x-dior-using-pseudo.py │ ├── README.md │ └── point2rbox_v2-1x-sku110k.py └── point2rbox │ └── metafile.yml ├── setup.cfg ├── tools ├── data │ ├── fair │ │ ├── split │ │ │ └── split_configs │ │ │ │ ├── ss_test.json │ │ │ │ ├── ss_val.json │ │ │ │ ├── ss_train.json │ │ │ │ └── ss_trainval.json │ │ └── README.md │ ├── dota │ │ ├── split │ │ │ └── split_configs │ │ │ │ ├── ss_test.json │ │ │ │ ├── ms_test.json │ │ │ │ ├── ss_val.json │ │ │ │ ├── ss_train.json │ │ │ │ ├── ms_val.json │ │ │ │ ├── ms_train.json │ │ │ │ ├── ms_trainval.json │ │ │ │ └── ss_trainval.json │ │ └── README.md │ ├── README.md │ ├── srsdd │ │ └── README.md │ ├── hrsid │ │ └── README.md │ ├── rsdd │ │ └── README.md │ ├── ssdd │ │ └── README.md │ ├── hrsc │ │ └── README.md │ └── dior │ │ └── README.md ├── dist_train.sh ├── dist_test.sh ├── slurm_test.sh ├── slurm_train.sh ├── misc │ └── print_config.py ├── model_converters │ └── publish_model.py └── analysis_tools │ ├── get_flops.py │ └── browse_dataset.py └── .gitignore /requirements/optional.txt: -------------------------------------------------------------------------------- 1 | imagecorruptions 2 | scikit-learn 3 | scipy 4 | -------------------------------------------------------------------------------- /basic_patterns/hrsc/properties.txt: -------------------------------------------------------------------------------- 1 | { 2 | 'ship': (240, 60, 0.8, 1.0), 3 | } 4 | -------------------------------------------------------------------------------- /basic_patterns/sku110k/properties.txt: -------------------------------------------------------------------------------- 1 | { 2 | 'object': (40, 25, 0.4, 0.4) 3 | } 4 | -------------------------------------------------------------------------------- /requirements/build.txt: -------------------------------------------------------------------------------- 1 | # These must be installed before building mmrotate 2 | cython 3 | numpy 4 | -------------------------------------------------------------------------------- /requirements/mminstall.txt: -------------------------------------------------------------------------------- 1 | mmcv>=2.0.0rc2,<2.1.0 2 | mmdet>=3.0.0rc2,<3.2.0 3 | mmengine>= 0.1.0 4 | -------------------------------------------------------------------------------- /requirements/runtime.txt: -------------------------------------------------------------------------------- 1 | matplotlib 2 | numpy 3 | pycocotools 4 | six 5 | terminaltables 6 | torch 7 | -------------------------------------------------------------------------------- /resources/h2rbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/resources/h2rbox.png -------------------------------------------------------------------------------- /resources/h2rbox_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/resources/h2rbox_v2.png -------------------------------------------------------------------------------- /resources/point2rbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/resources/point2rbox.png -------------------------------------------------------------------------------- /resources/whollywood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/resources/whollywood.png -------------------------------------------------------------------------------- /basic_patterns/dior/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dior/0.png -------------------------------------------------------------------------------- /basic_patterns/dior/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dior/10.png -------------------------------------------------------------------------------- /basic_patterns/dior/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dior/11.png -------------------------------------------------------------------------------- /basic_patterns/dior/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dior/13.png -------------------------------------------------------------------------------- /basic_patterns/dior/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dior/14.png -------------------------------------------------------------------------------- /basic_patterns/dior/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dior/15.png -------------------------------------------------------------------------------- /basic_patterns/dior/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dior/16.png -------------------------------------------------------------------------------- /basic_patterns/dior/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dior/18.png -------------------------------------------------------------------------------- /basic_patterns/dior/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dior/2.png -------------------------------------------------------------------------------- /basic_patterns/dior/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dior/3.png -------------------------------------------------------------------------------- /basic_patterns/dior/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dior/4.png -------------------------------------------------------------------------------- /basic_patterns/dior/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dior/5.png -------------------------------------------------------------------------------- /basic_patterns/dior/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dior/9.png -------------------------------------------------------------------------------- /basic_patterns/dota/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/0.png -------------------------------------------------------------------------------- /basic_patterns/dota/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/1.png -------------------------------------------------------------------------------- /basic_patterns/dota/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/10.png -------------------------------------------------------------------------------- /basic_patterns/dota/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/11.png -------------------------------------------------------------------------------- /basic_patterns/dota/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/12.png -------------------------------------------------------------------------------- /basic_patterns/dota/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/13.png -------------------------------------------------------------------------------- /basic_patterns/dota/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/14.png -------------------------------------------------------------------------------- /basic_patterns/dota/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/15.png -------------------------------------------------------------------------------- /basic_patterns/dota/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/16.png -------------------------------------------------------------------------------- /basic_patterns/dota/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/17.png -------------------------------------------------------------------------------- /basic_patterns/dota/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/2.png -------------------------------------------------------------------------------- /basic_patterns/dota/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/3.png -------------------------------------------------------------------------------- /basic_patterns/dota/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/4.png -------------------------------------------------------------------------------- /basic_patterns/dota/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/5.png -------------------------------------------------------------------------------- /basic_patterns/dota/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/6.png -------------------------------------------------------------------------------- /basic_patterns/dota/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/7.png -------------------------------------------------------------------------------- /basic_patterns/dota/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/8.png -------------------------------------------------------------------------------- /basic_patterns/dota/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/dota/9.png -------------------------------------------------------------------------------- /basic_patterns/fair/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/0.png -------------------------------------------------------------------------------- /basic_patterns/fair/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/1.png -------------------------------------------------------------------------------- /basic_patterns/fair/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/10.png -------------------------------------------------------------------------------- /basic_patterns/fair/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/11.png -------------------------------------------------------------------------------- /basic_patterns/fair/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/12.png -------------------------------------------------------------------------------- /basic_patterns/fair/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/13.png -------------------------------------------------------------------------------- /basic_patterns/fair/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/14.png -------------------------------------------------------------------------------- /basic_patterns/fair/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/15.png -------------------------------------------------------------------------------- /basic_patterns/fair/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/16.png -------------------------------------------------------------------------------- /basic_patterns/fair/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/17.png -------------------------------------------------------------------------------- /basic_patterns/fair/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/18.png -------------------------------------------------------------------------------- /basic_patterns/fair/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/19.png -------------------------------------------------------------------------------- /basic_patterns/fair/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/2.png -------------------------------------------------------------------------------- /basic_patterns/fair/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/20.png -------------------------------------------------------------------------------- /basic_patterns/fair/21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/21.png -------------------------------------------------------------------------------- /basic_patterns/fair/22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/22.png -------------------------------------------------------------------------------- /basic_patterns/fair/23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/23.png -------------------------------------------------------------------------------- /basic_patterns/fair/24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/24.png -------------------------------------------------------------------------------- /basic_patterns/fair/25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/25.png -------------------------------------------------------------------------------- /basic_patterns/fair/26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/26.png -------------------------------------------------------------------------------- /basic_patterns/fair/27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/27.png -------------------------------------------------------------------------------- /basic_patterns/fair/28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/28.png -------------------------------------------------------------------------------- /basic_patterns/fair/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/29.png -------------------------------------------------------------------------------- /basic_patterns/fair/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/3.png -------------------------------------------------------------------------------- /basic_patterns/fair/30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/30.png -------------------------------------------------------------------------------- /basic_patterns/fair/31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/31.png -------------------------------------------------------------------------------- /basic_patterns/fair/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/32.png -------------------------------------------------------------------------------- /basic_patterns/fair/33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/33.png -------------------------------------------------------------------------------- /basic_patterns/fair/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/4.png -------------------------------------------------------------------------------- /basic_patterns/fair/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/5.png -------------------------------------------------------------------------------- /basic_patterns/fair/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/6.png -------------------------------------------------------------------------------- /basic_patterns/fair/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/7.png -------------------------------------------------------------------------------- /basic_patterns/fair/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/8.png -------------------------------------------------------------------------------- /basic_patterns/fair/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/fair/9.png -------------------------------------------------------------------------------- /basic_patterns/hrsc/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/hrsc/0.png -------------------------------------------------------------------------------- /third_parties/ted/ted.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/third_parties/ted/ted.pth -------------------------------------------------------------------------------- /basic_patterns/sku110k/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/basic_patterns/sku110k/0.png -------------------------------------------------------------------------------- /resources/point2rbox_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisionXLab/point2rbox-v2/HEAD/resources/point2rbox_v2.png -------------------------------------------------------------------------------- /requirements/readthedocs.txt: -------------------------------------------------------------------------------- 1 | e2cnn 2 | mmcv>=2.0.0rc2 3 | mmdet>=3.0.0rc2 4 | mmengine>=0.1.0 5 | torch 6 | torchvision 7 | -------------------------------------------------------------------------------- /mmrotate/structures/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .bbox import * # noqa: F401, F403 3 | -------------------------------------------------------------------------------- /mmrotate/version.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | 3 | __version__ = '1.0.0rc1' 4 | short_version = __version__ 5 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | -r requirements/build.txt 2 | -r requirements/optional.txt 3 | -r requirements/runtime.txt 4 | -r requirements/tests.txt 5 | -------------------------------------------------------------------------------- /mmrotate/models/necks/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .re_fpn import ReFPN 3 | 4 | __all__ = ['ReFPN'] 5 | -------------------------------------------------------------------------------- /mmrotate/models/backbones/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .re_resnet import ReResNet 3 | 4 | __all__ = ['ReResNet'] 5 | -------------------------------------------------------------------------------- /mmrotate/evaluation/functional/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .mean_ap import eval_rbbox_map 3 | 4 | __all__ = ['eval_rbbox_map'] 5 | -------------------------------------------------------------------------------- /mmrotate/evaluation/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .functional import * # noqa: F401,F403 3 | from .metrics import * # noqa: F401,F403 4 | -------------------------------------------------------------------------------- /mmrotate/apis/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .inference import inference_detector_by_patches 3 | 4 | __all__ = ['inference_detector_by_patches'] 5 | -------------------------------------------------------------------------------- /mmrotate/models/roi_heads/roi_extractors/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .rotate_single_level_roi_extractor import RotatedSingleRoIExtractor 3 | 4 | __all__ = ['RotatedSingleRoIExtractor'] 5 | -------------------------------------------------------------------------------- /mmrotate/visualization/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .local_visualizer import RotLocalVisualizer 3 | from .palette import get_palette 4 | 5 | __all__ = ['get_palette', 'RotLocalVisualizer'] 6 | -------------------------------------------------------------------------------- /mmrotate/models/layers/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .align import FRM, AlignConv, DCNAlignModule, PseudoAlignModule 3 | 4 | __all__ = ['FRM', 'AlignConv', 'DCNAlignModule', 'PseudoAlignModule'] 5 | -------------------------------------------------------------------------------- /mmrotate/testing/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from ._utils import demo_mm_inputs, demo_mm_proposals, get_detector_cfg 3 | 4 | __all__ = ['get_detector_cfg', 'demo_mm_inputs', 'demo_mm_proposals'] 5 | -------------------------------------------------------------------------------- /mmrotate/models/task_modules/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .assigners import * # noqa: F401,F403 3 | from .coders import * # noqa: F401,F403 4 | from .prior_generators import * # noqa: F401,F403 5 | -------------------------------------------------------------------------------- /requirements/docs.txt: -------------------------------------------------------------------------------- 1 | docutils==0.16.0 2 | myst-parser 3 | -e git+https://github.com/open-mmlab/pytorch_sphinx_theme.git#egg=pytorch_sphinx_theme 4 | sphinx==4.0.2 5 | sphinx-copybutton 6 | sphinx_markdown_tables 7 | sphinx_rtd_theme==0.5.2 8 | -------------------------------------------------------------------------------- /pyvenv.cfg: -------------------------------------------------------------------------------- 1 | home = /usr/bin 2 | implementation = CPython 3 | version_info = 3.10.12.final.0 4 | virtualenv = 20.24.5 5 | include-system-site-packages = false 6 | base-prefix = /usr 7 | base-exec-prefix = /usr 8 | base-executable = /usr/bin/python3 9 | -------------------------------------------------------------------------------- /mmrotate/utils/patch/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .merge_results import merge_results_by_nms 3 | from .split import get_multiscale_patch, slide_window 4 | 5 | __all__ = ['merge_results_by_nms', 'get_multiscale_patch', 'slide_window'] 6 | -------------------------------------------------------------------------------- /mmrotate/evaluation/metrics/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .dota_metric import DOTAMetric 3 | from .fair_metric import FAIRMetric 4 | from .rotated_coco_metric import RotatedCocoMetric 5 | 6 | __all__ = ['DOTAMetric', 'FAIRMetric', 'RotatedCocoMetric'] 7 | -------------------------------------------------------------------------------- /mmrotate/models/task_modules/prior_generators/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .anchor_generator import (FakeRotatedAnchorGenerator, 3 | PseudoRotatedAnchorGenerator) 4 | 5 | __all__ = ['PseudoRotatedAnchorGenerator', 'FakeRotatedAnchorGenerator'] 6 | -------------------------------------------------------------------------------- /mmrotate/models/roi_heads/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .bbox_heads import RotatedShared2FCBBoxHead 3 | from .gv_ratio_roi_head import GVRatioRoIHead 4 | from .roi_extractors import RotatedSingleRoIExtractor 5 | 6 | __all__ = [ 7 | 'RotatedShared2FCBBoxHead', 'RotatedSingleRoIExtractor', 'GVRatioRoIHead' 8 | ] 9 | -------------------------------------------------------------------------------- /mmrotate/models/roi_heads/bbox_heads/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .convfc_rbbox_head import RotatedShared2FCBBoxHead 3 | from .h2rbox_v2_convfc_bbox_head import H2RBoxV2Shared2FCBBoxHead 4 | from .gv_bbox_head import GVBBoxHead 5 | 6 | __all__ = ['RotatedShared2FCBBoxHead', 'GVBBoxHead', 'H2RBoxV2Shared2FCBBoxHead'] 7 | -------------------------------------------------------------------------------- /configs/h2rbox/h2rbox-le90_r50_fpn_adamw-1x_dota-ms.py: -------------------------------------------------------------------------------- 1 | _base_ = './h2rbox-le90_r50_fpn_adamw-1x_dota.py' 2 | data_root = '/data/nas/dataset_share/DOTA/split_ms_dota1_0/' 3 | 4 | train_dataloader = dict(dataset=dict(data_root=data_root)) 5 | val_dataloader = dict(dataset=dict(data_root=data_root)) 6 | test_dataloader = dict(dataset=dict(data_root=data_root)) 7 | -------------------------------------------------------------------------------- /requirements/tests.txt: -------------------------------------------------------------------------------- 1 | asynctest 2 | codecov 3 | coverage 4 | cython 5 | -e git+https://github.com/QUVA-Lab/e2cnn.git#egg=e2cnn 6 | flake8 7 | interrogate 8 | isort==4.3.21 9 | # Note: used for kwarray.group_items, this may be ported to mmcv in the future. 10 | kwarray 11 | matplotlib 12 | parameterized 13 | pytest 14 | scikit-learn 15 | ubelt 16 | wheel 17 | xdoctest>=0.10.0 18 | yapf 19 | -------------------------------------------------------------------------------- /mmrotate/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .collect_env import collect_env 3 | from .misc import get_test_pipeline_cfg 4 | from .patch import get_multiscale_patch, merge_results_by_nms, slide_window 5 | from .setup_env import register_all_modules 6 | 7 | __all__ = [ 8 | 'collect_env', 'register_all_modules', 'get_test_pipeline_cfg', 9 | 'get_multiscale_patch', 'merge_results_by_nms', 'slide_window' 10 | ] 11 | -------------------------------------------------------------------------------- /mmrotate/models/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .misc import (convex_overlaps, get_num_level_anchors_inside, 3 | levels_to_images, points_center_pts) 4 | from .orconv import ORConv2d 5 | from .ripool import RotationInvariantPooling 6 | 7 | __all__ = [ 8 | 'ORConv2d', 'RotationInvariantPooling', 'get_num_level_anchors_inside', 9 | 'points_center_pts', 'levels_to_images', 'convex_overlaps' 10 | ] 11 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [isort] 2 | line_length = 79 3 | multi_line_output = 0 4 | known_standard_library = setuptools 5 | known_first_party = mmrotate 6 | known_third_party = 7 | no_lines_before = STDLIB,LOCALFOLDER 8 | default_section = THIRDPARTY 9 | 10 | [yapf] 11 | BASED_ON_STYLE = pep8 12 | BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF = true 13 | SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN = true 14 | 15 | [codespell] 16 | skip = *.ipynb 17 | quiet-level = 3 18 | ignore-words-list = DOTA,dota,alse, warmup 19 | -------------------------------------------------------------------------------- /mmrotate/models/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .backbones import * # noqa: F401, F403 3 | from .dense_heads import * # noqa: F401, F403 4 | from .detectors import * # noqa: F401, F403 5 | from .layers import * # noqa: F401, F403 6 | from .losses import * # noqa: F401, F403 7 | from .necks import * # noqa: F401, F403 8 | from .roi_heads import * # noqa: F401, F403 9 | from .task_modules import * # noqa: F401,F403 10 | from .utils import * # noqa: F401, F403 11 | -------------------------------------------------------------------------------- /tools/data/fair/split/split_configs/ss_test.json: -------------------------------------------------------------------------------- 1 | { 2 | "nproc": 10, 3 | "img_dirs": [ 4 | "../data/FAIR1M/test/images/" 5 | ], 6 | "ann_dirs": null, 7 | "sizes": [ 8 | 1024 9 | ], 10 | "gaps": [ 11 | 200 12 | ], 13 | "rates": [ 14 | 1.5 15 | ], 16 | "img_rate_thr": 0.6, 17 | "iof_thr": 0.7, 18 | "no_padding": false, 19 | "padding_value": [ 20 | 104, 21 | 116, 22 | 124 23 | ], 24 | "save_dir": "data/split_ss_fair/test/", 25 | "save_ext": ".png" 26 | } -------------------------------------------------------------------------------- /tools/data/dota/split/split_configs/ss_test.json: -------------------------------------------------------------------------------- 1 | { 2 | "nproc": 10, 3 | "img_dirs": [ 4 | "../../Data/DOTA/test/images-v2.0/" 5 | ], 6 | "ann_dirs": null, 7 | "sizes": [ 8 | 1024 9 | ], 10 | "gaps": [ 11 | 200 12 | ], 13 | "rates": [ 14 | 1.0 15 | ], 16 | "img_rate_thr": 0.6, 17 | "iof_thr": 0.7, 18 | "no_padding": false, 19 | "padding_value": [ 20 | 104, 21 | 116, 22 | 124 23 | ], 24 | "save_dir": "data/split_ss_dota2_0/test/", 25 | "save_ext": ".png" 26 | } -------------------------------------------------------------------------------- /tools/data/dota/split/split_configs/ms_test.json: -------------------------------------------------------------------------------- 1 | { 2 | "nproc": 10, 3 | "img_dirs": [ 4 | "data/DOTA/test/images/" 5 | ], 6 | "ann_dirs": null, 7 | "sizes": [ 8 | 1024 9 | ], 10 | "gaps": [ 11 | 500 12 | ], 13 | "rates": [ 14 | 0.5, 15 | 1.0, 16 | 1.5 17 | ], 18 | "img_rate_thr": 0.6, 19 | "iof_thr": 0.7, 20 | "no_padding": false, 21 | "padding_value": [ 22 | 104, 23 | 116, 24 | 124 25 | ], 26 | "save_dir": "data/split_ms_dota/test/", 27 | "save_ext": ".png" 28 | } 29 | -------------------------------------------------------------------------------- /tools/dist_train.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | CONFIG=$1 4 | GPUS=$2 5 | NNODES=${NNODES:-1} 6 | NODE_RANK=${NODE_RANK:-0} 7 | PORT=${PORT:-29500} 8 | MASTER_ADDR=${MASTER_ADDR:-"127.0.0.1"} 9 | 10 | PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \ 11 | python -m torch.distributed.launch \ 12 | --nnodes=$NNODES \ 13 | --node_rank=$NODE_RANK \ 14 | --master_addr=$MASTER_ADDR \ 15 | --nproc_per_node=$GPUS \ 16 | --master_port=$PORT \ 17 | $(dirname "$0")/train.py \ 18 | $CONFIG \ 19 | --launcher pytorch ${@:3} 20 | -------------------------------------------------------------------------------- /tools/data/dota/split/split_configs/ss_val.json: -------------------------------------------------------------------------------- 1 | { 2 | "nproc": 10, 3 | "img_dirs": [ 4 | "data/DOTA/val/images/" 5 | ], 6 | "ann_dirs": [ 7 | "data/DOTA/val/labelTxt/" 8 | ], 9 | "sizes": [ 10 | 1024 11 | ], 12 | "gaps": [ 13 | 200 14 | ], 15 | "rates": [ 16 | 1.0 17 | ], 18 | "img_rate_thr": 0.6, 19 | "iof_thr": 0.7, 20 | "no_padding": false, 21 | "padding_value": [ 22 | 104, 23 | 116, 24 | 124 25 | ], 26 | "save_dir": "data/split_ss_dota/val/", 27 | "save_ext": ".png" 28 | } 29 | -------------------------------------------------------------------------------- /tools/data/fair/split/split_configs/ss_val.json: -------------------------------------------------------------------------------- 1 | { 2 | "nproc": 10, 3 | "img_dirs": [ 4 | "../data/FAIR1M/val/images/" 5 | ], 6 | "ann_dirs": [ 7 | "../data/FAIR1M/val/labelXml/" 8 | ], 9 | "sizes": [ 10 | 1024 11 | ], 12 | "gaps": [ 13 | 200 14 | ], 15 | "rates": [ 16 | 1.5 17 | ], 18 | "img_rate_thr": 0.6, 19 | "iof_thr": 0.7, 20 | "no_padding": false, 21 | "padding_value": [ 22 | 104, 23 | 116, 24 | 124 25 | ], 26 | "save_dir": "data/split_ss_fair/val/", 27 | "save_ext": ".png" 28 | } -------------------------------------------------------------------------------- /tools/data/dota/split/split_configs/ss_train.json: -------------------------------------------------------------------------------- 1 | { 2 | "nproc": 10, 3 | "img_dirs": [ 4 | "data/DOTA/train/images/" 5 | ], 6 | "ann_dirs": [ 7 | "data/DOTA/train/labelTxt/" 8 | ], 9 | "sizes": [ 10 | 1024 11 | ], 12 | "gaps": [ 13 | 200 14 | ], 15 | "rates": [ 16 | 1.0 17 | ], 18 | "img_rate_thr": 0.6, 19 | "iof_thr": 0.7, 20 | "no_padding": false, 21 | "padding_value": [ 22 | 104, 23 | 116, 24 | 124 25 | ], 26 | "save_dir": "data/split_ss_dota/train/", 27 | "save_ext": ".png" 28 | } 29 | -------------------------------------------------------------------------------- /tools/data/fair/split/split_configs/ss_train.json: -------------------------------------------------------------------------------- 1 | { 2 | "nproc": 10, 3 | "img_dirs": [ 4 | "../data/FAIR1M/train/images/" 5 | ], 6 | "ann_dirs": [ 7 | "../data/FAIR1M/train/labelXml/" 8 | ], 9 | "sizes": [ 10 | 1024 11 | ], 12 | "gaps": [ 13 | 200 14 | ], 15 | "rates": [ 16 | 1.5 17 | ], 18 | "img_rate_thr": 0.6, 19 | "iof_thr": 0.7, 20 | "no_padding": false, 21 | "padding_value": [ 22 | 104, 23 | 116, 24 | 124 25 | ], 26 | "save_dir": "data/split_ss_fair/train/", 27 | "save_ext": ".png" 28 | } -------------------------------------------------------------------------------- /tools/data/dota/split/split_configs/ms_val.json: -------------------------------------------------------------------------------- 1 | { 2 | "nproc": 10, 3 | "img_dirs": [ 4 | "data/DOTA/val/images/" 5 | ], 6 | "ann_dirs": [ 7 | "data/DOTA/val/labelTxt/" 8 | ], 9 | "sizes": [ 10 | 1024 11 | ], 12 | "gaps": [ 13 | 500 14 | ], 15 | "rates": [ 16 | 0.5, 17 | 1.0, 18 | 1.5 19 | ], 20 | "img_rate_thr": 0.6, 21 | "iof_thr": 0.7, 22 | "no_padding": false, 23 | "padding_value": [ 24 | 104, 25 | 116, 26 | 124 27 | ], 28 | "save_dir": "data/split_ms_dota/val/", 29 | "save_ext": ".png" 30 | } 31 | -------------------------------------------------------------------------------- /configs/h2rbox/h2rbox-le90_r50_fpn_adamw-3x_dota.py: -------------------------------------------------------------------------------- 1 | _base_ = './h2rbox-le90_r50_fpn_adamw-1x_dota.py' 2 | 3 | # training schedule for 3x 4 | train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=36, val_interval=12) 5 | 6 | param_scheduler = [ 7 | dict( 8 | type='LinearLR', 9 | start_factor=1.0 / 3, 10 | by_epoch=False, 11 | begin=0, 12 | end=500), 13 | dict( 14 | type='MultiStepLR', 15 | begin=0, 16 | end=36, 17 | by_epoch=True, 18 | milestones=[24, 33], 19 | gamma=0.1) 20 | ] 21 | -------------------------------------------------------------------------------- /tools/data/dota/split/split_configs/ms_train.json: -------------------------------------------------------------------------------- 1 | { 2 | "nproc": 10, 3 | "img_dirs": [ 4 | "data/DOTA/train/images/" 5 | ], 6 | "ann_dirs": [ 7 | "data/DOTA/train/labelTxt/" 8 | ], 9 | "sizes": [ 10 | 1024 11 | ], 12 | "gaps": [ 13 | 500 14 | ], 15 | "rates": [ 16 | 0.5, 17 | 1.0, 18 | 1.5 19 | ], 20 | "img_rate_thr": 0.6, 21 | "iof_thr": 0.7, 22 | "no_padding": false, 23 | "padding_value": [ 24 | 104, 25 | 116, 26 | 124 27 | ], 28 | "save_dir": "data/split_ms_dota/train/", 29 | "save_ext": ".png" 30 | } 31 | -------------------------------------------------------------------------------- /configs/h2rbox/dotav2/h2rbox-le90_r50_fpn_adamw-3x_dotav2.py: -------------------------------------------------------------------------------- 1 | _base_ = './h2rbox-le90_r50_fpn_adamw-1x_dotav2.py' 2 | 3 | # training schedule for 3x 4 | train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=36, val_interval=12) 5 | 6 | param_scheduler = [ 7 | dict( 8 | type='LinearLR', 9 | start_factor=1.0 / 3, 10 | by_epoch=False, 11 | begin=0, 12 | end=500), 13 | dict( 14 | type='MultiStepLR', 15 | begin=0, 16 | end=36, 17 | by_epoch=True, 18 | milestones=[24, 33], 19 | gamma=0.1) 20 | ] 21 | -------------------------------------------------------------------------------- /mmrotate/utils/collect_env.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from mmengine.utils import get_git_hash 3 | from mmengine.utils.dl_utils import collect_env as collect_base_env 4 | 5 | import mmrotate 6 | 7 | 8 | def collect_env(): 9 | """Collect environment information.""" 10 | env_info = collect_base_env() 11 | env_info['MMRotate'] = ( 12 | mmrotate.__version__ + '+' + get_git_hash(digits=7)) 13 | return env_info 14 | 15 | 16 | if __name__ == '__main__': 17 | for name, val in collect_env().items(): 18 | print(f'{name}: {val}') 19 | -------------------------------------------------------------------------------- /tools/dist_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | CONFIG=$1 4 | CHECKPOINT=$2 5 | GPUS=$3 6 | NNODES=${NNODES:-1} 7 | NODE_RANK=${NODE_RANK:-0} 8 | PORT=${PORT:-29500} 9 | MASTER_ADDR=${MASTER_ADDR:-"127.0.0.1"} 10 | 11 | PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \ 12 | python -m torch.distributed.launch \ 13 | --nnodes=$NNODES \ 14 | --node_rank=$NODE_RANK \ 15 | --master_addr=$MASTER_ADDR \ 16 | --nproc_per_node=$GPUS \ 17 | --master_port=$PORT \ 18 | $(dirname "$0")/test.py \ 19 | $CONFIG \ 20 | $CHECKPOINT \ 21 | --launcher pytorch \ 22 | ${@:4} 23 | -------------------------------------------------------------------------------- /configs/h2rbox/dotav15/h2rbox-le90_r50_fpn_adamw-3x_dotav15.py: -------------------------------------------------------------------------------- 1 | _base_ = './h2rbox-le90_r50_fpn_adamw-1x_dotav15.py' 2 | 3 | # training schedule for 3x 4 | train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=36, val_interval=12) 5 | 6 | param_scheduler = [ 7 | dict( 8 | type='LinearLR', 9 | start_factor=1.0 / 3, 10 | by_epoch=False, 11 | begin=0, 12 | end=500), 13 | dict( 14 | type='MultiStepLR', 15 | begin=0, 16 | end=36, 17 | by_epoch=True, 18 | milestones=[24, 33], 19 | gamma=0.1) 20 | ] 21 | -------------------------------------------------------------------------------- /tools/data/fair/README.md: -------------------------------------------------------------------------------- 1 | # Preparing FAIR Dataset 2 | 3 | ``` 4 | @article{sun2022fair1m, 5 | title = {FAIR1M: A benchmark dataset for fine-grained object recognition in high-resolution remote sensing imagery}, 6 | journal = {ISPRS Journal of Photogrammetry and Remote Sensing}, 7 | volume = {184}, 8 | pages = {116-130}, 9 | year = {2022}, 10 | issn = {0924-2716}, 11 | author = {Xian Sun and Peijin Wang and Zhiyuan Yan and Feng Xu and Ruiping Wang and Wenhui Diao and Jin Chen and Jihao Li and Yingchao Feng and Tao Xu and Martin Weinmann and Stefan Hinz and Cheng Wang and Kun Fu}, 12 | } 13 | ``` 14 | -------------------------------------------------------------------------------- /mmrotate/datasets/transforms/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .loading import LoadPatchFromNDArray 3 | from .transforms import (ConvertBoxType, ConvertMask2BoxType, 4 | ConvertWeakSupervision, RBox2PointWithNoise, 5 | RandomChoiceRotate, RandomRotate, RBox2Point, 6 | Rotate, ClampBox) 7 | 8 | __all__ = [ 9 | 'LoadPatchFromNDArray', 'Rotate', 'RandomRotate', 'RandomChoiceRotate', 10 | 'ConvertBoxType', 'RBox2Point', 'ConvertMask2BoxType', 11 | 'ConvertWeakSupervision', 'RBox2PointWithNoise', 'ClampBox' 12 | ] 13 | -------------------------------------------------------------------------------- /tools/data/fair/split/split_configs/ss_trainval.json: -------------------------------------------------------------------------------- 1 | { 2 | "nproc": 10, 3 | "img_dirs": [ 4 | "../data/FAIR1M/train/images/", 5 | "../data/FAIR1M/val/images/" 6 | ], 7 | "ann_dirs": [ 8 | "../data/FAIR1M/train/labelXml/", 9 | "../data/FAIR1M/val/labelXml/" 10 | ], 11 | "sizes": [ 12 | 1024 13 | ], 14 | "gaps": [ 15 | 200 16 | ], 17 | "rates": [ 18 | 1.5 19 | ], 20 | "img_rate_thr": 0.6, 21 | "iof_thr": 0.7, 22 | "no_padding": false, 23 | "padding_value": [ 24 | 104, 25 | 116, 26 | 124 27 | ], 28 | "save_dir": "data/split_ss_fair/trainval/", 29 | "save_ext": ".png" 30 | } -------------------------------------------------------------------------------- /tools/data/dota/split/split_configs/ms_trainval.json: -------------------------------------------------------------------------------- 1 | { 2 | "nproc": 10, 3 | "img_dirs": [ 4 | "data/DOTA/train/images/", 5 | "data/DOTA/val/images/" 6 | ], 7 | "ann_dirs": [ 8 | "data/DOTA/train/labelTxt/", 9 | "data/DOTA/val/labelTxt/" 10 | ], 11 | "sizes": [ 12 | 1024 13 | ], 14 | "gaps": [ 15 | 500 16 | ], 17 | "rates": [ 18 | 0.5, 19 | 1.0, 20 | 1.5 21 | ], 22 | "img_rate_thr": 0.6, 23 | "iof_thr": 0.7, 24 | "no_padding": false, 25 | "padding_value": [ 26 | 104, 27 | 116, 28 | 124 29 | ], 30 | "save_dir": "data/split_ms_dota/trainval/", 31 | "save_ext": ".png" 32 | } 33 | -------------------------------------------------------------------------------- /tools/data/dota/split/split_configs/ss_trainval.json: -------------------------------------------------------------------------------- 1 | { 2 | "nproc": 10, 3 | "img_dirs": [ 4 | "../../Data/DOTA/train/images/", 5 | "../../Data/DOTA/val/images/" 6 | ], 7 | "ann_dirs": [ 8 | "../../Data/DOTA/train/labelTxt-v2.0/", 9 | "../../Data/DOTA/val/labelTxt-v2.0/" 10 | ], 11 | "sizes": [ 12 | 1024 13 | ], 14 | "gaps": [ 15 | 200 16 | ], 17 | "rates": [ 18 | 1.0 19 | ], 20 | "img_rate_thr": 0.6, 21 | "iof_thr": 0.7, 22 | "no_padding": false, 23 | "padding_value": [ 24 | 104, 25 | 116, 26 | 124 27 | ], 28 | "save_dir": "data/split_ss_dota2_0/trainval/", 29 | "save_ext": ".png" 30 | } -------------------------------------------------------------------------------- /tools/data/README.md: -------------------------------------------------------------------------------- 1 | # Data Preparation for Rotation Detection 2 | 3 | It is recommended to symlink the dataset root to `$MMROTATE/data`. 4 | If your folder structure is different, you may need to change the corresponding paths in config files. 5 | 6 | Datasets supported in MMRotate: 7 | 8 | - [DOTA Dataset](dota/README.md) \[ [Homepage](https://captain-whu.github.io/DOTA/) \] 9 | - [DIOR Dataset](dior/README.md) \[ [Homepage](https://gcheng-nwpu.github.io/#Datasets) \] 10 | - [SSDD Dataset](ssdd/README.md) 11 | - [HRSC Dataset](hrsc/README.md) 12 | - [HRSID Dataset](hrsid/README.md) 13 | - [SRSDD Dataset](srsdd/README.md) 14 | - [RSDD Dataset](rsdd/README.md) 15 | -------------------------------------------------------------------------------- /tools/slurm_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -x 4 | 5 | PARTITION=$1 6 | JOB_NAME=$2 7 | CONFIG=$3 8 | CHECKPOINT=$4 9 | GPUS=${GPUS:-8} 10 | GPUS_PER_NODE=${GPUS_PER_NODE:-8} 11 | CPUS_PER_TASK=${CPUS_PER_TASK:-5} 12 | PY_ARGS=${@:5} 13 | SRUN_ARGS=${SRUN_ARGS:-""} 14 | 15 | PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \ 16 | srun -p ${PARTITION} \ 17 | --job-name=${JOB_NAME} \ 18 | --gres=gpu:${GPUS_PER_NODE} \ 19 | --ntasks=${GPUS} \ 20 | --ntasks-per-node=${GPUS_PER_NODE} \ 21 | --cpus-per-task=${CPUS_PER_TASK} \ 22 | --kill-on-bad-exit=1 \ 23 | ${SRUN_ARGS} \ 24 | python -u tools/test.py ${CONFIG} ${CHECKPOINT} --launcher="slurm" ${PY_ARGS} 25 | -------------------------------------------------------------------------------- /tools/slurm_train.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -x 4 | 5 | PARTITION=$1 6 | JOB_NAME=$2 7 | CONFIG=$3 8 | WORK_DIR=$4 9 | GPUS=${GPUS:-8} 10 | GPUS_PER_NODE=${GPUS_PER_NODE:-8} 11 | CPUS_PER_TASK=${CPUS_PER_TASK:-5} 12 | SRUN_ARGS=${SRUN_ARGS:-""} 13 | PY_ARGS=${@:5} 14 | 15 | PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \ 16 | srun -p ${PARTITION} \ 17 | --job-name=${JOB_NAME} \ 18 | --gres=gpu:${GPUS_PER_NODE} \ 19 | --ntasks=${GPUS} \ 20 | --ntasks-per-node=${GPUS_PER_NODE} \ 21 | --cpus-per-task=${CPUS_PER_TASK} \ 22 | --kill-on-bad-exit=1 \ 23 | ${SRUN_ARGS} \ 24 | python -u tools/train.py ${CONFIG} --work-dir=${WORK_DIR} --launcher="slurm" ${PY_ARGS} 25 | -------------------------------------------------------------------------------- /mmrotate/structures/bbox/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .bbox_overlaps import fake_rbbox_overlaps, rbbox_overlaps 3 | from .box_converters import (hbox2qbox, hbox2rbox, qbox2hbox, qbox2rbox, 4 | rbox2hbox, rbox2qbox) 5 | from .quadri_boxes import QuadriBoxes 6 | from .rotated_boxes import RotatedBoxes 7 | from .transforms import distance2obb, gaussian2bbox, gt2gaussian, norm_angle 8 | 9 | __all__ = [ 10 | 'QuadriBoxes', 'RotatedBoxes', 'hbox2rbox', 'hbox2qbox', 'rbox2hbox', 11 | 'rbox2qbox', 'qbox2hbox', 'qbox2rbox', 'gaussian2bbox', 'gt2gaussian', 12 | 'norm_angle', 'rbbox_overlaps', 'fake_rbbox_overlaps', 'distance2obb' 13 | ] 14 | -------------------------------------------------------------------------------- /mmrotate/datasets/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .dior import DIORDataset # noqa: F401, F403 3 | from .dota import DOTADataset, DOTAv15Dataset, DOTAv2Dataset 4 | from .ocdpcb import OCDPCBDataset 5 | from .fair import FAIRDataset 6 | from .diatom import DIATOMDataset 7 | from .sardet100k import SAR_Det_Finegrained_Dataset 8 | from .hrsc import HRSCDataset # noqa: F401, F403 9 | from .transforms import * # noqa: F401, F403 10 | from .sku110k import SKU110KDataset 11 | 12 | __all__ = [ 13 | 'DOTADataset', 'DOTAv15Dataset', 'DOTAv2Dataset', 'HRSCDataset', 14 | 'DIORDataset', 'FAIRDataset', 'OCDPCBDataset', 'DIATOMDataset', 15 | 'SAR_Det_Finegrained_Dataset', 'SKU110KDataset' 16 | ] 17 | -------------------------------------------------------------------------------- /configs/_base_/schedules/schedule_1x.py: -------------------------------------------------------------------------------- 1 | # training schedule for 1x 2 | train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=12, val_interval=1) 3 | val_cfg = dict(type='ValLoop') 4 | test_cfg = dict(type='TestLoop') 5 | 6 | # learning rate 7 | param_scheduler = [ 8 | dict( 9 | type='LinearLR', 10 | start_factor=1.0 / 3, 11 | by_epoch=False, 12 | begin=0, 13 | end=500), 14 | dict( 15 | type='MultiStepLR', 16 | begin=0, 17 | end=12, 18 | by_epoch=True, 19 | milestones=[8, 11], 20 | gamma=0.1) 21 | ] 22 | 23 | # optimizer 24 | optim_wrapper = dict( 25 | type='OptimWrapper', 26 | optimizer=dict(type='SGD', lr=0.0025, momentum=0.9, weight_decay=0.0001), 27 | clip_grad=dict(max_norm=35, norm_type=2)) 28 | -------------------------------------------------------------------------------- /configs/_base_/schedules/schedule_3x.py: -------------------------------------------------------------------------------- 1 | # training schedule for 1x 2 | train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=36, val_interval=1) 3 | val_cfg = dict(type='ValLoop') 4 | test_cfg = dict(type='TestLoop') 5 | 6 | # learning rate 7 | param_scheduler = [ 8 | dict( 9 | type='LinearLR', 10 | start_factor=1.0 / 3, 11 | by_epoch=False, 12 | begin=0, 13 | end=500), 14 | dict( 15 | type='MultiStepLR', 16 | begin=0, 17 | end=36, 18 | by_epoch=True, 19 | milestones=[24, 33], 20 | gamma=0.1) 21 | ] 22 | 23 | # optimizer 24 | optim_wrapper = dict( 25 | type='OptimWrapper', 26 | optimizer=dict(type='SGD', lr=0.0025, momentum=0.9, weight_decay=0.0001), 27 | clip_grad=dict(max_norm=35, norm_type=2)) 28 | -------------------------------------------------------------------------------- /configs/_base_/schedules/schedule_6x.py: -------------------------------------------------------------------------------- 1 | # training schedule for 1x 2 | train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=72, val_interval=1) 3 | val_cfg = dict(type='ValLoop') 4 | test_cfg = dict(type='TestLoop') 5 | 6 | # learning rate 7 | param_scheduler = [ 8 | dict( 9 | type='LinearLR', 10 | start_factor=1.0 / 3, 11 | by_epoch=False, 12 | begin=0, 13 | end=500), 14 | dict( 15 | type='MultiStepLR', 16 | begin=0, 17 | end=72, 18 | by_epoch=True, 19 | milestones=[48, 66], 20 | gamma=0.1) 21 | ] 22 | 23 | # optimizer 24 | optim_wrapper = dict( 25 | type='OptimWrapper', 26 | optimizer=dict(type='SGD', lr=0.0025, momentum=0.9, weight_decay=0.0001), 27 | clip_grad=dict(max_norm=35, norm_type=2)) 28 | -------------------------------------------------------------------------------- /configs/_base_/schedules/schedule_40e.py: -------------------------------------------------------------------------------- 1 | # training schedule for 1x 2 | train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=40, val_interval=1) 3 | val_cfg = dict(type='ValLoop') 4 | test_cfg = dict(type='TestLoop') 5 | 6 | # learning rate 7 | param_scheduler = [ 8 | dict( 9 | type='LinearLR', 10 | start_factor=1.0 / 3, 11 | by_epoch=False, 12 | begin=0, 13 | end=500), 14 | dict( 15 | type='MultiStepLR', 16 | begin=0, 17 | end=40, 18 | by_epoch=True, 19 | milestones=[24, 32, 38], 20 | gamma=0.1) 21 | ] 22 | 23 | # optimizer 24 | optim_wrapper = dict( 25 | type='OptimWrapper', 26 | optimizer=dict(type='SGD', lr=0.0025, momentum=0.9, weight_decay=0.0001), 27 | clip_grad=dict(max_norm=35, norm_type=2)) 28 | -------------------------------------------------------------------------------- /mmrotate/models/utils/ripool.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from torch import nn 3 | 4 | 5 | class RotationInvariantPooling(nn.Module): 6 | """Rotating invariant pooling module. 7 | 8 | Args: 9 | nInputPlane (int): The number of Input plane. 10 | nOrientation (int, optional): The number of oriented channels. 11 | """ 12 | 13 | def __init__(self, nInputPlane, nOrientation=8): 14 | super(RotationInvariantPooling, self).__init__() 15 | self.nInputPlane = nInputPlane 16 | self.nOrientation = nOrientation 17 | 18 | def forward(self, x): 19 | """Forward function.""" 20 | N, c, h, w = x.size() 21 | x = x.view(N, -1, self.nOrientation, h, w) 22 | x, _ = x.max(dim=2, keepdim=False) 23 | return x 24 | -------------------------------------------------------------------------------- /basic_patterns/dota/properties.txt: -------------------------------------------------------------------------------- 1 | { 2 | 'plane': (200, 190, 0.6, 0.6), 3 | 'baseball-diamond': (200, 200, 0.5, 0.1), 4 | 'bridge': (60, 40, 0.5, 0.4), 5 | 'ground-track-field': (180, 120, 0.8, 0.4), 6 | 'small-vehicle': (36, 16, 0.4, 0.3), 7 | 'large-vehicle': (76, 20, 0.4, 0.8), 8 | 'ship': (76, 26, 0.4, 0.5), 9 | 'tennis-court': (168, 74, 0.4, 0.4), 10 | 'basketball-court': (176, 94, 0.4, 0.4), 11 | 'storage-tank': (76, 76, 0.8, 0.1), 12 | 'soccer-ball-field': (180, 120, 0.8, 0.4), 13 | 'roundabout': (200, 200, 0.8, 0.1), 14 | 'harbor': (200, 30, 0.8, 0.8), 15 | 'swimming-pool': (78, 48, 0.4, 0.6), 16 | 'helicopter': (100, 40, 0.4, 0.4), 17 | 'container-crane': (155, 40, 0.4, 0.4), 18 | 'airport': (200, 40, 0.4, 0.4), 19 | 'helipad': (76, 76, 0.8, 0.1) 20 | } 21 | -------------------------------------------------------------------------------- /mmrotate/models/detectors/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .h2rbox import H2RBoxDetector 3 | from .h2rbox_v2 import H2RBoxV2Detector 4 | from .h2rbox_v2p import H2RBoxV2PDetector 5 | from .h2rbox_v2_redet import H2RBoxV2ReDetDetector 6 | from .h2rbox_v2_s2anet import H2RBoxV2S2ANetDetector 7 | from .point2rbox_yolof import Point2RBoxYOLOF 8 | from .point2rbox_v2 import Point2RBoxV2 9 | from .refine_single_stage import RefineSingleStageDetector 10 | from .whollywood_p2h import WhollyWoodP2H 11 | from .whollywood_p2r import WhollyWoodP2R 12 | 13 | __all__ = [ 14 | 'RefineSingleStageDetector', 'H2RBoxDetector', 'H2RBoxV2Detector', 15 | 'Point2RBoxV2', 'Point2RBoxYOLOF', 'H2RBoxV2PDetector', 16 | 'H2RBoxV2ReDetDetector', 'H2RBoxV2S2ANetDetector', 'WhollyWoodP2H', 17 | 'WhollyWoodP2R' 18 | ] 19 | -------------------------------------------------------------------------------- /configs/whollywood/whollywood-ms_rr-1x-dota-using-pseudo.py: -------------------------------------------------------------------------------- 1 | _base_ = 'whollywood-1x-dota-using-pseudo.py' 2 | 3 | train_pipeline = [ 4 | dict(type='mmdet.LoadImageFromFile', backend_args=_base_.backend_args), 5 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='rbox'), 6 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 7 | dict( 8 | type='mmdet.RandomFlip', 9 | prob=0.75, 10 | direction=['horizontal', 'vertical', 'diagonal']), 11 | dict(type='RandomRotate', prob=1, angle_range=180), 12 | dict(type='mmdet.PackDetInputs') 13 | ] 14 | 15 | data_root = 'data/split_ms_dota/' 16 | 17 | train_dataloader = dict( 18 | dataset=dict(data_root=data_root, pipeline=train_pipeline)) 19 | val_dataloader = dict(dataset=dict(data_root=data_root)) 20 | test_dataloader = dict(dataset=dict(data_root=data_root)) 21 | -------------------------------------------------------------------------------- /configs/_base_/default_runtime.py: -------------------------------------------------------------------------------- 1 | default_scope = 'mmrotate' 2 | 3 | default_hooks = dict( 4 | timer=dict(type='IterTimerHook'), 5 | logger=dict(type='LoggerHook', interval=50), 6 | param_scheduler=dict(type='ParamSchedulerHook'), 7 | checkpoint=dict(type='CheckpointHook', interval=1), 8 | sampler_seed=dict(type='DistSamplerSeedHook'), 9 | visualization=dict(type='mmdet.DetVisualizationHook')) 10 | 11 | env_cfg = dict( 12 | cudnn_benchmark=False, 13 | mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0), 14 | dist_cfg=dict(backend='nccl'), 15 | ) 16 | 17 | vis_backends = [dict(type='LocalVisBackend')] 18 | visualizer = dict( 19 | type='RotLocalVisualizer', vis_backends=vis_backends, name='visualizer') 20 | log_processor = dict(type='LogProcessor', window_size=50, by_epoch=True) 21 | 22 | log_level = 'INFO' 23 | load_from = None 24 | resume = False 25 | -------------------------------------------------------------------------------- /basic_patterns/dior/properties.txt: -------------------------------------------------------------------------------- 1 | { 2 | 'airplane': (200, 200, 0.5, 0.3), 3 | 'airport': (300, 200, 0.5, 0.8), 4 | 'baseballfield': (100, 100, 0.5, 0.3), 5 | 'basketballcourt': (200, 110, 0.5, 0.8), 6 | 'bridge': (50, 10, 0.5, 0.8), 7 | 'chimney': (120, 120, 0.5, 0.3), 8 | 'expressway-service-area': (300, 120, 0.5, 0.8), 9 | 'expressway-toll-station': (300, 120, 0.5, 0.8), 10 | 'dam': (150, 50, 0.5, 0.8), 11 | 'golffield': (300, 300, 0.5, 0.3), 12 | 'groundtrackfield': (300, 150, 0.5, 0.8), 13 | 'harbor': (132, 25, 0.5, 0.8), 14 | 'overpass': (160, 55, 0.5, 0.8), 15 | 'ship': (76, 26, 0.5, 0.8), 16 | 'stadium': (300, 200, 0.5, 0.3), 17 | 'storagetank': (80, 80, 0.5, 0.3), 18 | 'tenniscourt': (180, 90, 0.5, 0.8), 19 | 'trainstation': (200, 70, 0.5, 0.8), 20 | 'vehicle': (40, 20, 0.5, 0.8), 21 | 'windmill': (90, 80, 0.5, 0.3) 22 | } -------------------------------------------------------------------------------- /tools/data/srsdd/README.md: -------------------------------------------------------------------------------- 1 | # Preparing SRSDD Dataset 2 | 3 | 4 | 5 | ```bibtex 6 | @ARTICLE{SRSDD2021, 7 | author = {S. Lei, D. Lu and X. Qiu}, 8 | title = {SRSDD-v1.0: A high-resolution SAR rotation ship 9 | detection dataset}, 10 | journal = {Remote Senseing}, 11 | month = {Dec.}, 12 | year = {2021}, 13 | volume={13}, 14 | number={24}, 15 | pages={5104}, 16 | } 17 | ``` 18 | 19 | ## Download SRSDD dataset 20 | 21 | The SRSDD dataset can be downloaded from [Google drive](https://drive.google.com/file/d/1QtCjih1ChOmG-TOPUTlsL3WbMh0L-1zp/view?usp=sharing). 22 | 23 | The data structure is as follows: 24 | 25 | ```none 26 | mmrotate 27 | ├── mmrotate 28 | ├── tools 29 | ├── configs 30 | ├── data 31 | │ ├── srsdd 32 | │ │ ├── train 33 | │ │ ├── test 34 | ``` 35 | 36 | ## Change base config 37 | 38 | Please change `data_root` in `configs/_base_/datasets/srsdd.py` to `data/srsdd/`. 39 | -------------------------------------------------------------------------------- /mmrotate/models/task_modules/assigners/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .convex_assigner import ConvexAssigner 3 | from .max_convex_iou_assigner import MaxConvexIoUAssigner 4 | from .point2rbox_assigner import Point2RBoxAssigner 5 | from .rotate_iou2d_calculator import (FakeRBboxOverlaps2D, 6 | QBbox2HBboxOverlaps2D, 7 | RBbox2HBboxOverlaps2D, 8 | RBboxOverlaps2D, 9 | CircumRBboxOverlaps2D) 10 | from .rotated_atss_assigner import RotatedATSSAssigner 11 | from .sas_assigner import SASAssigner 12 | 13 | __all__ = [ 14 | 'ConvexAssigner', 'MaxConvexIoUAssigner', 'SASAssigner', 15 | 'RotatedATSSAssigner', 'RBboxOverlaps2D', 'FakeRBboxOverlaps2D', 16 | 'RBbox2HBboxOverlaps2D', 'QBbox2HBboxOverlaps2D', 'Point2RBoxAssigner', 17 | 'CircumRBboxOverlaps2D' 18 | ] 19 | -------------------------------------------------------------------------------- /configs/h2rbox_v2/h2rbox_v2-le90_r50_fpn_rr-6x_hrsc.py: -------------------------------------------------------------------------------- 1 | _base_ = ['h2rbox_v2-le90_r50_fpn-6x_hrsc.py'] 2 | 3 | # load hbox annotations 4 | train_pipeline = [ 5 | dict(type='mmdet.LoadImageFromFile', backend_args={{_base_.backend_args}}), 6 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 7 | dict(type='mmdet.FixShapeResize', width=800, height=800, keep_ratio=True), 8 | # Horizontal GTBox, (x1,y1,x2,y2) 9 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='hbox')), 10 | # Horizontal GTBox, (x,y,w,h,theta) 11 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 12 | dict( 13 | type='mmdet.RandomFlip', 14 | prob=0.75, 15 | direction=['horizontal', 'vertical', 'diagonal']), 16 | dict(type='RandomRotate', prob=1, angle_range=180), 17 | dict(type='mmdet.PackDetInputs') 18 | ] 19 | 20 | train_dataloader = dict(dataset=dict(pipeline=train_pipeline)) 21 | -------------------------------------------------------------------------------- /tools/data/hrsid/README.md: -------------------------------------------------------------------------------- 1 | # Preparing HRSID Dataset 2 | 3 | 4 | 5 | ```bibtex 6 | @ARTICLE{HRSID_2020, 7 | author={Wei, Shunjun and Zeng, Xiangfeng and Qu, Qizhe and Wang, Mou and Su, Hao and Shi, Jun}, 8 | journal={IEEE Access}, 9 | title={HRSID: A High-Resolution SAR Images Dataset for Ship Detection and Instance Segmentation}, 10 | year={2020}, 11 | volume={8}, 12 | pages={120234-120254}, 13 | } 14 | ``` 15 | 16 | ## Download HRSID dataset 17 | 18 | The HRSID dataset can be downloaded from [Google drive](https://drive.google.com/file/d/1BZTU8Gyg20wqHXtBPFzRazn_lEdvhsbE/view). 19 | 20 | The data structure is as follows: 21 | 22 | ```none 23 | mmrotate 24 | ├── mmrotate 25 | ├── tools 26 | ├── configs 27 | ├── data 28 | │ ├── HRSID_JPG 29 | │ │ ├── JPEGImages 30 | │ │ ├── annotations 31 | ``` 32 | 33 | ## Change base config 34 | 35 | Please change `data_root` in `configs/_base_/datasets/hrisd.py` to `data/HRSID_JPG/`. 36 | -------------------------------------------------------------------------------- /mmrotate/models/losses/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .convex_giou_loss import BCConvexGIoULoss, ConvexGIoULoss 3 | from .gaussian_dist_loss import GDLoss 4 | from .gaussian_dist_loss_v1 import GDLoss_v1 5 | from .h2rbox_consistency_loss import H2RBoxConsistencyLoss 6 | from .h2rbox_v2_consistency_loss import H2RBoxV2ConsistencyLoss 7 | from .kf_iou_loss import KFLoss 8 | from .rotated_iou_loss import RotatedIoULoss 9 | from .smooth_focal_loss import SmoothFocalLoss 10 | from .spatial_border_loss import SpatialBorderLoss 11 | from .point2rbox_v2_loss import GaussianOverlapLoss, VoronoiWatershedLoss, EdgeLoss, Point2RBoxV2ConsistencyLoss 12 | 13 | __all__ = [ 14 | 'GDLoss', 'GDLoss_v1', 'KFLoss', 'ConvexGIoULoss', 'BCConvexGIoULoss', 15 | 'SmoothFocalLoss', 'RotatedIoULoss', 'SpatialBorderLoss', 16 | 'H2RBoxConsistencyLoss', 'H2RBoxV2ConsistencyLoss', 17 | 'GaussianOverlapLoss', 'VoronoiWatershedLoss', 'EdgeLoss', 'Point2RBoxV2ConsistencyLoss' 18 | ] 19 | -------------------------------------------------------------------------------- /tools/data/rsdd/README.md: -------------------------------------------------------------------------------- 1 | # Preparing RSDD Dataset 2 | 3 | 4 | 5 | ```bibtex 6 | @ARTICLE{RSDD2022, 7 | author = {C. Xu, H. Su, J. Li, Y. Liu, L. Yao, L. Gao, W. Yan and T. Wang}, 8 | title = {RSDD-SAR: Rotated Ship Detection Dataset in SAR Images}, 9 | journal = {Journal of Radars}, 10 | month = {Sep.}, 11 | year = {2022}, 12 | volume={11}, 13 | number={R22007}, 14 | pages={581}, 15 | } 16 | ``` 17 | 18 | ## Download RSDD dataset 19 | 20 | The RSDD dataset can be downloaded from [Google drive](https://drive.google.com/file/d/1PJxr7Tbr_ZAzuG8MNloDa4mLaRYCD3qc/view?usp=sharing). 21 | 22 | The data structure is as follows: 23 | 24 | ```none 25 | mmrotate 26 | ├── mmrotate 27 | ├── tools 28 | ├── configs 29 | ├── data 30 | │ ├── rsdd 31 | │ │ ├── Annotations 32 | │ │ ├── ImageSets 33 | │ │ ├── JPEGImages 34 | │ │ ├── JPEGValidation 35 | ``` 36 | 37 | ## Change base config 38 | 39 | Please change `data_root` in `configs/_base_/datasets/rsdd.py` to `data/rsdd/`. 40 | -------------------------------------------------------------------------------- /tools/data/ssdd/README.md: -------------------------------------------------------------------------------- 1 | # Preparing SSDD Dataset 2 | 3 | 4 | 5 | ```bibtex 6 | @ARTICLE{SSDD2021, 7 | author = {T. Zhang, X. Zhang, J. Li and X. Xu}, 8 | title = {SAR ship detection dataset (SSDD): Official release and comprehensive data analysis}, 9 | journal = {Remote Senseing}, 10 | month = {Sep.}, 11 | year = {2021} 12 | volume={13}, 13 | number={18}, 14 | pages={3690}, 15 | } 16 | ``` 17 | 18 | ## Download SSDD dataset 19 | 20 | The SSDD dataset can be downloaded from [Google drive](https://drive.google.com/file/d/1LmoHBk4xUvm0Zdtm8X7256dHigyFW4Nh/view?usp=sharing). 21 | 22 | The data structure is as follows: 23 | 24 | ```none 25 | mmrotate 26 | ├── mmrotate 27 | ├── tools 28 | ├── configs 29 | ├── data 30 | │ ├── ssdd 31 | │ │ ├── train 32 | │ │ ├── test 33 | │ │ │ ├── all 34 | │ │ │ ├── inshore 35 | │ │ │ ├── offshore 36 | ``` 37 | 38 | ## Change base config 39 | 40 | Please change `data_root` in `configs/_base_/datasets/ssdd.py` to `data/ssdd/`. 41 | -------------------------------------------------------------------------------- /configs/point2rbox_v2/point2rbox_v2-pseudo-generator-dota.py: -------------------------------------------------------------------------------- 1 | _base_ = 'point2rbox_v2-1x-dota.py' 2 | 3 | # This allows the model to use gt points during inference 4 | model = dict(bbox_head=dict(pseudo_generator=True)) 5 | 6 | test_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args={{_base_.backend_args}}), 8 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 9 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 10 | dict(type='ConvertWeakSupervision', point_proportion=1., hbox_proportion=0), 11 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 12 | dict(type='mmdet.PackDetInputs') 13 | ] 14 | 15 | # Use train set for inference and turn off the augmentation 16 | test_dataloader = _base_.train_dataloader 17 | test_dataloader['_delete_'] = True 18 | test_dataloader['dataset']['pipeline'] = test_pipeline 19 | test_evaluator = dict(_delete_=True, 20 | type='DOTAMetric', 21 | metric='mAP', 22 | format_only=True, 23 | outfile_prefix='data/split_ss_dota/point2rbox_v2_pseudo_labels') 24 | -------------------------------------------------------------------------------- /configs/point2rbox_v2/point2rbox_v2-pseudo-generator-fair.py: -------------------------------------------------------------------------------- 1 | _base_ = 'point2rbox_v2-1x-fair.py' 2 | 3 | # This allows the model to use gt points during inference 4 | model = dict(bbox_head=dict(pseudo_generator=True)) 5 | 6 | test_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args={{_base_.backend_args}}), 8 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 9 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 10 | dict(type='ConvertWeakSupervision', point_proportion=1., hbox_proportion=0), 11 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 12 | dict(type='mmdet.PackDetInputs') 13 | ] 14 | 15 | # Use train set for inference and turn off the augmentation 16 | test_dataloader = _base_.train_dataloader 17 | test_dataloader['_delete_'] = True 18 | test_dataloader['dataset']['pipeline'] = test_pipeline 19 | test_evaluator = dict(_delete_=True, 20 | type='DOTAMetric', 21 | metric='mAP', 22 | format_only=True, 23 | outfile_prefix='data/split_ss_fair/point2rbox_v2_pseudo_labels') 24 | -------------------------------------------------------------------------------- /configs/point2rbox_v2/point2rbox_v2-pseudo-generator-hrsc.py: -------------------------------------------------------------------------------- 1 | _base_ = 'point2rbox_v2-6x-hrsc.py' 2 | 3 | # This allows the model to use gt points during inference 4 | model = dict(bbox_head=dict(pseudo_generator=True)) 5 | 6 | test_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args={{_base_.backend_args}}), 8 | dict(type='mmdet.FixShapeResize', width=800, height=800, keep_ratio=True), 9 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 10 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 11 | dict(type='ConvertWeakSupervision', point_proportion=1., hbox_proportion=0), 12 | dict(type='mmdet.PackDetInputs') 13 | ] 14 | 15 | # Use train set for inference and turn off the augmentation 16 | test_dataloader = _base_.train_dataloader 17 | test_dataloader['_delete_'] = True 18 | test_dataloader['dataset']['pipeline'] = test_pipeline 19 | test_evaluator = dict(_delete_=True, 20 | type='DOTAMetric', 21 | metric='mAP', 22 | format_only=True, 23 | outfile_prefix='data/hrsc/point2rbox_v2_pseudo_labels') 24 | -------------------------------------------------------------------------------- /configs/point2rbox_v2/point2rbox_v2-pseudo-generator-sku110k.py: -------------------------------------------------------------------------------- 1 | _base_ = 'point2rbox_v2-1x-sku110k.py' 2 | 3 | # This allows the model to use gt points during inference 4 | model = dict(bbox_head=dict(pseudo_generator=True)) 5 | 6 | test_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args={{_base_.backend_args}}), 8 | dict(type='mmdet.FixShapeResize', width=800, height=800, keep_ratio=True), 9 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 10 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 11 | dict(type='ConvertWeakSupervision', point_proportion=1., hbox_proportion=0), 12 | dict(type='mmdet.PackDetInputs') 13 | ] 14 | 15 | # Use train set for inference and turn off the augmentation 16 | test_dataloader = _base_.train_dataloader 17 | test_dataloader['_delete_'] = True 18 | test_dataloader['dataset']['pipeline'] = test_pipeline 19 | test_evaluator = dict(_delete_=True, 20 | type='DOTAMetric', 21 | metric='mAP', 22 | format_only=True, 23 | outfile_prefix='data/sku110k/point2rbox_v2_pseudo_labels') 24 | -------------------------------------------------------------------------------- /configs/h2rbox_v2/h2rbox_v2p-le90_r50_fpn-ms_rr_1x_dota.py: -------------------------------------------------------------------------------- 1 | _base_ = ['h2rbox_v2p-le90_r50_fpn-1x_dota.py'] 2 | 3 | # load hbox annotations 4 | train_pipeline = [ 5 | dict(type='mmdet.LoadImageFromFile', backend_args={{_base_.backend_args}}), 6 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 7 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 8 | dict(type='ConvertWeakSupervision', 9 | point_proportion=0.0, 10 | hbox_proportion=1.0, 11 | modify_labels=True), 12 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 13 | dict( 14 | type='mmdet.RandomFlip', 15 | prob=0.75, 16 | direction=['horizontal', 'vertical', 'diagonal']), 17 | dict(type='RandomRotate', prob=1, angle_range=180), 18 | dict(type='mmdet.PackDetInputs') 19 | ] 20 | 21 | train_dataloader = dict(dataset=dict()) 22 | 23 | data_root = 'data/split_ms_dota/' 24 | 25 | train_dataloader = dict( 26 | dataset=dict(data_root=data_root, pipeline=train_pipeline)) 27 | val_dataloader = dict(dataset=dict(data_root=data_root)) 28 | test_dataloader = dict(dataset=dict(data_root=data_root)) 29 | -------------------------------------------------------------------------------- /mmrotate/models/task_modules/coders/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .angle_coder import CSLCoder, PSCCoder, PseudoAngleCoder 3 | from .delta_midpointoffset_rbbox_coder import MidpointOffsetCoder 4 | from .delta_xywh_hbbox_coder import DeltaXYWHHBBoxCoder 5 | from .delta_xywh_qbbox_coder import DeltaXYWHQBBoxCoder 6 | from .delta_xywht_hbbox_coder import DeltaXYWHTHBBoxCoder 7 | from .delta_xywht_rbbox_coder import DeltaXYWHTRBBoxCoder 8 | from .distance_angle_point_coder import DistanceAnglePointCoder 9 | from .distance_boundary_free_point_coder import DistanceBoundaryFreePointCoder 10 | from .gliding_vertex_coder import GVFixCoder, GVRatioCoder 11 | from .delta_xywh_psc_hbbox_coder import DeltaXYWHPSCHBBoxCoder 12 | from .delta_xywh_psc_rbbox_coder import DeltaXYWHPSCRBBoxCoder 13 | 14 | __all__ = [ 15 | 'DeltaXYWHTRBBoxCoder', 'DeltaXYWHTHBBoxCoder', 'MidpointOffsetCoder', 16 | 'GVFixCoder', 'GVRatioCoder', 'CSLCoder', 'PSCCoder', 17 | 'DistanceAnglePointCoder', 'DeltaXYWHHBBoxCoder', 'DeltaXYWHQBBoxCoder', 18 | 'PseudoAngleCoder', 'DistanceBoundaryFreePointCoder', 19 | 'DeltaXYWHPSCHBBoxCoder', 'DeltaXYWHPSCRBBoxCoder' 20 | ] 21 | -------------------------------------------------------------------------------- /configs/h2rbox_v2/h2rbox_v2-le90_r50_fpn_ms_rr-1x_dota.py: -------------------------------------------------------------------------------- 1 | _base_ = ['h2rbox_v2-le90_r50_fpn-1x_dota.py'] 2 | 3 | # load hbox annotations 4 | train_pipeline = [ 5 | dict(type='mmdet.LoadImageFromFile', backend_args={{_base_.backend_args}}), 6 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 7 | # Horizontal GTBox, (x1,y1,x2,y2) 8 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='hbox')), 9 | # Horizontal GTBox, (x,y,w,h,theta) 10 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 11 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 12 | dict( 13 | type='mmdet.RandomFlip', 14 | prob=0.75, 15 | direction=['horizontal', 'vertical', 'diagonal']), 16 | dict(type='RandomRotate', prob=1, angle_range=180), 17 | dict(type='mmdet.PackDetInputs') 18 | ] 19 | 20 | train_dataloader = dict(dataset=dict()) 21 | 22 | data_root = 'data/split_ms_dota/' 23 | 24 | train_dataloader = dict( 25 | dataset=dict(data_root=data_root, pipeline=train_pipeline)) 26 | val_dataloader = dict(dataset=dict(data_root=data_root)) 27 | test_dataloader = dict(dataset=dict(data_root=data_root)) 28 | -------------------------------------------------------------------------------- /mmrotate/utils/misc.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from typing import Union 3 | 4 | from mmengine.config import Config, ConfigDict 5 | 6 | 7 | def get_test_pipeline_cfg(cfg: Union[str, ConfigDict]) -> ConfigDict: 8 | """Get the test dataset pipeline from entire config. 9 | 10 | Args: 11 | cfg (str or :obj:`ConfigDict`): the entire config. Can be a config 12 | file or a ``ConfigDict``. 13 | 14 | Returns: 15 | :obj:`ConfigDict`: the config of test dataset. 16 | """ 17 | if isinstance(cfg, str): 18 | cfg = Config.fromfile(cfg) 19 | 20 | def _get_test_pipeline_cfg(dataset_cfg): 21 | if 'pipeline' in dataset_cfg: 22 | return dataset_cfg.pipeline 23 | # handle dataset wrapper 24 | elif 'dataset' in dataset_cfg: 25 | return _get_test_pipeline_cfg(dataset_cfg.dataset) 26 | # handle dataset wrappers like ConcatDataset 27 | elif 'datasets' in dataset_cfg: 28 | return _get_test_pipeline_cfg(dataset_cfg.datasets[0]) 29 | 30 | raise RuntimeError('Cannot find `pipeline` in `test_dataloader`') 31 | 32 | return _get_test_pipeline_cfg(cfg.test_dataloader.dataset) 33 | -------------------------------------------------------------------------------- /configs/point2rbox_v2/point2rbox_v2-pseudo-generator-dior.py: -------------------------------------------------------------------------------- 1 | _base_ = 'point2rbox_v2-1x-dior.py' 2 | 3 | # This allows the model to use gt points during inference 4 | model = dict(bbox_head=dict(pseudo_generator=True)) 5 | 6 | test_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args={{_base_.backend_args}}), 8 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 9 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 10 | dict(type='ConvertWeakSupervision', point_proportion=1., hbox_proportion=0), 11 | dict(type='mmdet.Resize', scale=(800, 800), keep_ratio=True), 12 | dict(type='mmdet.PackDetInputs') 13 | ] 14 | 15 | # Use train set for inference and turn off the augmentation 16 | test_dataloader = _base_.train_dataloader 17 | test_dataloader['_delete_'] = True 18 | test_dataloader['dataset']['datasets'][0]['pipeline'] = test_pipeline 19 | test_dataloader['dataset']['datasets'][1]['pipeline'] = test_pipeline 20 | test_evaluator = dict(_delete_=True, 21 | type='DOTAMetric', 22 | metric='mAP', 23 | format_only=True, 24 | outfile_prefix='data/dior/point2rbox_v2_pseudo_labels') 25 | -------------------------------------------------------------------------------- /tools/data/hrsc/README.md: -------------------------------------------------------------------------------- 1 | # Preparing HRSC Dataset 2 | 3 | 4 | 5 | ```bibtex 6 | @conference{hrsc, 7 | author = {Zikun Liu. and Liu Yuan. and Lubin Weng. and Yiping Yang.}, 8 | title = {A High Resolution Optical Satellite Image Dataset for Ship Recognition and Some New Baselines}, 9 | booktitle = {Proceedings of the 6th International Conference on Pattern Recognition Applications and Methods - ICPRAM,}, 10 | year = {2017}, 11 | pages = {324-331}, 12 | publisher = {SciTePress}, 13 | organization = {INSTICC}, 14 | doi = {10.5220/0006120603240331}, 15 | isbn = {978-989-758-222-6}, 16 | issn = {2184-4313}, 17 | } 18 | ``` 19 | 20 | ## Download HRSC dataset 21 | 22 | The HRSC dataset can be downloaded from [here](https://aistudio.baidu.com/aistudio/datasetdetail/54106). 23 | 24 | The data structure is as follows: 25 | 26 | ```none 27 | mmrotate 28 | ├── mmrotate 29 | ├── tools 30 | ├── configs 31 | ├── data 32 | │ ├── hrsc 33 | │ │ ├── FullDataSet 34 | │ │ │ ├─ AllImages 35 | │ │ │ ├─ Annotations 36 | │ │ │ ├─ LandMask 37 | │ │ │ ├─ Segmentations 38 | │ │ ├── ImageSets 39 | ``` 40 | 41 | ## Change base config 42 | 43 | Please change `data_root` in `configs/_base_/datasets/hrsc.py` to `data/hrsc/`. 44 | -------------------------------------------------------------------------------- /tools/misc/print_config.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | import argparse 3 | 4 | from mmengine import Config, DictAction 5 | 6 | 7 | def parse_args(): 8 | """Parse arguments.""" 9 | parser = argparse.ArgumentParser(description='Print the whole config') 10 | parser.add_argument('config', help='config file path') 11 | parser.add_argument( 12 | '--cfg-options', 13 | nargs='+', 14 | action=DictAction, 15 | help='override some settings in the used config, the key-value pair ' 16 | 'in xxx=yyy format will be merged into config file. If the value to ' 17 | 'be overwritten is a list, it should be like key="[a,b]" or key=a,b ' 18 | 'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" ' 19 | 'Note that the quotation marks are necessary and that no white space ' 20 | 'is allowed.') 21 | args = parser.parse_args() 22 | 23 | return args 24 | 25 | 26 | def main(): 27 | """Print config.""" 28 | args = parse_args() 29 | 30 | cfg = Config.fromfile(args.config) 31 | 32 | if args.cfg_options is not None: 33 | cfg.merge_from_dict(args.cfg_options) 34 | print(f'Config:\n{cfg.pretty_text}') 35 | 36 | 37 | if __name__ == '__main__': 38 | main() 39 | -------------------------------------------------------------------------------- /tools/data/dior/README.md: -------------------------------------------------------------------------------- 1 | # Preparing DIOR Dataset 2 | 3 | 4 | 5 | ```bibtex 6 | @article{LI2020296, 7 | title = {Object detection in optical remote sensing images: A survey and a new benchmark}, 8 | journal = {ISPRS Journal of Photogrammetry and Remote Sensing}, 9 | volume = {159}, 10 | pages = {296-307}, 11 | year = {2020}, 12 | issn = {0924-2716}, 13 | doi = {https://doi.org/10.1016/j.isprsjprs.2019.11.023}, 14 | url = {https://www.sciencedirect.com/science/article/pii/S0924271619302825}, 15 | author = {Ke Li and Gang Wan and Gong Cheng and Liqiu Meng and Junwei Han} 16 | ``` 17 | 18 | ## Download DIOR dataset 19 | 20 | The DIOR dataset can be downloaded from [here](https://gcheng-nwpu.github.io/#Datasets). 21 | 22 | The data structure is as follows: 23 | 24 | ```none 25 | mmrotate 26 | ├── mmrotate 27 | ├── tools 28 | ├── configs 29 | ├── data 30 | │ ├── DIOR 31 | │ │ ├── JPEGImages-trainval 32 | │ │ ├── JPEGImages-test 33 | │ │ ├── Annotations 34 | │ │ │ ├─ Oriented Bounding Boxes 35 | │ │ │ ├─ Horizontal Bounding Boxes 36 | │ │ ├── ImageSets 37 | │ │ │ ├─ Main 38 | │ │ │ │ ├─ train.txt 39 | │ │ │ │ ├─ val.txt 40 | │ │ │ │ ├─ test.txt 41 | ``` 42 | 43 | ## Change base config 44 | 45 | Please change `data_root` in `configs/_base_/datasets/dior.py` to `data/dior/`. 46 | -------------------------------------------------------------------------------- /basic_patterns/fair/properties.txt: -------------------------------------------------------------------------------- 1 | { 2 | 'Boeing737': (72, 64, 0.6, 0.4), 3 | 'Boeing747': (135, 123, 0.6, 0.4), 4 | 'Boeing777': (137, 120, 0.6, 0.4), 5 | 'Boeing787': (109, 115, 0.6, 0.4), 6 | 'C919': (78, 71, 0.6, 0.4), 7 | 'A220': (70, 67, 0.6, 0.4), 8 | 'A321': (81, 68, 0.6, 0.4), 9 | 'A330': (120, 118, 0.6, 0.4), 10 | 'A350': (141, 128, 0.6, 0.4), 11 | 'ARJ21': (57, 40, 0.6, 0.4), 12 | 'Passenger Ship': (129, 31, 0.6, 0.4), 13 | 'Motorboat': (53, 18, 0.6, 0.4), 14 | 'Fishing Boat': (86, 29, 0.6, 0.4), 15 | 'Tugboat': (50, 27, 0.6, 0.4), 16 | 'Engineering Ship': (72, 33, 0.6, 0.4), 17 | 'Liquid Cargo Ship': (221, 37, 0.6, 0.4), 18 | 'Dry Cargo Ship': (94, 27, 0.6, 0.4), 19 | 'Warship': (169, 50, 0.6, 0.4), 20 | 'Small Car': (22, 10, 0.6, 0.4), 21 | 'Bus': (93, 15, 0.6, 0.4), 22 | 'Cargo Truck': (43, 17, 0.6, 0.4), 23 | 'Dump Truck': (38, 18, 0.6, 0.4), 24 | 'Van': (34, 13, 0.6, 0.4), 25 | 'Trailer': (132, 27, 0.6, 0.4), 26 | 'Tractor': (50, 22, 0.6, 0.4), 27 | 'Excavator': (46, 13, 0.6, 0.4), 28 | 'Truck Tractor': (114, 20, 0.6, 0.4), 29 | 'Basketball Court': (54, 28, 0.6, 0.4), 30 | 'Tennis Court': (121, 67, 0.6, 0.4), 31 | 'Football Field': (266, 205, 0.6, 0.4), 32 | 'Baseball Field': (274, 212, 0.6, 0.4), 33 | 'Intersection': (110, 104, 0.6, 0.4), 34 | 'Roundabout': (92, 94, 0.6, 0.1), 35 | 'Bridge': (230, 31, 0.6, 0.4) 36 | } 37 | -------------------------------------------------------------------------------- /mmrotate/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | import mmcv 3 | import mmdet 4 | import mmengine 5 | from mmengine.utils import digit_version 6 | 7 | from .version import __version__, short_version 8 | 9 | mmcv_minimum_version = '2.0.0rc4' 10 | mmcv_maximum_version = '2.2.0' 11 | mmcv_version = digit_version(mmcv.__version__) 12 | 13 | assert (mmcv_version >= digit_version(mmcv_minimum_version) 14 | and mmcv_version <= digit_version(mmcv_maximum_version)), \ 15 | f'MMCV {mmcv.__version__} is incompatible with MMRotate {__version__}. ' \ 16 | f'Please use MMCV >= {mmcv_minimum_version}, ' \ 17 | f'<= {mmcv_maximum_version} instead.' 18 | 19 | mmengine_minimum_version = '0.6.0' 20 | mmengine_maximum_version = '1.0.0' 21 | mmengine_version = digit_version(mmengine.__version__) 22 | 23 | assert (mmengine_version >= digit_version(mmengine_minimum_version) 24 | and mmengine_version < digit_version(mmengine_maximum_version)), \ 25 | f'MMEngine=={mmengine.__version__} is used but incompatible. ' \ 26 | f'Please install mmengine>={mmengine_minimum_version}, ' \ 27 | f'<{mmengine_maximum_version}.' 28 | 29 | mmdet_minimum_version = '3.0.0rc6' 30 | mmdet_maximum_version = '3.3.0' 31 | mmdet_version = digit_version(mmdet.__version__) 32 | 33 | assert (mmdet_version >= digit_version(mmdet_minimum_version) 34 | and mmdet_version <= digit_version(mmdet_maximum_version)), \ 35 | f'MMDetection {mmdet.__version__} is incompatible ' \ 36 | f'with MMRotate {__version__}. ' \ 37 | f'Please use MMDetection >= {mmdet_minimum_version}, ' \ 38 | f'< {mmdet_maximum_version} instead.' 39 | 40 | __all__ = ['__version__', 'short_version', 'digit_version'] 41 | -------------------------------------------------------------------------------- /mmrotate/models/dense_heads/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from .angle_branch_retina_head import AngleBranchRetinaHead 3 | from .cfa_head import CFAHead 4 | from .h2rbox_head import H2RBoxHead 5 | from .h2rbox_v2_head import H2RBoxV2Head 6 | from .h2rbox_v2p_head import H2RBoxV2PHead 7 | from .oriented_reppoints_head import OrientedRepPointsHead 8 | from .oriented_rpn_head import OrientedRPNHead 9 | from .point2rbox_yolof_head import Point2RBoxYOLOFHead 10 | from .point2rbox_v2_head import Point2RBoxV2Head 11 | from .r3_head import R3Head, R3RefineHead 12 | from .rotated_atss_head import RotatedATSSHead 13 | from .rotated_fcos_head import RotatedFCOSHead 14 | from .rotated_fcos_bf_head import RotatedFCOSBFHead 15 | from .rotated_reppoints_head import RotatedRepPointsHead 16 | from .rotated_retina_head import RotatedRetinaHead 17 | from .rotated_rtmdet_head import RotatedRTMDetHead, RotatedRTMDetSepBNHead 18 | from .s2a_head import S2AHead, S2ARefineHead 19 | from .sam_reppoints_head import SAMRepPointsHead 20 | from .h2rbox_v2_s2a_head import H2RBoxV2S2AHead, H2RBoxV2S2ARefineHead 21 | from .whollywood_p2h_head import WhollyWoodP2HHead 22 | from .whollywood_p2r_head import WhollyWoodP2RHead 23 | 24 | __all__ = [ 25 | 'RotatedRetinaHead', 'OrientedRPNHead', 'RotatedRepPointsHead', 26 | 'SAMRepPointsHead', 'AngleBranchRetinaHead', 'RotatedATSSHead', 27 | 'RotatedFCOSHead', 'OrientedRepPointsHead', 'R3Head', 'R3RefineHead', 28 | 'S2AHead', 'S2ARefineHead', 'CFAHead', 'H2RBoxHead', 'H2RBoxV2Head', 29 | 'RotatedRTMDetHead', 'RotatedRTMDetSepBNHead', 'Point2RBoxYOLOFHead', 30 | 'H2RBoxV2PHead', 'RotatedFCOSBFHead', 'Point2RBoxV2Head', 31 | 'H2RBoxV2S2AHead', 'H2RBoxV2S2ARefineHead', 'WhollyWoodP2HHead', 32 | 'WhollyWoodP2RHead' 33 | ] 34 | -------------------------------------------------------------------------------- /tools/model_converters/publish_model.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | import argparse 3 | import subprocess 4 | 5 | import torch 6 | 7 | 8 | def parse_args(): 9 | """Parse parameters.""" 10 | parser = argparse.ArgumentParser( 11 | description='Process a checkpoint to be published') 12 | parser.add_argument('in_file', help='input checkpoint filename') 13 | parser.add_argument('out_file', help='output checkpoint filename') 14 | args = parser.parse_args() 15 | return args 16 | 17 | 18 | def process_checkpoint(in_file, out_file): 19 | """Only inference related parameters are retained. 20 | 21 | Args: 22 | in_file (str): Filename of input checkpoint. 23 | out_file (str): Filename of output checkpoint. 24 | """ 25 | checkpoint = torch.load(in_file, map_location='cpu') 26 | # remove optimizer for smaller file size 27 | if 'optimizer' in checkpoint: 28 | del checkpoint['optimizer'] 29 | # if it is necessary to remove some sensitive data in checkpoint['meta'], 30 | # add the code here. 31 | if torch.__version__ >= '1.6': 32 | torch.save(checkpoint, out_file, _use_new_zipfile_serialization=False) 33 | else: 34 | torch.save(checkpoint, out_file) 35 | sha = subprocess.check_output(['sha256sum', out_file]).decode() 36 | if out_file.endswith('.pth'): 37 | out_file_name = out_file[:-4] 38 | else: 39 | out_file_name = out_file 40 | final_file = out_file_name + f'-{sha[:8]}.pth' 41 | subprocess.Popen(['mv', out_file, final_file]) 42 | 43 | 44 | def main(): 45 | """Main function of publish model.""" 46 | args = parse_args() 47 | process_checkpoint(args.in_file, args.out_file) 48 | 49 | 50 | if __name__ == '__main__': 51 | main() 52 | -------------------------------------------------------------------------------- /configs/point2rbox/metafile.yml: -------------------------------------------------------------------------------- 1 | Collections: 2 | - Name: point2rbox 3 | Metadata: 4 | Training Data: DOTAv1.0 5 | Training Techniques: 6 | - AdamW 7 | Training Resources: 1x GeForce RTX 4090 8 | Architecture: 9 | - ResNet 10 | Paper: 11 | URL: https://arxiv.org/pdf/2311.14758.pdf 12 | Title: 'Point2RBox: Combine Knowledge from Synthetic Visual Patterns for End-to-end Oriented Object Detection with Single Point Supervision' 13 | README: configs/point2rbox/README.md 14 | 15 | Models: 16 | - Name: point2rbox-yolof-dota 17 | In Collection: point2rbox 18 | Config: configs/point2rbox/point2rbox-yolof-dota.py 19 | Metadata: 20 | Training Data: DOTAv1.0 21 | Results: 22 | - Task: Oriented Object Detection 23 | Dataset: DOTAv1.0 24 | Metrics: 25 | mAP: 41.87 26 | Weights: https://download.openmmlab.com/mmrotate/v1.0/point2rbox/point2rbox-yolof-dota/point2rbox-yolof-dota-c94da82d.pth 27 | 28 | - Name: point2rbox-yolof-dior 29 | In Collection: point2rbox 30 | Config: configs/point2rbox/point2rbox-yolof-dior.py 31 | Metadata: 32 | Training Data: DIOR 33 | Results: 34 | - Task: Oriented Object Detection 35 | Dataset: DIOR 36 | Metrics: 37 | mAP: 27.34 38 | Weights: https://download.openmmlab.com/mmrotate/v1.0/point2rbox/point2rbox-yolof-dior/point2rbox-yolof-dior-f4f724df.pth 39 | 40 | - Name: point2rbox-yolof-hrsc 41 | In Collection: point2rbox 42 | Config: configs/point2rbox/point2rbox-yolof-hrsc.py 43 | Metadata: 44 | Training Data: HRSC 45 | Results: 46 | - Task: Oriented Object Detection 47 | Dataset: HRSC 48 | Metrics: 49 | mAP: 79.40 50 | Weights: https://download.openmmlab.com/mmrotate/v1.0/point2rbox/point2rbox-yolof-hrsc/point2rbox-yolof-hrsc-9d096323.pth 51 | -------------------------------------------------------------------------------- /mmrotate/models/task_modules/coders/delta_xywh_qbbox_coder.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from typing import Union 3 | 4 | from mmdet.models.task_modules.coders import DeltaXYWHBBoxCoder 5 | from mmdet.models.task_modules.coders.delta_xywh_bbox_coder import bbox2delta 6 | from mmdet.structures.bbox import HorizontalBoxes, get_box_tensor 7 | from torch import Tensor 8 | 9 | from mmrotate.registry import TASK_UTILS 10 | from mmrotate.structures.bbox import QuadriBoxes 11 | 12 | 13 | @TASK_UTILS.register_module() 14 | class DeltaXYWHQBBoxCoder(DeltaXYWHBBoxCoder): 15 | """Delta XYWH QBBox coder. 16 | 17 | This coder is almost the same as `DeltaXYWHBBoxCoder`. Besides the 18 | gt_bboxes of encode is :obj:`QuadriBoxes`. 19 | """ 20 | 21 | def encode(self, bboxes: Union[HorizontalBoxes, Tensor], 22 | gt_bboxes: Union[QuadriBoxes, Tensor]) -> Tensor: 23 | """Get box regression transformation deltas that can be used to 24 | transform the ``bboxes`` into the ``gt_bboxes``. 25 | 26 | Args: 27 | bboxes (:obj:`HorizontalBoxes` or Tensor): Source boxes, e.g., 28 | object proposals. 29 | gt_bboxes (:obj:`QuadriBoxes` or Tensor): Target of the 30 | transformation, e.g., ground-truth boxes. 31 | Returns: 32 | Tensor: Box transformation deltas 33 | """ 34 | 35 | assert bboxes.size(0) == gt_bboxes.size(0) 36 | assert bboxes.size(-1) == 4 37 | assert gt_bboxes.size(-1) == 8 38 | 39 | bboxes = get_box_tensor(bboxes) 40 | 41 | if not isinstance(gt_bboxes, QuadriBoxes): 42 | gt_bboxes = QuadriBoxes(gt_bboxes) 43 | gt_bboxes = gt_bboxes.convert_to('hbox').tensor 44 | 45 | encoded_bboxes = bbox2delta(bboxes, gt_bboxes, self.means, self.stds) 46 | return encoded_bboxes 47 | -------------------------------------------------------------------------------- /mmrotate/models/task_modules/coders/delta_xywh_hbbox_coder.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from typing import Union 3 | 4 | from mmdet.models.task_modules.coders import DeltaXYWHBBoxCoder 5 | from mmdet.models.task_modules.coders.delta_xywh_bbox_coder import bbox2delta 6 | from mmdet.structures.bbox import HorizontalBoxes, get_box_tensor 7 | from torch import Tensor 8 | 9 | from mmrotate.registry import TASK_UTILS 10 | from mmrotate.structures.bbox import RotatedBoxes 11 | 12 | 13 | @TASK_UTILS.register_module() 14 | class DeltaXYWHHBBoxCoder(DeltaXYWHBBoxCoder): 15 | """Delta XYWH HBBox coder. 16 | 17 | This coder is almost the same as `DeltaXYWHBBoxCoder`. Besides the 18 | gt_bboxes of encode is :obj:`RotatedBoxes`. 19 | """ 20 | 21 | def encode(self, bboxes: Union[HorizontalBoxes, Tensor], 22 | gt_bboxes: Union[RotatedBoxes, Tensor]) -> Tensor: 23 | """Get box regression transformation deltas that can be used to 24 | transform the ``bboxes`` into the ``gt_bboxes``. 25 | 26 | Args: 27 | bboxes (:obj:`HorizontalBoxes` or Tensor): Source boxes, e.g., 28 | object proposals. 29 | gt_bboxes (:obj:`RotatedBoxes` or Tensor): Target of the 30 | transformation, e.g., ground-truth boxes. 31 | Returns: 32 | Tensor: Box transformation deltas 33 | """ 34 | 35 | assert bboxes.size(0) == gt_bboxes.size(0) 36 | assert bboxes.size(-1) == 4 37 | assert gt_bboxes.size(-1) == 5 38 | 39 | bboxes = get_box_tensor(bboxes) 40 | 41 | if not isinstance(gt_bboxes, RotatedBoxes): 42 | gt_bboxes = RotatedBoxes(gt_bboxes) 43 | gt_bboxes = gt_bboxes.convert_to('hbox').tensor 44 | 45 | encoded_bboxes = bbox2delta(bboxes, gt_bboxes, self.means, self.stds) 46 | return encoded_bboxes 47 | -------------------------------------------------------------------------------- /configs/whollywood/whollywood-ms_rr-1x-dota-p2r-pseudo.py: -------------------------------------------------------------------------------- 1 | _base_ = 'whollywood-1x-dota-p2r-pseudo.py' 2 | 3 | train_pipeline = [ 4 | dict(type='mmdet.LoadImageFromFile', backend_args={{_base_.backend_args}}), 5 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 6 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 7 | # This modify labels to (cls, ws) format. ws: 0=RBox, 1=HBox, 2=Point 8 | dict(type='ConvertWeakSupervision', 9 | point_proportion=1.0, 10 | hbox_proportion=0.0, 11 | modify_labels=True), 12 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 13 | dict( 14 | type='mmdet.RandomFlip', 15 | prob=0.75, 16 | direction=['horizontal', 'vertical', 'diagonal']), 17 | dict(type='mmdet.RandomShift', prob=0.5, max_shift_px=16), 18 | dict(type='RandomRotate', prob=1, angle_range=180), 19 | dict(type='mmdet.PackDetInputs') 20 | ] 21 | 22 | test_pipeline = [ 23 | dict(type='mmdet.LoadImageFromFile', backend_args={{_base_.backend_args}}), 24 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 25 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 26 | dict(type='ConvertWeakSupervision', 27 | point_proportion=1.0, 28 | hbox_proportion=0.0, 29 | modify_labels=True), 30 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 31 | dict(type='mmdet.PackDetInputs') 32 | ] 33 | 34 | data_root = 'data/split_ms_dota/' 35 | 36 | train_dataloader = dict( 37 | dataset=dict(data_root=data_root, pipeline=train_pipeline)) 38 | val_dataloader = dict(dataset=dict(data_root=data_root)) 39 | test_dataloader = dict( 40 | dataset=dict(data_root=data_root, pipeline=test_pipeline)) 41 | 42 | test_evaluator = dict( 43 | outfile_prefix='data/split_ms_dota/whollywood_pseudo_labels') 44 | -------------------------------------------------------------------------------- /mmrotate/visualization/palette.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from typing import List, Tuple, Union 3 | 4 | import mmcv 5 | import numpy as np 6 | from mmengine.utils import is_str 7 | 8 | 9 | def get_palette(palette: Union[List[tuple], str, tuple], 10 | num_classes: int) -> List[Tuple[int]]: 11 | """Get palette from various inputs. 12 | 13 | Args: 14 | palette (list[tuple] | str | tuple): palette inputs. 15 | num_classes (int): the number of classes. 16 | Returns: 17 | list[tuple[int]]: A list of color tuples. 18 | """ 19 | assert isinstance(num_classes, int) 20 | 21 | if isinstance(palette, list): 22 | dataset_palette = palette 23 | elif isinstance(palette, tuple): 24 | dataset_palette = [palette] * num_classes 25 | elif palette == 'random' or palette is None: 26 | state = np.random.get_state() 27 | # random color 28 | np.random.seed(42) 29 | palette = np.random.randint(0, 256, size=(num_classes, 3)) 30 | np.random.set_state(state) 31 | dataset_palette = [tuple(c) for c in palette] 32 | elif palette == 'dota': 33 | from mmrotate.datasets import DOTADataset 34 | dataset_palette = DOTADataset.METAINFO['palette'] 35 | elif palette == 'sar': 36 | from mmrotate.datasets import SARDataset 37 | dataset_palette = SARDataset.METAINFO['palette'] 38 | elif palette == 'hrsc': 39 | from mmrotate.datasets import HRSCDataset 40 | dataset_palette = HRSCDataset.METAINFO['palette'] 41 | elif is_str(palette): 42 | dataset_palette = [mmcv.color_val(palette)[::-1]] * num_classes 43 | else: 44 | raise TypeError(f'Invalid type for palette: {type(palette)}') 45 | 46 | assert len(dataset_palette) >= num_classes, \ 47 | 'The length of palette should not be less than `num_classes`.' 48 | return dataset_palette 49 | -------------------------------------------------------------------------------- /mmrotate/utils/setup_env.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | import datetime 3 | import warnings 4 | 5 | from mmengine import DefaultScope 6 | 7 | 8 | def register_all_modules(init_default_scope: bool = True) -> None: 9 | """Register all modules in mmrotate into the registries. 10 | 11 | Args: 12 | init_default_scope (bool): Whether initialize the mmrotate default scope. 13 | When `init_default_scope=True`, the global default scope will be 14 | set to `mmrotate`, anmmrotate all registries will build modules from mmrotate's 15 | registry node. To understand more about the registry, please refer 16 | to https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/registry.md 17 | Defaults to True. 18 | """ # noqa 19 | import mmrotate.datasets # noqa: F401,F403 20 | import mmrotate.evaluation # noqa: F401,F403 21 | import mmrotate.models # noqa: F401,F403 22 | import mmrotate.visualization # noqa: F401,F403 23 | 24 | if init_default_scope: 25 | never_created = DefaultScope.get_current_instance() is None \ 26 | or not DefaultScope.check_instance_created('mmrotate') 27 | if never_created: 28 | DefaultScope.get_instance('mmrotate', scope_name='mmrotate') 29 | return 30 | current_scope = DefaultScope.get_current_instance() 31 | if current_scope.scope_name != 'mmrotate': 32 | warnings.warn('The current default scope ' 33 | f'"{current_scope.scope_name}" is not "mmrotate", ' 34 | '`register_all_modules` will force the current' 35 | 'default scope to be "mmrotate". If this is not ' 36 | 'expected, please set `init_default_scope=False`.') 37 | # avoid name conflict 38 | new_instance_name = f'mmrotate-{datetime.datetime.now()}' 39 | DefaultScope.get_instance(new_instance_name, scope_name='mmrotate') 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .nox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | .hypothesis/ 49 | .pytest_cache/ 50 | .idea/* 51 | 52 | # Translations 53 | *.mo 54 | *.pot 55 | 56 | # Django stuff: 57 | *.log 58 | local_settings.py 59 | db.sqlite3 60 | 61 | # Flask stuff: 62 | instance/ 63 | .webassets-cache 64 | 65 | # Scrapy stuff: 66 | .scrapy 67 | 68 | # Sphinx documentation 69 | docs/en/_build/ 70 | docs/zh_cn/_build/ 71 | src 72 | 73 | # PyBuilder 74 | target/ 75 | 76 | # Jupyter Notebook 77 | .ipynb_checkpoints 78 | 79 | # IPython 80 | profile_default/ 81 | ipython_config.py 82 | 83 | # pyenv 84 | .python-version 85 | 86 | # celery beat schedule file 87 | celerybeat-schedule 88 | 89 | # SageMath parsed files 90 | *.sage.py 91 | 92 | # Environments 93 | .env 94 | .venv 95 | env/ 96 | venv/ 97 | ENV/ 98 | env.bak/ 99 | venv.bak/ 100 | 101 | # Spyder project settings 102 | .spyderproject 103 | .spyproject 104 | 105 | # Rope project settings 106 | .ropeproject 107 | 108 | # mkdocs documentation 109 | /site 110 | 111 | # mypy 112 | .mypy_cache/ 113 | .dmypy.json 114 | dmypy.json 115 | 116 | # Pyre type checker 117 | .pyre/ 118 | .DS_Store 119 | .idea 120 | *work_dirs* 121 | data/ 122 | data 123 | tmp 124 | 125 | # custom 126 | mmrotate/.mim 127 | -------------------------------------------------------------------------------- /mmrotate/datasets/transforms/loading.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from typing import Sequence, Union 3 | 4 | import mmcv 5 | from mmcv.transforms import BaseTransform 6 | 7 | from mmrotate.registry import TRANSFORMS 8 | 9 | 10 | @TRANSFORMS.register_module() 11 | class LoadPatchFromNDArray(BaseTransform): 12 | """Load a patch from the huge image w.r.t ``results['patch']``. 13 | 14 | Requaired Keys: 15 | 16 | - img 17 | - patch 18 | 19 | Modified Keys: 20 | 21 | - img 22 | - img_path 23 | - img_shape 24 | - ori_shape 25 | 26 | Args: 27 | pad_val (float or Sequence[float]): Values to be filled in padding 28 | areas. Defaults to 0. 29 | """ 30 | 31 | def __init__(self, 32 | pad_val: Union[float, Sequence[float]] = 0, 33 | **kwargs) -> None: 34 | self.pad_val = pad_val 35 | 36 | def transform(self, results: dict) -> dict: 37 | """Transform function to add image meta information. 38 | 39 | Args: 40 | results (dict): Result dict with image array in ``results['img']`` 41 | and patch position in ``results['patch']``. 42 | 43 | Returns: 44 | dict: The dict contains loaded patch and meta information. 45 | """ 46 | image = results['img'] 47 | img_h, img_w = image.shape[:2] 48 | 49 | patch_xmin, patch_ymin, patch_xmax, patch_ymax = results['patch'] 50 | assert (patch_xmin < img_w) and (patch_xmax >= 0) and \ 51 | (patch_ymin < img_h) and (patch_ymax >= 0) 52 | x1 = max(patch_xmin, 0) 53 | y1 = max(patch_ymin, 0) 54 | x2 = min(patch_xmax, img_w) 55 | y2 = min(patch_ymax, img_h) 56 | padding = (x1 - patch_xmin, y1 - patch_ymin, patch_xmax - x2, 57 | patch_ymax - y2) 58 | 59 | patch = image[y1:y2, x1:x2] 60 | if any(padding): 61 | patch = mmcv.impad(patch, padding=padding, pad_val=self.pad_val) 62 | 63 | results['img_path'] = None 64 | results['img'] = patch 65 | results['img_shape'] = patch.shape[:2] 66 | results['ori_shape'] = patch.shape[:2] 67 | return results 68 | -------------------------------------------------------------------------------- /configs/_base_/datasets/sardet100k.py: -------------------------------------------------------------------------------- 1 | # dataset settings 2 | dataset_type = 'SAR_Det_Finegrained_Dataset' 3 | data_root = 'data/sardet100k/' 4 | backend_args = None 5 | 6 | train_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 8 | dict(type='mmdet.LoadAnnotations', with_bbox=True), 9 | dict(type='mmdet.Resize', scale=(800, 800), keep_ratio=False), 10 | dict( 11 | type='mmdet.RandomFlip', 12 | prob=0.75, 13 | direction=['horizontal', 'vertical', 'diagonal']), 14 | dict(type='mmdet.PackDetInputs') 15 | ] 16 | test_pipeline = [ 17 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 18 | dict(type='mmdet.Resize', scale=(800, 800), keep_ratio=False), 19 | # If you don't have a gt annotation, delete the pipeline 20 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='hbox'), 21 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 22 | dict( 23 | type='mmdet.PackDetInputs', 24 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 25 | 'scale_factor')) 26 | ] 27 | train_dataloader = dict( 28 | batch_size=4, 29 | num_workers=2, 30 | persistent_workers=True, 31 | sampler=dict(type='DefaultSampler', shuffle=True), 32 | batch_sampler=None, 33 | dataset=dict( 34 | type=dataset_type, 35 | data_root=data_root, 36 | ann_file='Annotations/train.json', 37 | data_prefix=dict(img='JPEGImages/train/'), 38 | filter_cfg=dict(filter_empty_gt=True, min_size=16), 39 | pipeline=train_pipeline, 40 | backend_args=backend_args)) 41 | val_dataloader = dict( 42 | batch_size=1, 43 | num_workers=2, 44 | persistent_workers=True, 45 | drop_last=False, 46 | sampler=dict(type='DefaultSampler', shuffle=False), 47 | dataset=dict( 48 | type=dataset_type, 49 | data_root=data_root, 50 | ann_file='Annotations/train.json', 51 | data_prefix=dict(img='JPEGImages/train/'), 52 | test_mode=True, 53 | pipeline=test_pipeline, 54 | backend_args=backend_args)) 55 | test_dataloader = val_dataloader 56 | 57 | val_evaluator = dict(type='DOTAMetric', metric='mAP') 58 | test_evaluator = val_evaluator 59 | -------------------------------------------------------------------------------- /configs/_base_/datasets/diatom.py: -------------------------------------------------------------------------------- 1 | # dataset settings 2 | dataset_type = 'DIATOMDataset' 3 | data_root = 'data/diatom/' 4 | backend_args = None 5 | 6 | train_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 8 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 9 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 10 | dict(type='mmdet.FixShapeResize', width=1024, height=1024, keep_ratio=True), 11 | dict( 12 | type='mmdet.RandomFlip', 13 | prob=0.75, 14 | direction=['horizontal', 'vertical', 'diagonal']), 15 | dict(type='mmdet.PackDetInputs') 16 | ] 17 | val_pipeline = [ 18 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 19 | dict(type='mmdet.FixShapeResize', width=1024, height=1024, keep_ratio=True), 20 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 21 | # avoid bboxes being resized 22 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 23 | dict( 24 | type='mmdet.PackDetInputs', 25 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 26 | 'scale_factor')) 27 | ] 28 | test_pipeline = [ 29 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 30 | dict(type='mmdet.FixShapeResize', width=1024, height=1024, keep_ratio=True), 31 | dict( 32 | type='mmdet.PackDetInputs', 33 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 34 | 'scale_factor')) 35 | ] 36 | train_dataloader = dict( 37 | batch_size=4, 38 | num_workers=2, 39 | persistent_workers=True, 40 | sampler=dict(type='DefaultSampler', shuffle=True), 41 | batch_sampler=None, 42 | dataset=dict( 43 | type=dataset_type, 44 | data_root=data_root, 45 | data_prefix=dict(sub_data_root='.'), 46 | filter_cfg=dict(filter_empty_gt=True), 47 | pipeline=train_pipeline, 48 | backend_args=backend_args)) 49 | val_dataloader = dict( 50 | batch_size=4, 51 | num_workers=2, 52 | persistent_workers=True, 53 | drop_last=False, 54 | sampler=dict(type='DefaultSampler', shuffle=False), 55 | dataset=dict( 56 | type=dataset_type, 57 | data_root=data_root, 58 | data_prefix=dict(sub_data_root=''), 59 | test_mode=True, 60 | pipeline=val_pipeline, 61 | backend_args=backend_args)) 62 | test_dataloader = val_dataloader 63 | 64 | val_evaluator = dict(type='DOTAMetric', metric='mAP') 65 | test_evaluator = val_evaluator 66 | -------------------------------------------------------------------------------- /configs/_base_/datasets/hrsc.py: -------------------------------------------------------------------------------- 1 | # dataset settings 2 | dataset_type = 'HRSCDataset' 3 | data_root = 'data/hrsc/' 4 | backend_args = None 5 | 6 | train_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 8 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 9 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 10 | dict(type='mmdet.Resize', scale=(800, 512), keep_ratio=True), 11 | dict( 12 | type='mmdet.RandomFlip', 13 | prob=0.75, 14 | direction=['horizontal', 'vertical', 'diagonal']), 15 | dict(type='mmdet.PackDetInputs') 16 | ] 17 | val_pipeline = [ 18 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 19 | dict(type='mmdet.Resize', scale=(800, 512), keep_ratio=True), 20 | # avoid bboxes being resized 21 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 22 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 23 | dict( 24 | type='mmdet.PackDetInputs', 25 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 26 | 'scale_factor')) 27 | ] 28 | test_pipeline = [ 29 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 30 | dict(type='mmdet.Resize', scale=(800, 512), keep_ratio=True), 31 | dict( 32 | type='mmdet.PackDetInputs', 33 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 34 | 'scale_factor')) 35 | ] 36 | train_dataloader = dict( 37 | batch_size=2, 38 | num_workers=2, 39 | persistent_workers=True, 40 | sampler=dict(type='DefaultSampler', shuffle=True), 41 | batch_sampler=None, 42 | dataset=dict( 43 | type=dataset_type, 44 | data_root=data_root, 45 | ann_file='ImageSets/trainval.txt', 46 | data_prefix=dict(sub_data_root='FullDataSet/'), 47 | filter_cfg=dict(filter_empty_gt=True), 48 | pipeline=train_pipeline, 49 | backend_args=backend_args)) 50 | val_dataloader = dict( 51 | batch_size=1, 52 | num_workers=2, 53 | persistent_workers=True, 54 | drop_last=False, 55 | sampler=dict(type='DefaultSampler', shuffle=False), 56 | dataset=dict( 57 | type=dataset_type, 58 | data_root=data_root, 59 | ann_file='ImageSets/test.txt', 60 | data_prefix=dict(sub_data_root='FullDataSet/'), 61 | test_mode=True, 62 | pipeline=val_pipeline, 63 | backend_args=backend_args)) 64 | test_dataloader = val_dataloader 65 | 66 | val_evaluator = dict(type='DOTAMetric', metric='mAP') 67 | test_evaluator = val_evaluator 68 | -------------------------------------------------------------------------------- /configs/_base_/datasets/rsdd.py: -------------------------------------------------------------------------------- 1 | # dataset settings 2 | dataset_type = 'mmdet.CocoDataset' 3 | data_root = 'data/rsdd/' 4 | backend_args = None 5 | 6 | train_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 8 | dict( 9 | type='mmdet.LoadAnnotations', 10 | with_bbox=True, 11 | with_mask=True, 12 | poly2mask=False), 13 | dict(type='ConvertMask2BoxType', box_type='rbox'), 14 | dict(type='mmdet.Resize', scale=(512, 512), keep_ratio=True), 15 | dict( 16 | type='mmdet.RandomFlip', 17 | prob=0.75, 18 | direction=['horizontal', 'vertical', 'diagonal']), 19 | dict(type='mmdet.PackDetInputs') 20 | ] 21 | val_pipeline = [ 22 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 23 | dict(type='mmdet.Resize', scale=(512, 512), keep_ratio=True), 24 | # avoid bboxes being resized 25 | dict( 26 | type='mmdet.LoadAnnotations', 27 | with_bbox=True, 28 | with_mask=True, 29 | poly2mask=False), 30 | dict(type='ConvertMask2BoxType', box_type='qbox'), 31 | dict( 32 | type='mmdet.PackDetInputs', 33 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 34 | 'scale_factor', 'instances')) 35 | ] 36 | test_pipeline = [ 37 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 38 | dict(type='mmdet.Resize', scale=(512, 512), keep_ratio=True), 39 | dict( 40 | type='mmdet.PackDetInputs', 41 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 42 | 'scale_factor')) 43 | ] 44 | 45 | metainfo = dict(classes=('ship', )) 46 | 47 | train_dataloader = dict( 48 | batch_size=2, 49 | num_workers=2, 50 | persistent_workers=True, 51 | sampler=dict(type='DefaultSampler', shuffle=True), 52 | batch_sampler=None, 53 | dataset=dict( 54 | type=dataset_type, 55 | metainfo=metainfo, 56 | data_root=data_root, 57 | ann_file='ImageSets/train.json', 58 | data_prefix=dict(img='JPEGImages/'), 59 | filter_cfg=dict(filter_empty_gt=True), 60 | pipeline=train_pipeline, 61 | backend_args=backend_args)) 62 | val_dataloader = dict( 63 | batch_size=1, 64 | num_workers=2, 65 | persistent_workers=True, 66 | drop_last=False, 67 | sampler=dict(type='DefaultSampler', shuffle=False), 68 | dataset=dict( 69 | type=dataset_type, 70 | metainfo=metainfo, 71 | data_root=data_root, 72 | ann_file='ImageSets/test.json', 73 | data_prefix=dict(img='JPEGImages/'), 74 | test_mode=True, 75 | pipeline=val_pipeline, 76 | backend_args=backend_args)) 77 | test_dataloader = val_dataloader 78 | 79 | val_evaluator = dict(type='RotatedCocoMetric', metric='bbox') 80 | 81 | test_evaluator = val_evaluator 82 | -------------------------------------------------------------------------------- /configs/_base_/datasets/ssdd.py: -------------------------------------------------------------------------------- 1 | # dataset settings 2 | dataset_type = 'mmdet.CocoDataset' 3 | data_root = 'data/ssdd/' 4 | backend_args = None 5 | 6 | train_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 8 | dict( 9 | type='mmdet.LoadAnnotations', 10 | with_bbox=True, 11 | with_mask=True, 12 | poly2mask=False), 13 | dict(type='ConvertMask2BoxType', box_type='rbox'), 14 | dict(type='mmdet.Resize', scale=(512, 512), keep_ratio=True), 15 | dict( 16 | type='mmdet.RandomFlip', 17 | prob=0.75, 18 | direction=['horizontal', 'vertical', 'diagonal']), 19 | dict(type='mmdet.PackDetInputs') 20 | ] 21 | val_pipeline = [ 22 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 23 | dict(type='mmdet.Resize', scale=(512, 512), keep_ratio=True), 24 | # avoid bboxes being resized 25 | dict( 26 | type='mmdet.LoadAnnotations', 27 | with_bbox=True, 28 | with_mask=True, 29 | poly2mask=False), 30 | dict(type='ConvertMask2BoxType', box_type='qbox'), 31 | dict( 32 | type='mmdet.PackDetInputs', 33 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 34 | 'scale_factor', 'instances')) 35 | ] 36 | test_pipeline = [ 37 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 38 | dict(type='mmdet.Resize', scale=(512, 512), keep_ratio=True), 39 | dict( 40 | type='mmdet.PackDetInputs', 41 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 42 | 'scale_factor')) 43 | ] 44 | 45 | metainfo = dict(classes=('ship', )) 46 | 47 | train_dataloader = dict( 48 | batch_size=2, 49 | num_workers=2, 50 | persistent_workers=True, 51 | sampler=dict(type='DefaultSampler', shuffle=True), 52 | batch_sampler=None, 53 | dataset=dict( 54 | type=dataset_type, 55 | metainfo=metainfo, 56 | data_root=data_root, 57 | ann_file='train/train.json', 58 | data_prefix=dict(img='train/images/'), 59 | filter_cfg=dict(filter_empty_gt=True), 60 | pipeline=train_pipeline, 61 | backend_args=backend_args)) 62 | val_dataloader = dict( 63 | batch_size=1, 64 | num_workers=2, 65 | persistent_workers=True, 66 | drop_last=False, 67 | sampler=dict(type='DefaultSampler', shuffle=False), 68 | dataset=dict( 69 | type=dataset_type, 70 | metainfo=metainfo, 71 | data_root=data_root, 72 | ann_file='test/all/test.json', 73 | data_prefix=dict(img='test/all/images/'), 74 | test_mode=True, 75 | pipeline=val_pipeline, 76 | backend_args=backend_args)) 77 | test_dataloader = val_dataloader 78 | 79 | val_evaluator = dict(type='RotatedCocoMetric', metric='bbox') 80 | 81 | test_evaluator = val_evaluator 82 | -------------------------------------------------------------------------------- /configs/_base_/datasets/hrsid.py: -------------------------------------------------------------------------------- 1 | # dataset settings 2 | dataset_type = 'mmdet.CocoDataset' 3 | data_root = 'data/HRSID_JPG/' 4 | backend_args = None 5 | 6 | train_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 8 | dict( 9 | type='mmdet.LoadAnnotations', 10 | with_bbox=True, 11 | with_mask=True, 12 | poly2mask=False), 13 | dict(type='ConvertMask2BoxType', box_type='rbox'), 14 | dict(type='mmdet.Resize', scale=(800, 800), keep_ratio=True), 15 | dict(type='mmdet.FilterAnnotations', min_gt_bbox_wh=(1e-2, 1e-2)), 16 | dict( 17 | type='mmdet.RandomFlip', 18 | prob=0.75, 19 | direction=['horizontal', 'vertical', 'diagonal']), 20 | dict(type='mmdet.PackDetInputs') 21 | ] 22 | val_pipeline = [ 23 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 24 | dict(type='mmdet.Resize', scale=(800, 800), keep_ratio=True), 25 | # avoid bboxes being resized 26 | dict( 27 | type='mmdet.LoadAnnotations', 28 | with_bbox=True, 29 | with_mask=True, 30 | poly2mask=False), 31 | dict(type='ConvertMask2BoxType', box_type='qbox'), 32 | dict( 33 | type='mmdet.PackDetInputs', 34 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 35 | 'scale_factor', 'instances')) 36 | ] 37 | test_pipeline = [ 38 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 39 | dict(type='mmdet.Resize', scale=(800, 800), keep_ratio=True), 40 | dict( 41 | type='mmdet.PackDetInputs', 42 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 43 | 'scale_factor')) 44 | ] 45 | 46 | metainfo = dict(classes=('ship', )) 47 | 48 | train_dataloader = dict( 49 | batch_size=2, 50 | num_workers=2, 51 | persistent_workers=True, 52 | sampler=dict(type='DefaultSampler', shuffle=True), 53 | batch_sampler=None, 54 | dataset=dict( 55 | type=dataset_type, 56 | metainfo=metainfo, 57 | data_root=data_root, 58 | ann_file='annotations/train2017.json', 59 | data_prefix=dict(img='JPEGImages/'), 60 | filter_cfg=dict(filter_empty_gt=True), 61 | pipeline=train_pipeline, 62 | backend_args=backend_args)) 63 | val_dataloader = dict( 64 | batch_size=1, 65 | num_workers=2, 66 | persistent_workers=True, 67 | drop_last=False, 68 | sampler=dict(type='DefaultSampler', shuffle=False), 69 | dataset=dict( 70 | type=dataset_type, 71 | metainfo=metainfo, 72 | data_root=data_root, 73 | ann_file='annotations/test2017.json', 74 | data_prefix=dict(img='JPEGImages/'), 75 | test_mode=True, 76 | pipeline=val_pipeline, 77 | backend_args=backend_args)) 78 | test_dataloader = val_dataloader 79 | 80 | val_evaluator = dict(type='RotatedCocoMetric', metric='bbox') 81 | 82 | test_evaluator = val_evaluator 83 | -------------------------------------------------------------------------------- /configs/_base_/datasets/srsdd.py: -------------------------------------------------------------------------------- 1 | # dataset settings 2 | dataset_type = 'mmdet.CocoDataset' 3 | data_root = 'data/srsdd/' 4 | backend_args = None 5 | 6 | train_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 8 | dict( 9 | type='mmdet.LoadAnnotations', 10 | with_bbox=True, 11 | with_mask=True, 12 | poly2mask=False), 13 | dict(type='ConvertMask2BoxType', box_type='rbox'), 14 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 15 | dict( 16 | type='mmdet.RandomFlip', 17 | prob=0.75, 18 | direction=['horizontal', 'vertical', 'diagonal']), 19 | dict(type='mmdet.PackDetInputs') 20 | ] 21 | val_pipeline = [ 22 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 23 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 24 | # avoid bboxes being resized 25 | dict( 26 | type='mmdet.LoadAnnotations', 27 | with_bbox=True, 28 | with_mask=True, 29 | poly2mask=False), 30 | dict(type='ConvertMask2BoxType', box_type='qbox'), 31 | dict( 32 | type='mmdet.PackDetInputs', 33 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 34 | 'scale_factor', 'instances')) 35 | ] 36 | test_pipeline = [ 37 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 38 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 39 | dict( 40 | type='mmdet.PackDetInputs', 41 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 42 | 'scale_factor')) 43 | ] 44 | 45 | metainfo = dict( 46 | classes=('Container', 'Dredger', 'LawEnforce', 'Cell-Container', 'ore-oil', 47 | 'Fishing')) 48 | 49 | train_dataloader = dict( 50 | batch_size=2, 51 | num_workers=2, 52 | persistent_workers=True, 53 | sampler=dict(type='DefaultSampler', shuffle=True), 54 | batch_sampler=None, 55 | dataset=dict( 56 | type=dataset_type, 57 | metainfo=metainfo, 58 | data_root=data_root, 59 | ann_file='train/train.json', 60 | data_prefix=dict(img='train/images/'), 61 | filter_cfg=dict(filter_empty_gt=True), 62 | pipeline=train_pipeline, 63 | backend_args=backend_args)) 64 | val_dataloader = dict( 65 | batch_size=1, 66 | num_workers=2, 67 | persistent_workers=True, 68 | drop_last=False, 69 | sampler=dict(type='DefaultSampler', shuffle=False), 70 | dataset=dict( 71 | type=dataset_type, 72 | metainfo=metainfo, 73 | data_root=data_root, 74 | ann_file='test/test.json', 75 | data_prefix=dict(img='test/images/'), 76 | test_mode=True, 77 | pipeline=val_pipeline, 78 | backend_args=backend_args)) 79 | test_dataloader = val_dataloader 80 | 81 | val_evaluator = dict(type='RotatedCocoMetric', metric='bbox') 82 | 83 | test_evaluator = val_evaluator 84 | -------------------------------------------------------------------------------- /configs/_base_/datasets/sku110k.py: -------------------------------------------------------------------------------- 1 | # dataset settings 2 | dataset_type = 'SKU110KDataset' 3 | data_root = 'data/sku110k/' 4 | backend_args = None 5 | 6 | train_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 8 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='rbox'), 9 | dict(type='mmdet.FixShapeResize', width=800, height=800, keep_ratio=True), 10 | dict( 11 | type='mmdet.RandomFlip', 12 | prob=0.75, 13 | direction=['horizontal', 'vertical', 'diagonal']), 14 | dict(type='mmdet.PackDetInputs') 15 | ] 16 | val_pipeline = [ 17 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 18 | dict(type='mmdet.FixShapeResize', width=800, height=800, keep_ratio=True), 19 | # avoid bboxes being resized 20 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='rbox'), 21 | dict( 22 | type='mmdet.PackDetInputs', 23 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 24 | 'scale_factor')) 25 | ] 26 | test_pipeline = [ 27 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 28 | dict(type='mmdet.Resize', scale=(800, 800), keep_ratio=True), 29 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='rbox'), #sku 30 | dict( 31 | type='mmdet.PackDetInputs', 32 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 33 | 'scale_factor')) 34 | ] 35 | train_dataloader = dict( 36 | batch_size=2, 37 | num_workers=2, 38 | persistent_workers=True, 39 | sampler=dict(type='DefaultSampler', shuffle=True), 40 | batch_sampler=None, 41 | dataset=dict( 42 | type=dataset_type, 43 | data_root=data_root, 44 | ann_file='sku110k-r_train.json', 45 | data_prefix=dict(img_path='images/train/'), 46 | filter_cfg=dict(filter_empty_gt=True), 47 | pipeline=train_pipeline)) 48 | val_dataloader = dict( 49 | batch_size=4, 50 | num_workers=2, 51 | persistent_workers=True, 52 | drop_last=False, 53 | sampler=dict(type='DefaultSampler', shuffle=False), 54 | dataset=dict( 55 | type=dataset_type, 56 | data_root=data_root, 57 | ann_file='sku110k-r_val.json', 58 | data_prefix=dict(img_path='images/val/'), 59 | filter_cfg=dict(filter_empty_gt=True), 60 | test_mode=True, 61 | pipeline=val_pipeline)) 62 | test_dataloader = dict( 63 | batch_size=4, 64 | num_workers=2, 65 | persistent_workers=True, 66 | drop_last=False, 67 | sampler=dict(type='DefaultSampler', shuffle=False), 68 | dataset=dict( 69 | type=dataset_type, 70 | data_root=data_root, 71 | ann_file='sku110k-r_val.json', 72 | data_prefix=dict(img_path='images/val/'), 73 | test_mode=True, 74 | pipeline=test_pipeline)) 75 | 76 | val_evaluator = dict(type='DOTAMetric', metric='mAP', iou_thrs=[0.5, 0.75]) 77 | test_evaluator = val_evaluator 78 | -------------------------------------------------------------------------------- /tools/data/dota/README.md: -------------------------------------------------------------------------------- 1 | # Preparing DOTA Dataset 2 | 3 | 4 | 5 | ```bibtex 6 | @InProceedings{Xia_2018_CVPR, 7 | author = {Xia, Gui-Song and Bai, Xiang and Ding, Jian and Zhu, Zhen and Belongie, Serge and Luo, Jiebo and Datcu, Mihai and Pelillo, Marcello and Zhang, Liangpei}, 8 | title = {DOTA: A Large-Scale Dataset for Object Detection in Aerial Images}, 9 | booktitle = {The IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, 10 | month = {June}, 11 | year = {2018} 12 | } 13 | ``` 14 | 15 | ## download dota dataset 16 | 17 | The dota dataset can be downloaded from [here](https://captain-whu.github.io/DOTA/dataset.html). 18 | 19 | The data structure is as follows: 20 | 21 | ```none 22 | mmrotate 23 | ├── mmrotate 24 | ├── tools 25 | ├── configs 26 | ├── data 27 | │ ├── DOTA 28 | │ │ ├── train 29 | │ │ ├── val 30 | │ │ ├── test 31 | ``` 32 | 33 | ## split dota dataset 34 | 35 | Please crop the original images into 1024×1024 patches with an overlap of 200 by run 36 | 37 | ```shell 38 | python tools/data/dota/split/img_split.py --base-json \ 39 | tools/data/dota/split/split_configs/ss_trainval.json 40 | 41 | python tools/data/dota/split/img_split.py --base-json \ 42 | tools/data/dota/split/split_configs/ss_test.json 43 | ``` 44 | 45 | If you want to get a multiple scale dataset, you can run the following command. 46 | 47 | ```shell 48 | python tools/data/dota/split/img_split.py --base-json \ 49 | tools/data/dota/split/split_configs/ms_trainval.json 50 | 51 | python tools/data/dota/split/img_split.py --base-json \ 52 | tools/data/dota/split/split_configs/ms_test.json 53 | ``` 54 | 55 | Please update the `img_dirs` and `ann_dirs` in json. 56 | 57 | The new data structure is as follows: 58 | 59 | ```none 60 | mmrotate 61 | ├── mmrotate 62 | ├── tools 63 | ├── configs 64 | ├── data 65 | │ ├── split_ss_dota 66 | │ │ ├── trainval 67 | │ │ │ ├── images 68 | │ │ │ ├── annfiles 69 | │ │ ├── test 70 | │ │ │ ├── images 71 | │ │ │ ├── annfiles 72 | ``` 73 | 74 | Please change `data_root` in `configs/_base_/datasets/dota.py` to `data/split_ss_dota`. 75 | 76 | ## Generating COCO style annotations 77 | 78 | Please convert the annotations from txt to json by run 79 | 80 | ```shell 81 | python tools/data/dota/dota2coco.py \ 82 | data/split_ss_dota/trainval/ \ 83 | data/split_ss_dota/trainval.json 84 | 85 | python tools/data/dota/dota2coco.py \ 86 | data/split_ss_dota/test/ \ 87 | data/split_ss_dota/test.json 88 | ``` 89 | 90 | The new data structure is as follows: 91 | 92 | ```none 93 | mmrotate 94 | ├── mmrotate 95 | ├── tools 96 | ├── configs 97 | ├── data 98 | │ ├── split_ss_dota 99 | │ │ ├── trainval 100 | │ │ │ ├── images 101 | │ │ │ ├── annfiles 102 | │ │ │ ├── trainval.json 103 | │ │ ├── test 104 | │ │ │ ├── images 105 | │ │ │ ├── annfiles 106 | │ │ │ ├── test.json 107 | ``` 108 | 109 | Please change `data_root` in `configs/_base_/datasets/dota_coco.py` to `data/split_ss_dota`. 110 | -------------------------------------------------------------------------------- /mmrotate/models/losses/h2rbox_v2_consistency_loss.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from typing import Optional 3 | 4 | import torch 5 | from mmdet.utils import ConfigType 6 | from torch import Tensor 7 | 8 | from mmrotate.registry import MODELS 9 | 10 | 11 | @MODELS.register_module() 12 | class H2RBoxV2ConsistencyLoss(torch.nn.Module): 13 | 14 | def __init__(self, 15 | loss_rot: ConfigType = dict( 16 | type='mmdet.SmoothL1Loss', loss_weight=1.0, beta=0.1), 17 | loss_flp: ConfigType = dict( 18 | type='mmdet.SmoothL1Loss', loss_weight=0.05, beta=0.1), 19 | use_snap_loss: bool = True, 20 | reduction: str = 'mean') -> None: 21 | super(H2RBoxV2ConsistencyLoss, self).__init__() 22 | self.loss_rot = MODELS.build(loss_rot) 23 | self.loss_flp = MODELS.build(loss_flp) 24 | self.use_snap_loss = use_snap_loss 25 | self.reduction = reduction 26 | 27 | def forward(self, 28 | pred_ori: Tensor, 29 | pred_rot: Tensor, 30 | pred_flp: Tensor, 31 | target_ori: Tensor, 32 | target_rot: Tensor, 33 | agnostic_mask: Optional[Tensor] = None, 34 | avg_factor: Optional[int] = None, 35 | reduction_override: Optional[str] = None) -> Tensor: 36 | """Forward function. 37 | 38 | Args: 39 | pred (Tensor): Predicted boxes. 40 | target (Tensor): Corresponding gt boxes. 41 | weight (Tensor): The weight of loss for each prediction. 42 | avg_factor (int, optional): Average factor that is used to average 43 | the loss. Defaults to None. 44 | reduction_override (str, optional): The reduction method used to 45 | override the original reduction method of the loss. 46 | Defaults to None. 47 | 48 | Returns: 49 | Calculated loss (Tensor) 50 | """ 51 | assert reduction_override in (None, 'none', 'mean', 'sum') 52 | reduction = ( 53 | reduction_override if reduction_override else self.reduction) 54 | 55 | d_ang_rot = (pred_ori - pred_rot) - (target_ori - target_rot) 56 | d_ang_flp = pred_ori + pred_flp 57 | 58 | if self.use_snap_loss: 59 | d_ang_rot = (d_ang_rot + torch.pi / 2) % torch.pi - torch.pi / 2 60 | d_ang_flp = (d_ang_flp + torch.pi / 2) % torch.pi - torch.pi / 2 61 | 62 | if agnostic_mask is not None: 63 | d_ang_rot[agnostic_mask] = 0 64 | d_ang_flp[agnostic_mask] = 0 65 | 66 | loss_rot = self.loss_rot( 67 | d_ang_rot, 68 | torch.zeros_like(d_ang_rot), 69 | reduction_override=reduction, 70 | avg_factor=avg_factor) 71 | loss_flp = self.loss_flp( 72 | d_ang_flp, 73 | torch.zeros_like(d_ang_flp), 74 | reduction_override=reduction, 75 | avg_factor=avg_factor) 76 | 77 | return loss_rot + loss_flp 78 | -------------------------------------------------------------------------------- /tools/analysis_tools/get_flops.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | import argparse 3 | 4 | import numpy as np 5 | import torch 6 | from mmengine.config import Config, DictAction 7 | 8 | from mmrotate.registry import MODELS 9 | from mmrotate.utils import register_all_modules 10 | 11 | try: 12 | from mmcv.cnn import get_model_complexity_info 13 | except ImportError: 14 | raise ImportError('Please upgrade mmcv to >0.6.2') 15 | 16 | 17 | def parse_args(): 18 | parser = argparse.ArgumentParser(description='Train a detector') 19 | parser.add_argument('config', help='train config file path') 20 | parser.add_argument( 21 | '--shape', 22 | type=int, 23 | nargs='+', 24 | default=[1024, 1024], 25 | help='input image size') 26 | parser.add_argument( 27 | '--cfg-options', 28 | nargs='+', 29 | action=DictAction, 30 | help='override some settings in the used config, the key-value pair ' 31 | 'in xxx=yyy format will be merged into config file. If the value to ' 32 | 'be overwritten is a list, it should be like key="[a,b]" or key=a,b ' 33 | 'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" ' 34 | 'Note that the quotation marks are necessary and that no white space ' 35 | 'is allowed.') 36 | parser.add_argument( 37 | '--size-divisor', 38 | type=int, 39 | default=32, 40 | help='Pad the input image, the minimum size that is divisible ' 41 | 'by size_divisor, -1 means do not pad the image.') 42 | args = parser.parse_args() 43 | return args 44 | 45 | 46 | def main(): 47 | register_all_modules() 48 | args = parse_args() 49 | 50 | if len(args.shape) == 1: 51 | h = w = args.shape[0] 52 | elif len(args.shape) == 2: 53 | h, w = args.shape 54 | else: 55 | raise ValueError('invalid input shape') 56 | ori_shape = (3, h, w) 57 | divisor = args.size_divisor 58 | if divisor > 0: 59 | h = int(np.ceil(h / divisor)) * divisor 60 | w = int(np.ceil(w / divisor)) * divisor 61 | 62 | input_shape = (3, h, w) 63 | 64 | cfg = Config.fromfile(args.config) 65 | if args.cfg_options is not None: 66 | cfg.merge_from_dict(args.cfg_options) 67 | 68 | model = MODELS.build(cfg.model) 69 | if torch.cuda.is_available(): 70 | model.cuda() 71 | model.eval() 72 | 73 | flops, params = get_model_complexity_info(model, input_shape) 74 | split_line = '=' * 30 75 | 76 | if divisor > 0 and \ 77 | input_shape != ori_shape: 78 | print(f'{split_line}\nUse size divisor set input shape ' 79 | f'from {ori_shape} to {input_shape}\n') 80 | print(f'{split_line}\nInput shape: {input_shape}\n' 81 | f'Flops: {flops}\nParams: {params}\n{split_line}') 82 | print('!!!Please be cautious if you use the results in papers. ' 83 | 'You may need to check if all ops are supported and verify that the ' 84 | 'flops computation is correct.') 85 | 86 | 87 | if __name__ == '__main__': 88 | main() 89 | -------------------------------------------------------------------------------- /mmrotate/models/task_modules/prior_generators/anchor_generator.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from typing import List, Tuple 3 | 4 | import torch 5 | from mmdet.models.task_modules import AnchorGenerator 6 | from mmdet.structures.bbox import HorizontalBoxes 7 | from torch import Tensor 8 | from torch.nn.modules.utils import _pair 9 | 10 | from mmrotate.registry import TASK_UTILS 11 | from mmrotate.structures.bbox import RotatedBoxes 12 | 13 | 14 | @TASK_UTILS.register_module() 15 | class FakeRotatedAnchorGenerator(AnchorGenerator): 16 | """Fake rotate anchor generator for 2D anchor-based detectors. Horizontal 17 | bounding box represented by (x,y,w,h,theta). 18 | 19 | Note: In mmrotate-0.x, the angle of anchor is always 0. If you want to 20 | load models in 0.x directly, please set the `angle_version` to 'None'. 21 | 22 | Args: 23 | angle_version (str, optional): Angle definition of rotated bbox. 24 | Can only be 'None', 'oc', 'le90', or 'le135'. 'None' means the 25 | angle of anchor is always 0. Defaults to None. 26 | """ 27 | 28 | def __init__(self, angle_version: str = None, **kwargs) -> None: 29 | super().__init__(**kwargs) 30 | self.angle_version = angle_version 31 | 32 | def single_level_grid_priors(self, 33 | featmap_size: Tuple[int], 34 | level_idx: int, 35 | dtype: torch.dtype = torch.float32, 36 | device: str = 'cuda') -> Tensor: 37 | """Generate grid anchors of a single level. 38 | 39 | Note: 40 | This function is usually called by method ``self.grid_priors``. 41 | 42 | Args: 43 | featmap_size (tuple[int]): Size of the feature maps. 44 | level_idx (int): The index of corresponding feature map level. 45 | dtype (obj:`torch.dtype`): Date type of points. Defaults to 46 | ``torch.float32``. 47 | device (str): The device the tensor will be put on. 48 | Defaults to ``cuda``. 49 | Returns: 50 | Tensor: Anchors in the overall feature maps. 51 | """ 52 | anchors = super().single_level_grid_priors( 53 | featmap_size, level_idx, dtype=dtype, device=device) 54 | anchors = HorizontalBoxes(anchors, clone=False) 55 | anchors = anchors.convert_to('rbox') 56 | if self.angle_version: 57 | anchors = anchors.regularize_boxes(self.angle_version) 58 | anchors = RotatedBoxes(anchors, clone=False) 59 | return anchors 60 | 61 | 62 | @TASK_UTILS.register_module() 63 | class PseudoRotatedAnchorGenerator(AnchorGenerator): 64 | """Non-Standard pseudo anchor generator that is used to generate valid 65 | flags only!""" 66 | 67 | def __init__(self, strides: List[int]) -> None: 68 | self.strides = [_pair(stride) for stride in strides] 69 | 70 | @property 71 | def num_base_priors(self) -> None: 72 | """list[int]: total number of base priors in a feature grid""" 73 | return [1 for _ in self.strides] 74 | -------------------------------------------------------------------------------- /configs/_base_/datasets/dior.py: -------------------------------------------------------------------------------- 1 | # dataset settings 2 | dataset_type = 'DIORDataset' 3 | data_root = 'data/dior/' 4 | backend_args = None 5 | 6 | train_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 8 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 9 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 10 | dict(type='mmdet.Resize', scale=(800, 800), keep_ratio=True), 11 | dict(type='RBoxClamp'), 12 | dict( 13 | type='mmdet.RandomFlip', 14 | prob=0.75, 15 | direction=['horizontal', 'vertical', 'diagonal']), 16 | dict(type='mmdet.PackDetInputs') 17 | ] 18 | val_pipeline = [ 19 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 20 | dict(type='mmdet.Resize', scale=(800, 800), keep_ratio=True), 21 | # avoid bboxes being resized 22 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 23 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 24 | dict( 25 | type='mmdet.PackDetInputs', 26 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 27 | 'scale_factor')) 28 | ] 29 | test_pipeline = [ 30 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 31 | dict(type='mmdet.Resize', scale=(800, 800), keep_ratio=True), 32 | dict( 33 | type='mmdet.PackDetInputs', 34 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 35 | 'scale_factor')) 36 | ] 37 | train_dataloader = dict( 38 | batch_size=4, 39 | num_workers=2, 40 | persistent_workers=True, 41 | sampler=dict(type='DefaultSampler', shuffle=True), 42 | batch_sampler=None, 43 | dataset=dict( 44 | type='ConcatDataset', 45 | ignore_keys=['DATASET_TYPE'], 46 | datasets=[ 47 | dict( 48 | type=dataset_type, 49 | data_root=data_root, 50 | ann_file='ImageSets/Main/train.txt', 51 | data_prefix=dict(img_path='JPEGImages-trainval'), 52 | filter_cfg=dict(filter_empty_gt=True), 53 | pipeline=train_pipeline), 54 | dict( 55 | type=dataset_type, 56 | data_root=data_root, 57 | ann_file='ImageSets/Main/val.txt', 58 | data_prefix=dict(img_path='JPEGImages-trainval'), 59 | filter_cfg=dict(filter_empty_gt=True), 60 | pipeline=train_pipeline, 61 | backend_args=backend_args) 62 | ])) 63 | val_dataloader = dict( 64 | batch_size=1, 65 | num_workers=2, 66 | persistent_workers=True, 67 | drop_last=False, 68 | sampler=dict(type='DefaultSampler', shuffle=False), 69 | dataset=dict( 70 | type=dataset_type, 71 | data_root=data_root, 72 | ann_file='ImageSets/Main/test.txt', 73 | data_prefix=dict(img_path='JPEGImages-test'), 74 | test_mode=True, 75 | pipeline=val_pipeline, 76 | backend_args=backend_args)) 77 | test_dataloader = val_dataloader 78 | 79 | val_evaluator = dict(type='DOTAMetric', metric='mAP') 80 | test_evaluator = val_evaluator 81 | -------------------------------------------------------------------------------- /configs/_base_/datasets/dota_qbox.py: -------------------------------------------------------------------------------- 1 | # dataset settings 2 | dataset_type = 'DOTADataset' 3 | data_root = 'data/split_ss_dota/' 4 | backend_args = None 5 | 6 | train_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 8 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 9 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 10 | dict( 11 | type='mmdet.RandomFlip', 12 | prob=0.75, 13 | direction=['horizontal', 'vertical', 'diagonal']), 14 | dict(type='mmdet.PackDetInputs') 15 | ] 16 | val_pipeline = [ 17 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 18 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 19 | # avoid bboxes being resized 20 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 21 | dict( 22 | type='mmdet.PackDetInputs', 23 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 24 | 'scale_factor')) 25 | ] 26 | test_pipeline = [ 27 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 28 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 29 | dict( 30 | type='mmdet.PackDetInputs', 31 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 32 | 'scale_factor')) 33 | ] 34 | train_dataloader = dict( 35 | batch_size=2, 36 | num_workers=2, 37 | persistent_workers=True, 38 | sampler=dict(type='DefaultSampler', shuffle=True), 39 | batch_sampler=None, 40 | dataset=dict( 41 | type=dataset_type, 42 | data_root=data_root, 43 | ann_file='trainval/annfiles/', 44 | data_prefix=dict(img_path='trainval/images/'), 45 | filter_cfg=dict(filter_empty_gt=True), 46 | pipeline=train_pipeline)) 47 | val_dataloader = dict( 48 | batch_size=1, 49 | num_workers=2, 50 | persistent_workers=True, 51 | drop_last=False, 52 | sampler=dict(type='DefaultSampler', shuffle=False), 53 | dataset=dict( 54 | type=dataset_type, 55 | data_root=data_root, 56 | ann_file='trainval/annfiles/', 57 | data_prefix=dict(img_path='trainval/images/'), 58 | test_mode=True, 59 | pipeline=val_pipeline)) 60 | test_dataloader = val_dataloader 61 | 62 | val_evaluator = dict( 63 | type='DOTAMetric', metric='mAP', iou_thrs=0.2, predict_box_type='qbox') 64 | test_evaluator = val_evaluator 65 | 66 | # inference on test dataset and format the output results 67 | # for submission. Note: the test set has no annotation. 68 | # test_dataloader = dict( 69 | # batch_size=1, 70 | # num_workers=2, 71 | # persistent_workers=True, 72 | # drop_last=False, 73 | # sampler=dict(type='DefaultSampler', shuffle=False), 74 | # dataset=dict( 75 | # type=dataset_type, 76 | # data_root=data_root, 77 | # data_prefix=dict(img_path='test/images/'), 78 | # test_mode=True, 79 | # pipeline=test_pipeline)) 80 | # test_evaluator = dict( 81 | # type='DOTAMetric', 82 | # format_only=True, 83 | # merge_patches=True, 84 | # predict_box_type='qbox', 85 | # outfile_prefix='./work_dirs/dota/Task1') 86 | -------------------------------------------------------------------------------- /configs/_base_/datasets/fair.py: -------------------------------------------------------------------------------- 1 | # dataset settings 2 | dataset_type = 'FAIRDataset' 3 | data_root = 'data/split_ss_fair/' 4 | backend_args = None 5 | 6 | train_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 8 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 9 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 10 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 11 | dict( 12 | type='mmdet.RandomFlip', 13 | prob=0.75, 14 | direction=['horizontal', 'vertical', 'diagonal']), 15 | dict(type='mmdet.PackDetInputs') 16 | ] 17 | val_pipeline = [ 18 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 19 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 20 | # avoid bboxes being resized 21 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 22 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 23 | dict( 24 | type='mmdet.PackDetInputs', 25 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 26 | 'scale_factor')) 27 | ] 28 | test_pipeline = [ 29 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 30 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 31 | dict( 32 | type='mmdet.PackDetInputs', 33 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 34 | 'scale_factor')) 35 | ] 36 | train_dataloader = dict( 37 | batch_size=2, 38 | num_workers=2, 39 | persistent_workers=True, 40 | sampler=dict(type='DefaultSampler', shuffle=True), 41 | batch_sampler=None, 42 | dataset=dict( 43 | type=dataset_type, 44 | data_root=data_root, 45 | ann_file='train/annfiles/', 46 | data_prefix=dict(img_path='train/images/'), 47 | filter_cfg=dict(filter_empty_gt=True), 48 | pipeline=train_pipeline)) 49 | val_dataloader = dict( 50 | batch_size=4, 51 | num_workers=2, 52 | persistent_workers=True, 53 | drop_last=False, 54 | sampler=dict(type='DefaultSampler', shuffle=False), 55 | dataset=dict( 56 | type=dataset_type, 57 | data_root=data_root, 58 | ann_file='train/annfiles/', 59 | data_prefix=dict(img_path='train/images/'), 60 | test_mode=True, 61 | pipeline=val_pipeline)) 62 | test_dataloader = val_dataloader 63 | 64 | val_evaluator = dict(type='FAIRMetric', metric='mAP') 65 | test_evaluator = val_evaluator 66 | 67 | # inference on test dataset and format the output results 68 | # for submission. Note: the test set has no annotation. 69 | test_dataloader = dict( 70 | batch_size=4, 71 | num_workers=2, 72 | persistent_workers=True, 73 | drop_last=False, 74 | sampler=dict(type='DefaultSampler', shuffle=False), 75 | dataset=dict( 76 | type=dataset_type, 77 | data_root=data_root, 78 | data_prefix=dict(img_path='test/images/'), 79 | test_mode=True, 80 | pipeline=test_pipeline)) 81 | test_evaluator = dict( 82 | type='FAIRMetric', 83 | format_only=True, 84 | merge_patches=True, 85 | outfile_prefix='./work_dirs/fair/Task1') 86 | -------------------------------------------------------------------------------- /mmrotate/utils/patch/split.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from itertools import product 3 | from math import ceil 4 | 5 | import numpy as np 6 | 7 | 8 | def get_multiscale_patch(sizes, steps, ratios): 9 | """Get multiscale patch sizes and steps. 10 | 11 | Args: 12 | sizes (list): A list of patch sizes. 13 | steps (list): A list of steps to slide patches. 14 | ratios (list): Multiscale ratios. devidie to each size and step and 15 | generate patches in new scales. 16 | 17 | Returns: 18 | new_sizes (list): A list of multiscale patch sizes. 19 | new_steps (list): A list of steps corresponding to new_sizes. 20 | """ 21 | assert len(sizes) == len(steps), 'The length of `sizes` and `steps`' \ 22 | 'should be the same.' 23 | new_sizes, new_steps = [], [] 24 | size_steps = list(zip(sizes, steps)) 25 | for (size, step), ratio in product(size_steps, ratios): 26 | new_sizes.append(int(size / ratio)) 27 | new_steps.append(int(step / ratio)) 28 | return new_sizes, new_steps 29 | 30 | 31 | def slide_window(width, height, sizes, steps, img_rate_thr=0.6): 32 | """Slide windows in images and get window position. 33 | 34 | Args: 35 | width (int): The width of the image. 36 | height (int): The height of the image. 37 | sizes (list): List of window's sizes. 38 | steps (list): List of window's steps. 39 | img_rate_thr (float): Threshold of window area divided by image area. 40 | 41 | Returns: 42 | np.ndarray: Information of valid windows. 43 | """ 44 | assert 1 >= img_rate_thr >= 0, 'The `in_rate_thr` should lie in 0~1' 45 | windows = [] 46 | # Sliding windows. 47 | for size, step in zip(sizes, steps): 48 | assert size > step, 'Size should large than step' 49 | 50 | x_num = 1 if width <= size else ceil((width - size) / step + 1) 51 | x_start = [step * i for i in range(x_num)] 52 | if len(x_start) > 1 and x_start[-1] + size > width: 53 | x_start[-1] = width - size 54 | 55 | y_num = 1 if height <= size else ceil((height - size) / step + 1) 56 | y_start = [step * i for i in range(y_num)] 57 | if len(y_start) > 1 and y_start[-1] + size > height: 58 | y_start[-1] = height - size 59 | 60 | start = np.array(list(product(x_start, y_start)), dtype=np.int64) 61 | windows.append(np.concatenate([start, start + size], axis=1)) 62 | windows = np.concatenate(windows, axis=0) 63 | 64 | # Calculate the rate of image part in each window. 65 | img_in_wins = windows.copy() 66 | img_in_wins[:, 0::2] = np.clip(img_in_wins[:, 0::2], 0, width) 67 | img_in_wins[:, 1::2] = np.clip(img_in_wins[:, 1::2], 0, height) 68 | img_areas = (img_in_wins[:, 2] - img_in_wins[:, 0]) * \ 69 | (img_in_wins[:, 3] - img_in_wins[:, 1]) 70 | win_areas = (windows[:, 2] - windows[:, 0]) * \ 71 | (windows[:, 3] - windows[:, 1]) 72 | img_rates = img_areas / win_areas 73 | if not (img_rates >= img_rate_thr).any(): 74 | img_rates[img_rates == img_rates.max()] = 1 75 | return windows[img_rates >= img_rate_thr] 76 | -------------------------------------------------------------------------------- /configs/_base_/datasets/dotav2.py: -------------------------------------------------------------------------------- 1 | # dataset settings 2 | dataset_type = 'DOTAv2Dataset' 3 | data_root = 'data/split_ss_dota2_0/' 4 | backend_args = None 5 | 6 | train_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 8 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 9 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 10 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 11 | dict( 12 | type='mmdet.RandomFlip', 13 | prob=0.75, 14 | direction=['horizontal', 'vertical', 'diagonal']), 15 | dict(type='mmdet.PackDetInputs') 16 | ] 17 | val_pipeline = [ 18 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 19 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 20 | # avoid bboxes being resized 21 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 22 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 23 | dict( 24 | type='mmdet.PackDetInputs', 25 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 26 | 'scale_factor')) 27 | ] 28 | test_pipeline = [ 29 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 30 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 31 | dict( 32 | type='mmdet.PackDetInputs', 33 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 34 | 'scale_factor')) 35 | ] 36 | train_dataloader = dict( 37 | batch_size=2, 38 | num_workers=2, 39 | persistent_workers=True, 40 | sampler=dict(type='DefaultSampler', shuffle=True), 41 | batch_sampler=None, 42 | dataset=dict( 43 | type=dataset_type, 44 | data_root=data_root, 45 | ann_file='trainval/annfiles/', 46 | data_prefix=dict(img_path='trainval/images/'), 47 | filter_cfg=dict(filter_empty_gt=True), 48 | pipeline=train_pipeline)) 49 | val_dataloader = dict( 50 | batch_size=4, 51 | num_workers=2, 52 | persistent_workers=True, 53 | drop_last=False, 54 | sampler=dict(type='DefaultSampler', shuffle=False), 55 | dataset=dict( 56 | type=dataset_type, 57 | data_root=data_root, 58 | ann_file='trainval/annfiles/', 59 | data_prefix=dict(img_path='trainval/images/'), 60 | test_mode=True, 61 | pipeline=val_pipeline)) 62 | test_dataloader = val_dataloader 63 | 64 | val_evaluator = dict(type='DOTAMetric', metric='mAP') 65 | test_evaluator = val_evaluator 66 | 67 | # inference on test dataset and format the output results 68 | # for submission. Note: the test set has no annotation. 69 | test_dataloader = dict( 70 | batch_size=4, 71 | num_workers=2, 72 | persistent_workers=True, 73 | drop_last=False, 74 | sampler=dict(type='DefaultSampler', shuffle=False), 75 | dataset=dict( 76 | type=dataset_type, 77 | data_root=data_root, 78 | data_prefix=dict(img_path='test/images/'), 79 | test_mode=True, 80 | pipeline=test_pipeline)) 81 | test_evaluator = dict( 82 | type='DOTAMetric', 83 | format_only=True, 84 | merge_patches=True, 85 | outfile_prefix='./work_dirs/dotav2/Task1') 86 | -------------------------------------------------------------------------------- /configs/_base_/datasets/dotav15.py: -------------------------------------------------------------------------------- 1 | # dataset settings 2 | dataset_type = 'DOTAv15Dataset' 3 | data_root = 'data/split_ss_dota1_5/' 4 | backend_args = None 5 | 6 | train_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 8 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 9 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 10 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 11 | dict( 12 | type='mmdet.RandomFlip', 13 | prob=0.75, 14 | direction=['horizontal', 'vertical', 'diagonal']), 15 | dict(type='mmdet.PackDetInputs') 16 | ] 17 | val_pipeline = [ 18 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 19 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 20 | # avoid bboxes being resized 21 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 22 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 23 | dict( 24 | type='mmdet.PackDetInputs', 25 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 26 | 'scale_factor')) 27 | ] 28 | test_pipeline = [ 29 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 30 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 31 | dict( 32 | type='mmdet.PackDetInputs', 33 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 34 | 'scale_factor')) 35 | ] 36 | train_dataloader = dict( 37 | batch_size=2, 38 | num_workers=2, 39 | persistent_workers=True, 40 | sampler=dict(type='DefaultSampler', shuffle=True), 41 | batch_sampler=None, 42 | dataset=dict( 43 | type=dataset_type, 44 | data_root=data_root, 45 | ann_file='trainval/annfiles/', 46 | data_prefix=dict(img_path='trainval/images/'), 47 | filter_cfg=dict(filter_empty_gt=True), 48 | pipeline=train_pipeline)) 49 | val_dataloader = dict( 50 | batch_size=4, 51 | num_workers=2, 52 | persistent_workers=True, 53 | drop_last=False, 54 | sampler=dict(type='DefaultSampler', shuffle=False), 55 | dataset=dict( 56 | type=dataset_type, 57 | data_root=data_root, 58 | ann_file='trainval/annfiles/', 59 | data_prefix=dict(img_path='trainval/images/'), 60 | test_mode=True, 61 | pipeline=val_pipeline)) 62 | test_dataloader = val_dataloader 63 | 64 | val_evaluator = dict(type='DOTAMetric', metric='mAP') 65 | test_evaluator = val_evaluator 66 | 67 | # inference on test dataset and format the output results 68 | # for submission. Note: the test set has no annotation. 69 | test_dataloader = dict( 70 | batch_size=4, 71 | num_workers=2, 72 | persistent_workers=True, 73 | drop_last=False, 74 | sampler=dict(type='DefaultSampler', shuffle=False), 75 | dataset=dict( 76 | type=dataset_type, 77 | data_root=data_root, 78 | data_prefix=dict(img_path='test/images/'), 79 | test_mode=True, 80 | pipeline=test_pipeline)) 81 | test_evaluator = dict( 82 | type='DOTAMetric', 83 | format_only=True, 84 | merge_patches=True, 85 | outfile_prefix='./work_dirs/dotav15/Task1') 86 | -------------------------------------------------------------------------------- /configs/_base_/datasets/dota.py: -------------------------------------------------------------------------------- 1 | # dataset settings 2 | dataset_type = 'DOTADataset' 3 | data_root = 'data/split_ss_dota/' 4 | backend_args = None 5 | 6 | train_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 8 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 9 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 10 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 11 | dict( 12 | type='mmdet.RandomFlip', 13 | prob=0.75, 14 | direction=['horizontal', 'vertical', 'diagonal']), 15 | dict(type='mmdet.PackDetInputs') 16 | ] 17 | val_pipeline = [ 18 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 19 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 20 | # avoid bboxes being resized 21 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 22 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 23 | dict( 24 | type='mmdet.PackDetInputs', 25 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 26 | 'scale_factor')) 27 | ] 28 | test_pipeline = [ 29 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 30 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 31 | dict( 32 | type='mmdet.PackDetInputs', 33 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 34 | 'scale_factor')) 35 | ] 36 | train_dataloader = dict( 37 | batch_size=2, 38 | num_workers=2, 39 | persistent_workers=True, 40 | sampler=dict(type='DefaultSampler', shuffle=True), 41 | batch_sampler=None, 42 | dataset=dict( 43 | type=dataset_type, 44 | data_root=data_root, 45 | ann_file='trainval/annfiles/', 46 | data_prefix=dict(img_path='trainval/images/'), 47 | filter_cfg=dict(filter_empty_gt=True), 48 | pipeline=train_pipeline)) 49 | val_dataloader = dict( 50 | batch_size=16, 51 | num_workers=2, 52 | persistent_workers=True, 53 | drop_last=False, 54 | sampler=dict(type='DefaultSampler', shuffle=False), 55 | dataset=dict( 56 | type=dataset_type, 57 | data_root=data_root, 58 | ann_file='trainval/annfiles/', 59 | data_prefix=dict(img_path='trainval/images/'), 60 | filter_cfg=dict(filter_empty_gt=True), 61 | test_mode=True, 62 | pipeline=val_pipeline)) 63 | test_dataloader = val_dataloader 64 | 65 | val_evaluator = dict(type='DOTAMetric', metric='mAP') 66 | test_evaluator = val_evaluator 67 | 68 | # inference on test dataset and format the output results 69 | # for submission. Note: the test set has no annotation. 70 | test_dataloader = dict( 71 | batch_size=4, 72 | num_workers=2, 73 | persistent_workers=True, 74 | drop_last=False, 75 | sampler=dict(type='DefaultSampler', shuffle=False), 76 | dataset=dict( 77 | type=dataset_type, 78 | data_root=data_root, 79 | data_prefix=dict(img_path='test/images/'), 80 | test_mode=True, 81 | pipeline=test_pipeline)) 82 | test_evaluator = dict( 83 | type='DOTAMetric', 84 | format_only=True, 85 | merge_patches=True, 86 | outfile_prefix='./work_dirs/dota/Task1') 87 | -------------------------------------------------------------------------------- /tools/analysis_tools/browse_dataset.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | import argparse 3 | import os.path as osp 4 | 5 | from mmdet.models.utils import mask2ndarray 6 | from mmdet.registry import DATASETS, VISUALIZERS 7 | from mmdet.structures.bbox import BaseBoxes 8 | from mmengine.config import Config, DictAction 9 | from mmengine.utils import ProgressBar 10 | 11 | from mmrotate.utils import register_all_modules 12 | 13 | 14 | def parse_args(): 15 | parser = argparse.ArgumentParser(description='Browse a dataset') 16 | parser.add_argument('config', help='train config file path') 17 | parser.add_argument( 18 | '--output-dir', 19 | default=None, 20 | type=str, 21 | help='If there is no display interface, you can save it') 22 | parser.add_argument('--not-show', default=False, action='store_true') 23 | parser.add_argument( 24 | '--show-interval', 25 | type=float, 26 | default=2, 27 | help='the interval of show (s)') 28 | parser.add_argument( 29 | '--cfg-options', 30 | nargs='+', 31 | action=DictAction, 32 | help='override some settings in the used config, the key-value pair ' 33 | 'in xxx=yyy format will be merged into config file. If the value to ' 34 | 'be overwritten is a list, it should be like key="[a,b]" or key=a,b ' 35 | 'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" ' 36 | 'Note that the quotation marks are necessary and that no white space ' 37 | 'is allowed.') 38 | args = parser.parse_args() 39 | return args 40 | 41 | 42 | def main(): 43 | args = parse_args() 44 | cfg = Config.fromfile(args.config) 45 | if args.cfg_options is not None: 46 | cfg.merge_from_dict(args.cfg_options) 47 | 48 | # register all modules in mmdet into the registries 49 | register_all_modules() 50 | 51 | dataset = DATASETS.build(cfg.train_dataloader.dataset) 52 | visualizer = VISUALIZERS.build(cfg.visualizer) 53 | visualizer.dataset_meta = dataset.metainfo 54 | 55 | progress_bar = ProgressBar(len(dataset)) 56 | for item in dataset: 57 | img = item['inputs'].permute(1, 2, 0).numpy() 58 | data_sample = item['data_samples'].numpy() 59 | gt_instances = data_sample.gt_instances 60 | img_path = osp.basename(item['data_samples'].img_path) 61 | 62 | out_file = osp.join( 63 | args.output_dir, 64 | osp.basename(img_path)) if args.output_dir is not None else None 65 | 66 | img = img[..., [2, 1, 0]] # bgr to rgb 67 | gt_bboxes = gt_instances.get('bboxes', None) 68 | if gt_bboxes is not None and isinstance(gt_bboxes, BaseBoxes): 69 | gt_instances.bboxes = gt_bboxes.tensor 70 | gt_masks = gt_instances.get('masks', None) 71 | if gt_masks is not None: 72 | masks = mask2ndarray(gt_masks) 73 | gt_instances.masks = masks.astype(bool) 74 | data_sample.gt_instances = gt_instances 75 | 76 | visualizer.add_datasample( 77 | osp.basename(img_path), 78 | img, 79 | data_sample, 80 | show=not args.not_show, 81 | wait_time=args.show_interval, 82 | out_file=out_file) 83 | 84 | progress_bar.update() 85 | 86 | 87 | if __name__ == '__main__': 88 | main() 89 | -------------------------------------------------------------------------------- /configs/_base_/datasets/dota_ms.py: -------------------------------------------------------------------------------- 1 | # dataset settings 2 | dataset_type = 'DOTADataset' 3 | data_root = 'data/split_ms_dota/' 4 | backend_args = None 5 | 6 | train_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 8 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 9 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 10 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 11 | dict( 12 | type='mmdet.RandomFlip', 13 | prob=0.75, 14 | direction=['horizontal', 'vertical', 'diagonal']), 15 | dict( 16 | type='RandomRotate', 17 | prob=0.5, 18 | angle_range=180, 19 | rect_obj_labels=[9, 11]), 20 | dict(type='mmdet.PackDetInputs') 21 | ] 22 | val_pipeline = [ 23 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 24 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 25 | # avoid bboxes being resized 26 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 27 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 28 | dict( 29 | type='mmdet.PackDetInputs', 30 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 31 | 'scale_factor')) 32 | ] 33 | test_pipeline = [ 34 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 35 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 36 | dict( 37 | type='mmdet.PackDetInputs', 38 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 39 | 'scale_factor')) 40 | ] 41 | train_dataloader = dict( 42 | batch_size=2, 43 | num_workers=2, 44 | persistent_workers=True, 45 | sampler=dict(type='DefaultSampler', shuffle=True), 46 | batch_sampler=None, 47 | dataset=dict( 48 | type=dataset_type, 49 | data_root=data_root, 50 | ann_file='trainval/annfiles/', 51 | data_prefix=dict(img_path='trainval/images/'), 52 | filter_cfg=dict(filter_empty_gt=True), 53 | pipeline=train_pipeline)) 54 | val_dataloader = dict( 55 | batch_size=1, 56 | num_workers=2, 57 | persistent_workers=True, 58 | drop_last=False, 59 | sampler=dict(type='DefaultSampler', shuffle=False), 60 | dataset=dict( 61 | type=dataset_type, 62 | data_root=data_root, 63 | ann_file='trainval/annfiles/', 64 | data_prefix=dict(img_path='trainval/images/'), 65 | test_mode=True, 66 | pipeline=val_pipeline)) 67 | test_dataloader = val_dataloader 68 | 69 | val_evaluator = dict(type='DOTAMetric', metric='mAP') 70 | test_evaluator = val_evaluator 71 | 72 | # inference on test dataset and format the output results 73 | # for submission. Note: the test set has no annotation. 74 | # test_dataloader = dict( 75 | # batch_size=1, 76 | # num_workers=2, 77 | # persistent_workers=True, 78 | # drop_last=False, 79 | # sampler=dict(type='DefaultSampler', shuffle=False), 80 | # dataset=dict( 81 | # type=dataset_type, 82 | # data_root=data_root, 83 | # data_prefix=dict(img_path='test/images/'), 84 | # test_mode=True, 85 | # pipeline=test_pipeline)) 86 | # test_evaluator = dict( 87 | # type='DOTAMetric', 88 | # format_only=True, 89 | # merge_patches=True, 90 | # outfile_prefix='./work_dirs/dota/Task1') 91 | -------------------------------------------------------------------------------- /configs/h2rbox_v2/metafile.yml: -------------------------------------------------------------------------------- 1 | Collections: 2 | - Name: h2rbox_v2 3 | Metadata: 4 | Training Data: DOTAv1.0 5 | Training Techniques: 6 | - AdamW 7 | Training Resources: 1x GeForce RTX 3090 8 | Architecture: 9 | - ResNet 10 | Paper: 11 | URL: https://arxiv.org/pdf/2304.04403.pdf 12 | Title: 'H2RBox-v2: Boosting HBox-supervised Oriented Object Detection via Symmetric Learning' 13 | README: configs/h2rbox_v2/README.md 14 | 15 | Models: 16 | - Name: h2rbox_v2-le90_r50_fpn-1x_dota 17 | In Collection: h2rbox_v2 18 | Config: configs/h2rbox_v2/h2rbox_v2-le90_r50_fpn-1x_dota.py 19 | Metadata: 20 | Training Data: DOTAv1.0 21 | Results: 22 | - Task: Oriented Object Detection 23 | Dataset: DOTAv1.0 24 | Metrics: 25 | mAP: 72.59 26 | Weights: https://download.openmmlab.com/mmrotate/v1.0/h2rbox_v2/h2rbox_v2-le90_r50_fpn-1x_dota/h2rbox_v2-le90_r50_fpn-1x_dota-fa5ad1d2.pth 27 | 28 | - Name: h2rbox_v2-le90_r50_fpn_ms_rr-1x_dota 29 | In Collection: h2rbox_v2 30 | Config: configs/h2rbox_v2/h2rbox_v2-le90_r50_fpn_ms_rr-1x_dota.py 31 | Metadata: 32 | Training Data: DOTAv1.0 33 | Results: 34 | - Task: Oriented Object Detection 35 | Dataset: DOTAv1.0 36 | Metrics: 37 | mAP: 78.25 38 | Weights: https://download.openmmlab.com/mmrotate/v1.0/h2rbox_v2/h2rbox_v2-le90_r50_fpn_ms_rr-1x_dota/h2rbox_v2-le90_r50_fpn_ms_rr-1x_dota-5e0e53e1.pth 39 | 40 | - Name: h2rbox_v2-le90_r50_fpn-1x_dotav15 41 | In Collection: h2rbox_v2 42 | Config: configs/h2rbox_v2/h2rbox_v2-le90_r50_fpn-1x_dotav15.py 43 | Metadata: 44 | Training Data: DOTAv1.5 45 | Results: 46 | - Task: Oriented Object Detection 47 | Dataset: DOTAv1.5 48 | Metrics: 49 | mAP: 64.76 50 | Weights: https://download.openmmlab.com/mmrotate/v1.0/h2rbox_v2/h2rbox_v2-le90_r50_fpn-1x_dotav15/h2rbox_v2-le90_r50_fpn-1x_dotav15-3adc0309.pth 51 | 52 | - Name: h2rbox_v2-le90_r50_fpn-1x_dotav2 53 | In Collection: h2rbox_v2 54 | Config: configs/h2rbox_v2/h2rbox_v2-le90_r50_fpn-1x_dotav2.py 55 | Metadata: 56 | Training Data: DOTAv2.0 57 | Results: 58 | - Task: Oriented Object Detection 59 | Dataset: DOTAv2.0 60 | Metrics: 61 | mAP: 50.33 62 | Weights: https://download.openmmlab.com/mmrotate/v1.0/h2rbox_v2/h2rbox_v2-le90_r50_fpn-1x_dotav2/h2rbox_v2-le90_r50_fpn-1x_dotav2-b1ec4d3c.pth 63 | 64 | - Name: h2rbox_v2-le90_r50_fpn-6x_hrsc 65 | In Collection: h2rbox_v2 66 | Config: configs/h2rbox_v2/h2rbox_v2-le90_r50_fpn-6x_hrsc.py 67 | Metadata: 68 | Training Data: HRSC 69 | Results: 70 | - Task: Oriented Object Detection 71 | Dataset: HRSC 72 | Metrics: 73 | mAP: 89.66 74 | Weights: https://download.openmmlab.com/mmrotate/v1.0/h2rbox_v2/h2rbox_v2-le90_r50_fpn-6x_hrsc/h2rbox_v2-le90_r50_fpn-6x_hrsc-b3b5e06b.pth 75 | 76 | - Name: h2rbox_v2-le90_r50_fpn_rr-6x_hrsc 77 | In Collection: h2rbox_v2 78 | Config: configs/h2rbox_v2/h2rbox_v2-le90_r50_fpn_rr-6x_hrsc.py 79 | Metadata: 80 | Training Data: HRSC 81 | Results: 82 | - Task: Oriented Object Detection 83 | Dataset: HRSC 84 | Metrics: 85 | mAP: 89.56 86 | Weights: https://download.openmmlab.com/mmrotate/v1.0/h2rbox_v2/h2rbox_v2-le90_r50_fpn_rr-6x_hrsc/h2rbox_v2-le90_r50_fpn_rr-6x_hrsc-ee6e851a.pth 87 | -------------------------------------------------------------------------------- /configs/point2rbox_v2/rotated-fcos-1x-dota-using-pseudo.py: -------------------------------------------------------------------------------- 1 | _base_ = [ 2 | '../_base_/datasets/dota.py', '../_base_/schedules/schedule_1x.py', 3 | '../_base_/default_runtime.py' 4 | ] 5 | angle_version = 'le90' 6 | 7 | # model settings 8 | model = dict( 9 | type='mmdet.FCOS', 10 | data_preprocessor=dict( 11 | type='mmdet.DetDataPreprocessor', 12 | mean=[123.675, 116.28, 103.53], 13 | std=[58.395, 57.12, 57.375], 14 | bgr_to_rgb=True, 15 | pad_size_divisor=32, 16 | boxtype2tensor=False), 17 | backbone=dict( 18 | type='mmdet.ResNet', 19 | depth=50, 20 | num_stages=4, 21 | out_indices=(0, 1, 2, 3), 22 | frozen_stages=1, 23 | norm_cfg=dict(type='BN', requires_grad=True), 24 | norm_eval=True, 25 | style='pytorch', 26 | init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), 27 | neck=dict( 28 | type='mmdet.FPN', 29 | in_channels=[256, 512, 1024, 2048], 30 | out_channels=512, 31 | start_level=1, 32 | add_extra_convs='on_output', 33 | num_outs=5, 34 | relu_before_extra_convs=True), 35 | bbox_head=dict( 36 | type='RotatedFCOSHead', 37 | num_classes=15, 38 | in_channels=512, 39 | stacked_convs=4, 40 | feat_channels=512, 41 | strides=[8, 16, 32, 64, 128], 42 | center_sampling=True, 43 | center_sample_radius=1.5, 44 | norm_on_bbox=True, 45 | centerness_on_reg=True, 46 | use_hbbox_loss=False, 47 | scale_angle=True, 48 | bbox_coder=dict( 49 | type='DistanceAnglePointCoder', angle_version=angle_version), 50 | loss_cls=dict( 51 | type='mmdet.FocalLoss', 52 | use_sigmoid=True, 53 | gamma=2.0, 54 | alpha=0.25, 55 | loss_weight=1.0), 56 | loss_bbox=dict(type='RotatedIoULoss', loss_weight=1.0), 57 | loss_angle=None, 58 | loss_centerness=dict( 59 | type='mmdet.CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0)), 60 | # training and testing settings 61 | train_cfg=None, 62 | test_cfg=dict( 63 | nms_pre=2000, 64 | min_bbox_size=0, 65 | score_thr=0.05, 66 | nms=dict(type='nms_rotated', iou_threshold=0.1), 67 | max_per_img=2000)) 68 | 69 | train_pipeline = [ 70 | dict(type='mmdet.LoadImageFromFile', backend_args=_base_.backend_args), 71 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='rbox'), 72 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 73 | dict( 74 | type='mmdet.RandomFlip', 75 | prob=0.75, 76 | direction=['horizontal', 'vertical', 'diagonal']), 77 | dict(type='mmdet.PackDetInputs') 78 | ] 79 | 80 | train_dataloader = dict( 81 | batch_size=4, 82 | dataset=dict( 83 | ann_file='point2rbox_v2_pseudo_labels.bbox.json', 84 | pipeline=train_pipeline)) 85 | 86 | val_dataloader = dict( 87 | batch_size=4) 88 | 89 | val_evaluator = dict( 90 | type='DOTAMetric', 91 | metric='mAP', 92 | iou_thrs=[0.5, 0.75]) 93 | 94 | # optimizer 95 | optim_wrapper = dict( 96 | optimizer=dict( 97 | _delete_=True, 98 | type='AdamW', 99 | lr=0.00005, 100 | betas=(0.9, 0.999), 101 | weight_decay=0.005)) 102 | 103 | train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=12, val_interval=12) 104 | -------------------------------------------------------------------------------- /configs/point2rbox_v2/rotated-fcos-1x-fair-using-pseudo.py: -------------------------------------------------------------------------------- 1 | _base_ = [ 2 | '../_base_/datasets/fair.py', '../_base_/schedules/schedule_1x.py', 3 | '../_base_/default_runtime.py' 4 | ] 5 | angle_version = 'le90' 6 | 7 | # model settings 8 | model = dict( 9 | type='mmdet.FCOS', 10 | data_preprocessor=dict( 11 | type='mmdet.DetDataPreprocessor', 12 | mean=[123.675, 116.28, 103.53], 13 | std=[58.395, 57.12, 57.375], 14 | bgr_to_rgb=True, 15 | pad_size_divisor=32, 16 | boxtype2tensor=False), 17 | backbone=dict( 18 | type='mmdet.ResNet', 19 | depth=50, 20 | num_stages=4, 21 | out_indices=(0, 1, 2, 3), 22 | frozen_stages=1, 23 | norm_cfg=dict(type='BN', requires_grad=True), 24 | norm_eval=True, 25 | style='pytorch', 26 | init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), 27 | neck=dict( 28 | type='mmdet.FPN', 29 | in_channels=[256, 512, 1024, 2048], 30 | out_channels=512, 31 | start_level=1, 32 | add_extra_convs='on_output', 33 | num_outs=5, 34 | relu_before_extra_convs=True), 35 | bbox_head=dict( 36 | type='RotatedFCOSHead', 37 | num_classes=34, 38 | in_channels=512, 39 | stacked_convs=4, 40 | feat_channels=512, 41 | strides=[8, 16, 32, 64, 128], 42 | center_sampling=True, 43 | center_sample_radius=1.5, 44 | norm_on_bbox=True, 45 | centerness_on_reg=True, 46 | use_hbbox_loss=False, 47 | scale_angle=True, 48 | bbox_coder=dict( 49 | type='DistanceAnglePointCoder', angle_version=angle_version), 50 | loss_cls=dict( 51 | type='mmdet.FocalLoss', 52 | use_sigmoid=True, 53 | gamma=2.0, 54 | alpha=0.25, 55 | loss_weight=1.0), 56 | loss_bbox=dict(type='RotatedIoULoss', loss_weight=1.0), 57 | loss_angle=None, 58 | loss_centerness=dict( 59 | type='mmdet.CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0)), 60 | # training and testing settings 61 | train_cfg=None, 62 | test_cfg=dict( 63 | nms_pre=2000, 64 | min_bbox_size=0, 65 | score_thr=0.05, 66 | nms=dict(type='nms_rotated', iou_threshold=0.1), 67 | max_per_img=2000)) 68 | 69 | train_pipeline = [ 70 | dict(type='mmdet.LoadImageFromFile', backend_args=_base_.backend_args), 71 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='rbox'), 72 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 73 | dict( 74 | type='mmdet.RandomFlip', 75 | prob=0.75, 76 | direction=['horizontal', 'vertical', 'diagonal']), 77 | dict(type='mmdet.PackDetInputs') 78 | ] 79 | 80 | train_dataloader = dict( 81 | batch_size=4, 82 | dataset=dict( 83 | ann_file='point2rbox_v2_pseudo_labels.bbox.json', 84 | pipeline=train_pipeline)) 85 | 86 | val_dataloader = dict( 87 | batch_size=4) 88 | 89 | val_evaluator = dict( 90 | type='DOTAMetric', 91 | metric='mAP', 92 | iou_thrs=[0.5, 0.75]) 93 | 94 | # optimizer 95 | optim_wrapper = dict( 96 | optimizer=dict( 97 | _delete_=True, 98 | type='AdamW', 99 | lr=0.00005, 100 | betas=(0.9, 0.999), 101 | weight_decay=0.005)) 102 | 103 | train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=12, val_interval=12) 104 | -------------------------------------------------------------------------------- /configs/point2rbox_v2/rotated-fcos-1x-sku110k-using-pseudo.py: -------------------------------------------------------------------------------- 1 | _base_ = [ 2 | '../_base_/datasets/sku110k.py', '../_base_/schedules/schedule_1x.py', 3 | '../_base_/default_runtime.py' 4 | ] 5 | angle_version = 'le90' 6 | 7 | # model settings 8 | model = dict( 9 | type='mmdet.FCOS', 10 | data_preprocessor=dict( 11 | type='mmdet.DetDataPreprocessor', 12 | mean=[123.675, 116.28, 103.53], 13 | std=[58.395, 57.12, 57.375], 14 | bgr_to_rgb=True, 15 | pad_size_divisor=32, 16 | boxtype2tensor=False), 17 | backbone=dict( 18 | type='mmdet.ResNet', 19 | depth=50, 20 | num_stages=4, 21 | out_indices=(0, 1, 2, 3), 22 | frozen_stages=1, 23 | norm_cfg=dict(type='BN', requires_grad=True), 24 | norm_eval=True, 25 | style='pytorch', 26 | init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), 27 | neck=dict( 28 | type='mmdet.FPN', 29 | in_channels=[256, 512, 1024, 2048], 30 | out_channels=512, 31 | start_level=1, 32 | add_extra_convs='on_output', 33 | num_outs=5, 34 | relu_before_extra_convs=True), 35 | bbox_head=dict( 36 | type='RotatedFCOSHead', 37 | num_classes=1, 38 | in_channels=512, 39 | stacked_convs=4, 40 | feat_channels=512, 41 | strides=[8, 16, 32, 64, 128], 42 | center_sampling=True, 43 | center_sample_radius=1.5, 44 | norm_on_bbox=True, 45 | centerness_on_reg=True, 46 | use_hbbox_loss=False, 47 | scale_angle=True, 48 | bbox_coder=dict( 49 | type='DistanceAnglePointCoder', angle_version=angle_version), 50 | loss_cls=dict( 51 | type='mmdet.FocalLoss', 52 | use_sigmoid=True, 53 | gamma=2.0, 54 | alpha=0.25, 55 | loss_weight=1.0), 56 | loss_bbox=dict(type='RotatedIoULoss', loss_weight=1.0), 57 | loss_angle=None, 58 | loss_centerness=dict( 59 | type='mmdet.CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0)), 60 | # training and testing settings 61 | train_cfg=None, 62 | test_cfg=dict( 63 | nms_pre=2000, 64 | min_bbox_size=0, 65 | score_thr=0.05, 66 | nms=dict(type='nms_rotated', iou_threshold=0.1), 67 | max_per_img=2000)) 68 | 69 | 70 | train_pipeline = [ 71 | dict(type='mmdet.LoadImageFromFile', backend_args=_base_.backend_args), 72 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='rbox'), 73 | dict(type='mmdet.FixShapeResize', width=800, height=800, keep_ratio=True), 74 | dict( 75 | type='mmdet.RandomFlip', 76 | prob=0.75, 77 | direction=['horizontal', 'vertical', 'diagonal']), 78 | dict(type='RandomRotate', prob=1, angle_range=180), 79 | dict(type='mmdet.PackDetInputs') 80 | ] 81 | 82 | train_dataloader = dict( 83 | batch_size=4, 84 | dataset=dict( 85 | ann_file='point2rbox_v2_pseudo_labels.bbox.json', 86 | pipeline=train_pipeline)) 87 | 88 | val_dataloader = dict( 89 | batch_size=4) 90 | 91 | val_evaluator = dict( 92 | type='DOTAMetric', 93 | metric='mAP', 94 | iou_thrs=[0.5, 0.75]) 95 | 96 | # optimizer 97 | optim_wrapper = dict( 98 | optimizer=dict( 99 | _delete_=True, 100 | type='AdamW', 101 | lr=0.00005, 102 | betas=(0.9, 0.999), 103 | weight_decay=0.005)) 104 | 105 | train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=12, val_interval=12) 106 | -------------------------------------------------------------------------------- /mmrotate/models/utils/misc.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | import torch 3 | from mmcv.ops import convex_iou 4 | 5 | 6 | def points_center_pts(RPoints, y_first=True): 7 | """Compute center point of Pointsets. 8 | 9 | Args: 10 | RPoints (torch.Tensor): the lists of Pointsets, shape (k, 18). 11 | y_first (bool, optional): if True, the sequence of Pointsets is (y,x). 12 | 13 | Returns: 14 | center_pts (torch.Tensor): the mean_center coordination of Pointsets, 15 | shape (k, 18). 16 | """ 17 | RPoints = RPoints.reshape(-1, 9, 2) 18 | 19 | if y_first: 20 | pts_dy = RPoints[:, :, 0::2] 21 | pts_dx = RPoints[:, :, 1::2] 22 | else: 23 | pts_dx = RPoints[:, :, 0::2] 24 | pts_dy = RPoints[:, :, 1::2] 25 | pts_dy_mean = pts_dy.mean(dim=1, keepdim=True).reshape(-1, 1) 26 | pts_dx_mean = pts_dx.mean(dim=1, keepdim=True).reshape(-1, 1) 27 | center_pts = torch.cat([pts_dx_mean, pts_dy_mean], dim=1).reshape(-1, 2) 28 | return center_pts 29 | 30 | 31 | def convex_overlaps(gt_bboxes, points): 32 | """Compute overlaps between polygons and points. 33 | 34 | Args: 35 | gt_rbboxes (torch.Tensor): Groundtruth polygons, shape (k, 8). 36 | points (torch.Tensor): Points to be assigned, shape(n, 18). 37 | 38 | Returns: 39 | overlaps (torch.Tensor): Overlaps between k gt_bboxes and n bboxes, 40 | shape(k, n). 41 | """ 42 | overlaps = convex_iou(points, gt_bboxes) 43 | overlaps = overlaps.transpose(1, 0) 44 | return overlaps 45 | 46 | 47 | def levels_to_images(mlvl_tensor, flatten=False): 48 | """Concat multi-level feature maps by image. 49 | 50 | [feature_level0, feature_level1...] -> [feature_image0, feature_image1...] 51 | Convert the shape of each element in mlvl_tensor from (N, C, H, W) to 52 | (N, H*W , C), then split the element to N elements with shape (H*W, C), and 53 | concat elements in same image of all level along first dimension. 54 | 55 | Args: 56 | mlvl_tensor (list[torch.Tensor]): list of Tensor which collect from 57 | corresponding level. Each element is of shape (N, C, H, W) 58 | flatten (bool, optional): if shape of mlvl_tensor is (N, C, H, W) 59 | set False, if shape of mlvl_tensor is (N, H, W, C) set True. 60 | 61 | Returns: 62 | list[torch.Tensor]: A list that contains N tensors and each tensor is 63 | of shape (num_elements, C) 64 | """ 65 | batch_size = mlvl_tensor[0].size(0) 66 | batch_list = [[] for _ in range(batch_size)] 67 | if flatten: 68 | channels = mlvl_tensor[0].size(-1) 69 | else: 70 | channels = mlvl_tensor[0].size(1) 71 | for t in mlvl_tensor: 72 | if not flatten: 73 | t = t.permute(0, 2, 3, 1) 74 | t = t.view(batch_size, -1, channels).contiguous() 75 | for img in range(batch_size): 76 | batch_list[img].append(t[img]) 77 | return [torch.cat(item, 0) for item in batch_list] 78 | 79 | 80 | def get_num_level_anchors_inside(num_level_anchors, inside_flags): 81 | """Get number of every level anchors inside. 82 | 83 | Args: 84 | num_level_anchors (List[int]): List of number of every level's anchors. 85 | inside_flags (torch.Tensor): Flags of all anchors. 86 | 87 | Returns: 88 | List[int]: List of number of inside anchors. 89 | """ 90 | split_inside_flags = torch.split(inside_flags, num_level_anchors) 91 | num_level_anchors_inside = [ 92 | int(flags.sum()) for flags in split_inside_flags 93 | ] 94 | return num_level_anchors_inside 95 | -------------------------------------------------------------------------------- /mmrotate/models/losses/spatial_border_loss.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | import torch 3 | import torch.nn as nn 4 | 5 | from mmrotate.registry import MODELS 6 | from mmrotate.structures.bbox import QuadriBoxes 7 | 8 | 9 | @MODELS.register_module() 10 | class SpatialBorderLoss(nn.Module): 11 | """Spatial Border loss for learning points in Oriented RepPoints. 12 | 13 | Args: 14 | pts (torch.Tensor): point sets with shape (N, 9*2). 15 | Default points number in each point set is 9. 16 | gt_bboxes (torch.Tensor): gt_bboxes with polygon form with shape(N, 8) 17 | 18 | Returns: 19 | torch.Tensor: spatial border loss. 20 | """ 21 | 22 | def __init__(self, loss_weight=1.0): 23 | super(SpatialBorderLoss, self).__init__() 24 | self.loss_weight = loss_weight 25 | 26 | def forward(self, pts, gt_bboxes, weight, *args, **kwargs): 27 | loss = self.loss_weight * weighted_spatial_border_loss( 28 | pts, gt_bboxes, weight, *args, **kwargs) 29 | return loss 30 | 31 | 32 | def spatial_border_loss(pts, gt_bboxes): 33 | """The loss is used to penalize the learning points out of the assigned 34 | ground truth boxes (polygon by default). 35 | 36 | Args: 37 | pts (torch.Tensor): point sets with shape (N, 9*2). 38 | gt_bboxes (torch.Tensor): gt_bboxes with polygon form with shape(N, 8) 39 | 40 | Returns: 41 | loss (torch.Tensor) 42 | """ 43 | num_gts, num_pointsets = gt_bboxes.size(0), pts.size(0) 44 | num_point = int(pts.size(1) / 2.0) 45 | loss = pts.new_zeros([0]) 46 | 47 | if num_gts > 0: 48 | inside_flag_list = [] 49 | for i in range(num_point): 50 | pt = pts[:, (2 * i):(2 * i + 2)].reshape(num_pointsets, 51 | 2).contiguous() 52 | gt_qboxes = QuadriBoxes(gt_bboxes) 53 | inside_pt_flag = gt_qboxes.find_inside_points(pt, is_aligned=True) 54 | inside_flag_list.append(inside_pt_flag) 55 | 56 | inside_flag = torch.stack(inside_flag_list, dim=1) 57 | pts = pts.reshape(-1, num_point, 2) 58 | out_border_pts = pts[torch.where(inside_flag == 0)] 59 | 60 | if out_border_pts.size(0) > 0: 61 | corr_gt_boxes = gt_bboxes[torch.where(inside_flag == 0)[0]] 62 | corr_gt_boxes_center_x = (corr_gt_boxes[:, 0] + 63 | corr_gt_boxes[:, 4]) / 2.0 64 | corr_gt_boxes_center_y = (corr_gt_boxes[:, 1] + 65 | corr_gt_boxes[:, 5]) / 2.0 66 | corr_gt_boxes_center = torch.stack( 67 | [corr_gt_boxes_center_x, corr_gt_boxes_center_y], dim=1) 68 | distance_out_pts = 0.2 * (( 69 | (out_border_pts - corr_gt_boxes_center)**2).sum(dim=1).sqrt()) 70 | loss = distance_out_pts.sum() / out_border_pts.size(0) 71 | 72 | return loss 73 | 74 | 75 | def weighted_spatial_border_loss(pts, gt_bboxes, weight, avg_factor=None): 76 | """Weghted spatial border loss. 77 | 78 | Args: 79 | pts (torch.Tensor): point sets with shape (N, 9*2). 80 | gt_bboxes (torch.Tensor): gt_bboxes with polygon form with shape(N, 8) 81 | weight (torch.Tensor): weights for point sets with shape (N) 82 | 83 | Returns: 84 | loss (torch.Tensor) 85 | """ 86 | 87 | weight = weight.unsqueeze(dim=1).repeat(1, 4) 88 | assert weight.dim() == 2 89 | if avg_factor is None: 90 | avg_factor = torch.sum(weight > 0).float().item() / 4 + 1e-6 91 | loss = spatial_border_loss(pts, gt_bboxes) 92 | 93 | return torch.sum(loss)[None] / avg_factor 94 | -------------------------------------------------------------------------------- /configs/point2rbox_v2/rotated-fcos-1x-dior-using-pseudo.py: -------------------------------------------------------------------------------- 1 | _base_ = [ 2 | '../_base_/datasets/dior.py', '../_base_/schedules/schedule_1x.py', 3 | '../_base_/default_runtime.py' 4 | ] 5 | angle_version = 'le90' 6 | 7 | # model settings 8 | model = dict( 9 | type='mmdet.FCOS', 10 | data_preprocessor=dict( 11 | type='mmdet.DetDataPreprocessor', 12 | mean=[123.675, 116.28, 103.53], 13 | std=[58.395, 57.12, 57.375], 14 | bgr_to_rgb=True, 15 | pad_size_divisor=32, 16 | boxtype2tensor=False), 17 | backbone=dict( 18 | type='mmdet.ResNet', 19 | depth=50, 20 | num_stages=4, 21 | out_indices=(0, 1, 2, 3), 22 | frozen_stages=1, 23 | norm_cfg=dict(type='BN', requires_grad=True), 24 | norm_eval=True, 25 | style='pytorch', 26 | init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), 27 | neck=dict( 28 | type='mmdet.FPN', 29 | in_channels=[256, 512, 1024, 2048], 30 | out_channels=512, 31 | start_level=1, 32 | add_extra_convs='on_output', 33 | num_outs=5, 34 | relu_before_extra_convs=True), 35 | bbox_head=dict( 36 | type='RotatedFCOSHead', 37 | num_classes=20, 38 | in_channels=512, 39 | stacked_convs=4, 40 | feat_channels=512, 41 | strides=[8, 16, 32, 64, 128], 42 | center_sampling=True, 43 | center_sample_radius=1.5, 44 | norm_on_bbox=True, 45 | centerness_on_reg=True, 46 | use_hbbox_loss=False, 47 | scale_angle=True, 48 | bbox_coder=dict( 49 | type='DistanceAnglePointCoder', angle_version=angle_version), 50 | loss_cls=dict( 51 | type='mmdet.FocalLoss', 52 | use_sigmoid=True, 53 | gamma=2.0, 54 | alpha=0.25, 55 | loss_weight=1.0), 56 | loss_bbox=dict(type='RotatedIoULoss', loss_weight=1.0), 57 | loss_angle=None, 58 | loss_centerness=dict( 59 | type='mmdet.CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0)), 60 | # training and testing settings 61 | train_cfg=None, 62 | test_cfg=dict( 63 | nms_pre=2000, 64 | min_bbox_size=0, 65 | score_thr=0.05, 66 | nms=dict(type='nms_rotated', iou_threshold=0.1), 67 | max_per_img=2000)) 68 | 69 | train_pipeline = [ 70 | dict(type='mmdet.LoadImageFromFile', backend_args=_base_.backend_args), 71 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='rbox'), 72 | dict(type='mmdet.Resize', scale=(800, 800), keep_ratio=True), 73 | dict( 74 | type='mmdet.RandomFlip', 75 | prob=0.75, 76 | direction=['horizontal', 'vertical', 'diagonal']), 77 | dict(type='mmdet.PackDetInputs') 78 | ] 79 | 80 | train_dataloader = dict( 81 | batch_size=4, 82 | dataset=dict( 83 | _delete_=True, 84 | type=_base_.dataset_type, 85 | data_root=_base_.data_root, 86 | ann_file='point2rbox_v2_pseudo_labels.bbox.json', 87 | data_prefix=dict(img_path='JPEGImages-trainval'), 88 | filter_cfg=dict(filter_empty_gt=True), 89 | pipeline=train_pipeline)) 90 | 91 | val_dataloader = dict( 92 | batch_size=4) 93 | 94 | val_evaluator = dict( 95 | type='DOTAMetric', 96 | metric='mAP', 97 | iou_thrs=[0.5, 0.75]) 98 | 99 | # optimizer 100 | optim_wrapper = dict( 101 | optimizer=dict( 102 | _delete_=True, 103 | type='AdamW', 104 | lr=0.00005, 105 | betas=(0.9, 0.999), 106 | weight_decay=0.005)) 107 | 108 | train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=12, val_interval=12) 109 | -------------------------------------------------------------------------------- /mmrotate/models/losses/h2rbox_consistency_loss.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | from typing import Optional 3 | 4 | import torch 5 | from mmdet.utils import ConfigType 6 | from torch import Tensor 7 | 8 | from mmrotate.registry import MODELS 9 | 10 | 11 | @MODELS.register_module() 12 | class H2RBoxConsistencyLoss(torch.nn.Module): 13 | 14 | def __init__(self, 15 | center_loss_cfg: ConfigType = dict( 16 | type='mmdet.L1Loss', loss_weight=0.0), 17 | shape_loss_cfg: ConfigType = dict( 18 | type='mmdet.IoULoss', loss_weight=1.0), 19 | angle_loss_cfg: ConfigType = dict( 20 | type='mmdet.L1Loss', loss_weight=1.0), 21 | reduction: str = 'mean', 22 | loss_weight: float = 1.0) -> None: 23 | super(H2RBoxConsistencyLoss, self).__init__() 24 | self.center_loss = MODELS.build(center_loss_cfg) 25 | self.shape_loss = MODELS.build(shape_loss_cfg) 26 | self.angle_loss = MODELS.build(angle_loss_cfg) 27 | self.reduction = reduction 28 | self.loss_weight = loss_weight 29 | 30 | def forward(self, 31 | pred: Tensor, 32 | target: Tensor, 33 | weight: Tensor, 34 | avg_factor: Optional[int] = None, 35 | reduction_override: Optional[str] = None) -> Tensor: 36 | """Forward function. 37 | 38 | Args: 39 | pred (Tensor): Predicted boxes. 40 | target (Tensor): Corresponding gt boxes. 41 | weight (Tensor): The weight of loss for each prediction. 42 | avg_factor (int, optional): Average factor that is used to average 43 | the loss. Defaults to None. 44 | reduction_override (str, optional): The reduction method used to 45 | override the original reduction method of the loss. 46 | Defaults to None. 47 | 48 | Returns: 49 | Calculated loss (Tensor) 50 | """ 51 | assert reduction_override in (None, 'none', 'mean', 'sum') 52 | reduction = ( 53 | reduction_override if reduction_override else self.reduction) 54 | xy_pred = pred[..., :2] 55 | xy_target = target[..., :2] 56 | hbb_pred1 = torch.cat([-pred[..., 2:4], pred[..., 2:4]], dim=-1) 57 | hbb_pred2 = hbb_pred1[..., [1, 0, 3, 2]] 58 | hbb_target = torch.cat([-target[..., 2:4], target[..., 2:4]], dim=-1) 59 | d_a_pred = pred[..., 4] - target[..., 4] 60 | 61 | center_loss = self.center_loss( 62 | xy_pred, 63 | xy_target, 64 | weight=weight[:, None], 65 | reduction_override=reduction, 66 | avg_factor=avg_factor) 67 | shape_loss1 = self.shape_loss( 68 | hbb_pred1, 69 | hbb_target, 70 | weight=weight, 71 | reduction_override=reduction, 72 | avg_factor=avg_factor) + self.angle_loss( 73 | d_a_pred.sin(), 74 | torch.zeros_like(d_a_pred), 75 | weight=weight, 76 | reduction_override=reduction, 77 | avg_factor=avg_factor) 78 | shape_loss2 = self.shape_loss( 79 | hbb_pred2, 80 | hbb_target, 81 | weight=weight, 82 | reduction_override=reduction, 83 | avg_factor=avg_factor) + self.angle_loss( 84 | d_a_pred.cos(), 85 | torch.zeros_like(d_a_pred), 86 | weight=weight, 87 | reduction_override=reduction, 88 | avg_factor=avg_factor) 89 | loss_bbox = center_loss + torch.min(shape_loss1, shape_loss2) 90 | return self.loss_weight * loss_bbox 91 | -------------------------------------------------------------------------------- /configs/point2rbox_v2/README.md: -------------------------------------------------------------------------------- 1 | # Point2RBox-v2 2 | 3 | > [Point2RBox-v2: Rethinking Point-supervised Oriented Object Detection with Spatial Layout Among Instances](https://arxiv.org/pdf/2502.04268) 4 | 5 | 6 | 7 | ## Abstract 8 | 9 |
10 | 11 |
12 | 13 | With the rapidly increasing demand for oriented object detection (OOD), recent research involving weakly-supervised detectors for learning OOD from point annotations has gained great attention. In this paper, we rethink this challenging task setting with the layout among instances and present Point2RBox-v2. At the core are three principles: 1) Gaussian overlap loss. It learns an upper bound for each instance by treating objects as 2D Gaussian distributions and minimizing their overlap. 2) Voronoi watershed loss. It learns a lower bound for each instance through watershed on Voronoi tessellation. 3) Consistency loss. It learns the size/rotation variation between two output sets with respect to an input image and its augmented view. Supplemented by a few devised techniques, e.g. edge loss and copy-paste, the detector is further enhanced. To our best knowledge, Point2RBox-v2 is the first approach to explore the spatial layout among instances for learning point-supervised OOD. Our solution is elegant and lightweight, yet it is expected to give a competitive performance especially in densely packed scenes: 62.61%/86.15%/34.71% on DOTA/HRSC/FAIR1M. 14 | 15 | ## Evaluation on DOTA-v1.0 16 | 17 | All the commands assume that you are currently in the point2rbox-v2 root folder. 18 | ``` 19 | cd point2rbox-v2 20 | ``` 21 | 22 | ### Data preparation 23 | 24 | Follow the instruction of MMRotate to prepare split_ss_dota. If you already have split_ss_dota on your disk, you can also create a soft link so that it can be visited under the data folder: 25 | ``` 26 | ln -s path/to/split_ss_dota data 27 | ``` 28 | 29 | ### End-to-end training 30 | We can train/test/visualize the Point2RBox-v2 model by: 31 | ```shell 32 | # train 33 | python tools/train.py configs/point2rbox_v2/point2rbox_v2-1x-dota.py 34 | # test 35 | python tools/test.py configs/point2rbox_v2/point2rbox_v2-1x-dota.py work_dirs/point2rbox_v2-1x-dota/epoch_12.pth 36 | # visualize 37 | python tools/test.py configs/point2rbox_v2/point2rbox_v2-1x-dota.py work_dirs/point2rbox_v2-1x-dota/epoch_12.pth --show-dir vis 38 | ``` 39 | 40 | ### Two-stage training 41 | Use the above trained model (1st stage, train Point2RBox-v2) as the pseudo generator: 42 | ```shell 43 | # this config file runs inference on trainval set 44 | python tools/test.py configs/point2rbox_v2/point2rbox_v2-pseudo-generator-dota.py work_dirs/point2rbox_v2-1x-dota/epoch_12.pth 45 | ``` 46 | 47 | Now the pseudo labels for trainval set have been saved at data/split_ss_dota/point2rbox_v2_pseudo_labels.bbox.json, with which we can train/test/visualize the FCOS detector (2nd stage, train FCOS): 48 | ```shell 49 | # train 50 | python tools/train.py configs/point2rbox_v2/rotated-fcos-1x-dota-using-pseudo.py 51 | # test 52 | python tools/test.py configs/point2rbox_v2/rotated-fcos-1x-dota-using-pseudo.py work_dirs/rotated-fcos-1x-dota-using-pseudo/epoch_12.pth 53 | # visualize 54 | python tools/test.py configs/point2rbox_v2/rotated-fcos-1x-dota-using-pseudo.py work_dirs/rotated-fcos-1x-dota-using-pseudo/epoch_12.pth --show-dir vis 55 | ``` 56 | 57 | ## Citation 58 | ``` 59 | @article{yu2025point2rboxv2, 60 | title={Point2RBox-v2: Rethinking Point-supervised Oriented Object Detection with Spatial Layout Among Instances}, 61 | author={Yi Yu and Botao Ren and Peiyuan Zhang and Mingxin Liu and Junwei Luo and Shaofeng Zhang and Feipeng Da and Junchi Yan and Xue Yang}, 62 | year={2025}, 63 | journal={arXiv preprint arXiv:2502.04268}, 64 | } 65 | ``` 66 | -------------------------------------------------------------------------------- /mmrotate/registry.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | """MMRotate provides 18 registry nodes to support using modules across 3 | projects. 4 | 5 | Each node is a child of the root registry in MMEngine. 6 | More details can be found at 7 | https://mmengine.readthedocs.io/en/latest/tutorials/registry.html. 8 | """ 9 | 10 | from mmengine.registry import DATA_SAMPLERS as MMENGINE_DATA_SAMPLERS 11 | from mmengine.registry import DATASETS as MMENGINE_DATASETS 12 | from mmengine.registry import HOOKS as MMENGINE_HOOKS 13 | from mmengine.registry import LOG_PROCESSORS as MMENGINE_LOG_PROCESSORS 14 | from mmengine.registry import LOOPS as MMENGINE_LOOPS 15 | from mmengine.registry import METRICS as MMENGINE_METRICS 16 | from mmengine.registry import MODEL_WRAPPERS as MMENGINE_MODEL_WRAPPERS 17 | from mmengine.registry import MODELS as MMENGINE_MODELS 18 | from mmengine.registry import \ 19 | OPTIM_WRAPPER_CONSTRUCTORS as MMENGINE_OPTIM_WRAPPER_CONSTRUCTORS 20 | from mmengine.registry import OPTIMIZERS as MMENGINE_OPTIMIZERS 21 | from mmengine.registry import PARAM_SCHEDULERS as MMENGINE_PARAM_SCHEDULERS 22 | from mmengine.registry import \ 23 | RUNNER_CONSTRUCTORS as MMENGINE_RUNNER_CONSTRUCTORS 24 | from mmengine.registry import RUNNERS as MMENGINE_RUNNERS 25 | from mmengine.registry import TASK_UTILS as MMENGINE_TASK_UTILS 26 | from mmengine.registry import TRANSFORMS as MMENGINE_TRANSFORMS 27 | from mmengine.registry import VISBACKENDS as MMENGINE_VISBACKENDS 28 | from mmengine.registry import VISUALIZERS as MMENGINE_VISUALIZERS 29 | from mmengine.registry import \ 30 | WEIGHT_INITIALIZERS as MMENGINE_WEIGHT_INITIALIZERS 31 | from mmengine.registry import Registry 32 | 33 | # manage all kinds of runners like `EpochBasedRunner` and `IterBasedRunner` 34 | RUNNERS = Registry('runner', parent=MMENGINE_RUNNERS) 35 | # manage runner constructors that define how to initialize runners 36 | RUNNER_CONSTRUCTORS = Registry( 37 | 'runner constructor', parent=MMENGINE_RUNNER_CONSTRUCTORS) 38 | # manage all kinds of loops like `EpochBasedTrainLoop` 39 | LOOPS = Registry('loop', parent=MMENGINE_LOOPS) 40 | # manage all kinds of hooks like `CheckpointHook` 41 | HOOKS = Registry('hook', parent=MMENGINE_HOOKS) 42 | 43 | # manage data-related modules 44 | DATASETS = Registry('dataset', parent=MMENGINE_DATASETS) 45 | DATA_SAMPLERS = Registry('data sampler', parent=MMENGINE_DATA_SAMPLERS) 46 | TRANSFORMS = Registry('transform', parent=MMENGINE_TRANSFORMS) 47 | 48 | # manage all kinds of modules inheriting `nn.Module` 49 | MODELS = Registry('model', parent=MMENGINE_MODELS) 50 | # manage all kinds of model wrappers like 'MMDistributedDataParallel' 51 | MODEL_WRAPPERS = Registry('model_wrapper', parent=MMENGINE_MODEL_WRAPPERS) 52 | # manage all kinds of weight initialization modules like `Uniform` 53 | WEIGHT_INITIALIZERS = Registry( 54 | 'weight initializer', parent=MMENGINE_WEIGHT_INITIALIZERS) 55 | 56 | # manage all kinds of optimizers like `SGD` and `Adam` 57 | OPTIMIZERS = Registry('optimizer', parent=MMENGINE_OPTIMIZERS) 58 | # manage constructors that customize the optimization hyperparameters. 59 | OPTIM_WRAPPER_CONSTRUCTORS = Registry( 60 | 'optimizer constructor', parent=MMENGINE_OPTIM_WRAPPER_CONSTRUCTORS) 61 | # manage all kinds of parameter schedulers like `MultiStepLR` 62 | PARAM_SCHEDULERS = Registry( 63 | 'parameter scheduler', parent=MMENGINE_PARAM_SCHEDULERS) 64 | # manage all kinds of metrics 65 | METRICS = Registry('metric', parent=MMENGINE_METRICS) 66 | 67 | # manage task-specific modules like anchor generators and box coders 68 | TASK_UTILS = Registry('task util', parent=MMENGINE_TASK_UTILS) 69 | 70 | # manage visualizer 71 | VISUALIZERS = Registry('visualizer', parent=MMENGINE_VISUALIZERS) 72 | # manage visualizer backend 73 | VISBACKENDS = Registry('vis_backend', parent=MMENGINE_VISBACKENDS) 74 | 75 | # manage logprocessor 76 | LOG_PROCESSORS = Registry('log_processor', parent=MMENGINE_LOG_PROCESSORS) 77 | -------------------------------------------------------------------------------- /configs/_base_/datasets/ocdpcb.py: -------------------------------------------------------------------------------- 1 | # dataset settings 2 | dataset_type = 'OCDPCBDataset' 3 | data_root = 'data/split_ss_ocdpcb/' 4 | backend_args = None 5 | 6 | train_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 8 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 9 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 10 | dict( 11 | type='RandomRotate', 12 | prob=1, 13 | angle_range=180), 14 | dict( 15 | type='mmdet.RandomResize', 16 | resize_type='mmdet.Resize', 17 | scale=(1024, 1024), 18 | ratio_range=(0.5, 1.5), 19 | keep_ratio=True), 20 | dict(type='mmdet.RandomCrop', crop_size=(1024, 1024)), 21 | dict(type='mmdet.YOLOXHSVRandomAug'), 22 | dict( 23 | type='mmdet.RandomFlip', 24 | prob=0.75, 25 | direction=['horizontal', 'vertical', 'diagonal']), 26 | dict( 27 | type='mmdet.Pad', size=(1024, 1024), 28 | pad_val=dict(img=(114, 114, 114))), 29 | dict(type='mmdet.PackDetInputs') 30 | ] 31 | val_pipeline = [ 32 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 33 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 34 | # avoid bboxes being resized 35 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 36 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 37 | dict( 38 | type='mmdet.PackDetInputs', 39 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 40 | 'scale_factor')) 41 | ] 42 | test_pipeline = [ 43 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 44 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 45 | dict( 46 | type='mmdet.PackDetInputs', 47 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 48 | 'scale_factor')) 49 | ] 50 | train_dataloader = dict( 51 | batch_size=4, 52 | num_workers=4, 53 | persistent_workers=True, 54 | sampler=dict(type='DefaultSampler', shuffle=True), 55 | batch_sampler=None, 56 | dataset=dict( 57 | type=dataset_type, 58 | data_root=data_root, 59 | ann_file='train/annfiles/', 60 | data_prefix=dict(img_path='train/images/'), 61 | img_shape=(1024, 1024), 62 | filter_cfg=dict(filter_empty_gt=True), 63 | pipeline=train_pipeline)) 64 | val_dataloader = dict( 65 | batch_size=4, 66 | num_workers=4, 67 | persistent_workers=True, 68 | drop_last=False, 69 | sampler=dict(type='DefaultSampler', shuffle=False), 70 | dataset=dict( 71 | type=dataset_type, 72 | data_root=data_root, 73 | ann_file='train/annfiles/', 74 | data_prefix=dict(img_path='train/images/'), 75 | img_shape=(1024, 1024), 76 | test_mode=True, 77 | pipeline=val_pipeline)) 78 | test_dataloader = val_dataloader 79 | 80 | val_evaluator = dict(type='DOTAMetric', metric='mAP') 81 | test_evaluator = val_evaluator 82 | 83 | # inference on test dataset and format the output results 84 | # for submission. Note: the test set has no annotation. 85 | # test_dataloader = dict( 86 | # batch_size=16, 87 | # num_workers=16, 88 | # persistent_workers=True, 89 | # drop_last=False, 90 | # sampler=dict(type='DefaultSampler', shuffle=False), 91 | # dataset=dict( 92 | # type=dataset_type, 93 | # data_root=data_root, 94 | # data_prefix=dict(img_path='test/images/'), 95 | # img_shape=(1024, 1024), 96 | # test_mode=True, 97 | # pipeline=test_pipeline)) 98 | # test_evaluator = dict( 99 | # type='DOTAMetric', 100 | # format_only=True, 101 | # merge_patches=True, 102 | # outfile_prefix='./work_dirs/dota/Task1') 103 | -------------------------------------------------------------------------------- /configs/point2rbox_v2/point2rbox_v2-1x-sku110k.py: -------------------------------------------------------------------------------- 1 | _base_ = [ 2 | '../_base_/datasets/sku110k.py', '../_base_/schedules/schedule_1x.py', 3 | '../_base_/default_runtime.py' 4 | ] 5 | angle_version = 'le90' 6 | 7 | # model settings 8 | model = dict( 9 | type='Point2RBoxV2', 10 | ss_prob=[0.68, 0.07, 0.25], 11 | copy_paste_start_epoch=6, 12 | data_preprocessor=dict( 13 | type='mmdet.DetDataPreprocessor', 14 | mean=[123.675, 116.28, 103.53], 15 | std=[58.395, 57.12, 57.375], 16 | bgr_to_rgb=True, 17 | pad_size_divisor=32, 18 | boxtype2tensor=False), 19 | backbone=dict( 20 | type='mmdet.ResNet', 21 | depth=50, 22 | num_stages=4, 23 | out_indices=(1, 2, 3), 24 | frozen_stages=1, 25 | norm_cfg=dict(type='BN', requires_grad=True), 26 | norm_eval=True, 27 | style='pytorch', 28 | init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), 29 | neck=dict( 30 | type='mmdet.FPN', 31 | in_channels=[512, 1024, 2048], 32 | out_channels=128, 33 | start_level=0, 34 | add_extra_convs='on_output', 35 | num_outs=3, 36 | relu_before_extra_convs=True), 37 | bbox_head=dict( 38 | type='Point2RBoxV2Head', 39 | num_classes=1, 40 | in_channels=128, 41 | feat_channels=128, 42 | strides=[8], 43 | edge_loss_start_epoch=6, 44 | joint_angle_start_epoch=1, 45 | voronoi_type='gaussian-orientation', 46 | voronoi_thres=dict(default=[0.995, 0.01]), 47 | square_cls=[], 48 | edge_loss_cls=[0], 49 | post_process={}, 50 | angle_coder=dict( 51 | type='PSCCoder', 52 | angle_version='le90', 53 | dual_freq=False, 54 | num_step=3, 55 | thr_mod=0), 56 | loss_cls=dict( 57 | type='mmdet.FocalLoss', 58 | use_sigmoid=True, 59 | gamma=2.0, 60 | alpha=0.25, 61 | loss_weight=1.0), 62 | loss_bbox=dict(type='GDLoss', loss_type='gwd', loss_weight=5.0), 63 | loss_overlap=dict( 64 | type='GaussianOverlapLoss', loss_weight=10.0, lamb=0), 65 | loss_voronoi=dict( 66 | type='VoronoiWatershedLoss', loss_weight=5.0), 67 | loss_bbox_edg=dict( 68 | type='EdgeLoss', loss_weight=0.3), 69 | loss_ss=dict( 70 | type='Point2RBoxV2ConsistencyLoss', loss_weight=1.0)), 71 | # training and testing settings 72 | train_cfg=None, 73 | test_cfg=dict( 74 | nms_pre=2000, 75 | min_bbox_size=0, 76 | score_thr=0.05, 77 | nms=dict(type='nms_rotated', iou_threshold=0.1), 78 | max_per_img=2000)) 79 | 80 | # load point annotations 81 | train_pipeline = [ 82 | dict(type='mmdet.LoadImageFromFile', backend_args={{_base_.backend_args}}), 83 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='rbox'), 84 | dict(type='mmdet.FixShapeResize', width=800, height=800, keep_ratio=True), 85 | dict(type='ConvertWeakSupervision', point_proportion=1., hbox_proportion=0), 86 | dict( 87 | type='mmdet.RandomFlip', 88 | prob=0.75, 89 | direction=['horizontal', 'vertical', 'diagonal']), 90 | dict(type='RandomRotate', prob=1, angle_range=180), 91 | dict(type='mmdet.PackDetInputs') 92 | ] 93 | 94 | train_dataloader = dict(batch_size=4, 95 | dataset=dict(pipeline=train_pipeline)) 96 | 97 | # optimizer 98 | optim_wrapper = dict( 99 | optimizer=dict( 100 | _delete_=True, 101 | type='AdamW', 102 | lr=0.00005, 103 | betas=(0.9, 0.999), 104 | weight_decay=0.05)) 105 | 106 | train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=12, val_interval=12) 107 | custom_hooks = [dict(type='mmdet.SetEpochInfoHook')] 108 | -------------------------------------------------------------------------------- /configs/h2rbox/h2rbox-le90_r50_fpn_adamw-1x_dota.py: -------------------------------------------------------------------------------- 1 | _base_ = [ 2 | '../_base_/datasets/dota.py', '../_base_/schedules/schedule_1x.py', 3 | '../_base_/default_runtime.py' 4 | ] 5 | angle_version = 'le90' 6 | 7 | # model settings 8 | model = dict( 9 | type='H2RBoxDetector', 10 | crop_size=(1024, 1024), 11 | data_preprocessor=dict( 12 | type='mmdet.DetDataPreprocessor', 13 | mean=[123.675, 116.28, 103.53], 14 | std=[58.395, 57.12, 57.375], 15 | bgr_to_rgb=True, 16 | pad_size_divisor=32, 17 | boxtype2tensor=False), 18 | backbone=dict( 19 | type='mmdet.ResNet', 20 | depth=50, 21 | num_stages=4, 22 | out_indices=(0, 1, 2, 3), 23 | frozen_stages=1, 24 | norm_cfg=dict(type='BN', requires_grad=True), 25 | norm_eval=True, 26 | style='pytorch', 27 | init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), 28 | neck=dict( 29 | type='mmdet.FPN', 30 | in_channels=[256, 512, 1024, 2048], 31 | out_channels=256, 32 | start_level=1, 33 | add_extra_convs='on_output', 34 | num_outs=5, 35 | relu_before_extra_convs=True), 36 | bbox_head=dict( 37 | type='H2RBoxHead', 38 | num_classes=15, 39 | in_channels=256, 40 | angle_version='le90', 41 | stacked_convs=4, 42 | feat_channels=256, 43 | strides=[8, 16, 32, 64, 128], 44 | center_sampling=True, 45 | center_sample_radius=1.5, 46 | norm_on_bbox=True, 47 | centerness_on_reg=True, 48 | use_hbbox_loss=False, 49 | scale_angle=True, 50 | bbox_coder=dict( 51 | type='DistanceAnglePointCoder', angle_version=angle_version), 52 | loss_cls=dict( 53 | type='mmdet.FocalLoss', 54 | use_sigmoid=True, 55 | gamma=2.0, 56 | alpha=0.25, 57 | loss_weight=1.0), 58 | loss_bbox=dict(type='mmdet.IoULoss', loss_weight=1.0), 59 | loss_centerness=dict( 60 | type='mmdet.CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), 61 | square_classes=[9, 11], 62 | crop_size=(1024, 1024), 63 | loss_bbox_ss=dict( 64 | type='H2RBoxConsistencyLoss', 65 | loss_weight=0.4, 66 | center_loss_cfg=dict(type='mmdet.L1Loss', loss_weight=0.0), 67 | shape_loss_cfg=dict(type='mmdet.IoULoss', loss_weight=1.0), 68 | angle_loss_cfg=dict(type='mmdet.L1Loss', loss_weight=1.0))), 69 | # training and testing settings 70 | train_cfg=None, 71 | test_cfg=dict( 72 | nms_pre=2000, 73 | min_bbox_size=0, 74 | score_thr=0.05, 75 | nms=dict(type='nms_rotated', iou_threshold=0.1), 76 | max_per_img=2000)) 77 | 78 | # load hbox annotations 79 | train_pipeline = [ 80 | dict(type='mmdet.LoadImageFromFile', backend_args={{_base_.backend_args}}), 81 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 82 | # Horizontal GTBox, (x1,y1,x2,y2) 83 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='hbox')), 84 | # Horizontal GTBox, (x,y,w,h,theta) 85 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 86 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 87 | dict( 88 | type='mmdet.RandomFlip', 89 | prob=0.75, 90 | direction=['horizontal', 'vertical', 'diagonal']), 91 | dict(type='mmdet.PackDetInputs') 92 | ] 93 | 94 | train_dataloader = dict(dataset=dict(pipeline=train_pipeline)) 95 | 96 | # optimizer 97 | optim_wrapper = dict( 98 | optimizer=dict( 99 | _delete_=True, 100 | type='AdamW', 101 | lr=0.0001, 102 | betas=(0.9, 0.999), 103 | weight_decay=0.05)) 104 | 105 | train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=12, val_interval=6) 106 | -------------------------------------------------------------------------------- /configs/h2rbox/dotav15/h2rbox-le90_r50_fpn_adamw-1x_dotav15.py: -------------------------------------------------------------------------------- 1 | _base_ = [ 2 | '../../_base_/datasets/dotav15.py', 3 | '../../_base_/schedules/schedule_1x.py', '../../_base_/default_runtime.py' 4 | ] 5 | angle_version = 'le90' 6 | 7 | # model settings 8 | model = dict( 9 | type='H2RBoxDetector', 10 | crop_size=(1024, 1024), 11 | data_preprocessor=dict( 12 | type='mmdet.DetDataPreprocessor', 13 | mean=[123.675, 116.28, 103.53], 14 | std=[58.395, 57.12, 57.375], 15 | bgr_to_rgb=True, 16 | pad_size_divisor=32, 17 | boxtype2tensor=False), 18 | backbone=dict( 19 | type='mmdet.ResNet', 20 | depth=50, 21 | num_stages=4, 22 | out_indices=(0, 1, 2, 3), 23 | frozen_stages=1, 24 | norm_cfg=dict(type='BN', requires_grad=True), 25 | norm_eval=True, 26 | style='pytorch', 27 | init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), 28 | neck=dict( 29 | type='mmdet.FPN', 30 | in_channels=[256, 512, 1024, 2048], 31 | out_channels=256, 32 | start_level=1, 33 | add_extra_convs='on_output', 34 | num_outs=5, 35 | relu_before_extra_convs=True), 36 | bbox_head=dict( 37 | type='H2RBoxHead', 38 | num_classes=16, 39 | in_channels=256, 40 | angle_version='le90', 41 | stacked_convs=4, 42 | feat_channels=256, 43 | strides=[8, 16, 32, 64, 128], 44 | center_sampling=True, 45 | center_sample_radius=1.5, 46 | norm_on_bbox=True, 47 | centerness_on_reg=True, 48 | use_hbbox_loss=False, 49 | scale_angle=True, 50 | bbox_coder=dict( 51 | type='DistanceAnglePointCoder', angle_version=angle_version), 52 | loss_cls=dict( 53 | type='mmdet.FocalLoss', 54 | use_sigmoid=True, 55 | gamma=2.0, 56 | alpha=0.25, 57 | loss_weight=1.0), 58 | loss_bbox=dict(type='mmdet.IoULoss', loss_weight=1.0), 59 | loss_centerness=dict( 60 | type='mmdet.CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), 61 | square_classes=[9, 11], 62 | crop_size=(1024, 1024), 63 | loss_bbox_ss=dict( 64 | type='H2RBoxConsistencyLoss', 65 | loss_weight=0.4, 66 | center_loss_cfg=dict(type='mmdet.L1Loss', loss_weight=0.0), 67 | shape_loss_cfg=dict(type='mmdet.IoULoss', loss_weight=1.0), 68 | angle_loss_cfg=dict(type='mmdet.L1Loss', loss_weight=1.0))), 69 | # training and testing settings 70 | train_cfg=None, 71 | test_cfg=dict( 72 | nms_pre=2000, 73 | min_bbox_size=0, 74 | score_thr=0.05, 75 | nms=dict(type='nms_rotated', iou_threshold=0.1), 76 | max_per_img=2000)) 77 | 78 | # load hbox annotations 79 | train_pipeline = [ 80 | dict(type='mmdet.LoadImageFromFile', backend_args={{_base_.backend_args}}), 81 | dict(type='mmdet.LoadAnnotations', with_bbox=True, box_type='qbox'), 82 | # Horizontal GTBox, (x1,y1,x2,y2) 83 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='hbox')), 84 | # Horizontal GTBox, (x,y,w,h,theta) 85 | dict(type='ConvertBoxType', box_type_mapping=dict(gt_bboxes='rbox')), 86 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 87 | dict( 88 | type='mmdet.RandomFlip', 89 | prob=0.75, 90 | direction=['horizontal', 'vertical', 'diagonal']), 91 | dict(type='mmdet.PackDetInputs') 92 | ] 93 | 94 | train_dataloader = dict(dataset=dict(pipeline=train_pipeline)) 95 | 96 | # optimizer 97 | optim_wrapper = dict( 98 | optimizer=dict( 99 | _delete_=True, 100 | type='AdamW', 101 | lr=0.0001, 102 | betas=(0.9, 0.999), 103 | weight_decay=0.05)) 104 | 105 | train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=12, val_interval=6) 106 | -------------------------------------------------------------------------------- /configs/_base_/datasets/dota_coco.py: -------------------------------------------------------------------------------- 1 | # dataset settings 2 | dataset_type = 'mmdet.CocoDataset' 3 | data_root = 'data/split_ms_dota/' 4 | backend_args = None 5 | 6 | train_pipeline = [ 7 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 8 | dict( 9 | type='mmdet.LoadAnnotations', 10 | with_bbox=True, 11 | with_mask=True, 12 | poly2mask=False), 13 | dict(type='ConvertMask2BoxType', box_type='rbox'), 14 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 15 | dict( 16 | type='mmdet.RandomFlip', 17 | prob=0.75, 18 | direction=['horizontal', 'vertical', 'diagonal']), 19 | dict(type='mmdet.PackDetInputs') 20 | ] 21 | val_pipeline = [ 22 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 23 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 24 | # avoid bboxes being resized 25 | dict( 26 | type='mmdet.LoadAnnotations', 27 | with_bbox=True, 28 | with_mask=True, 29 | poly2mask=False), 30 | dict(type='ConvertMask2BoxType', box_type='qbox'), 31 | dict( 32 | type='mmdet.PackDetInputs', 33 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 34 | 'scale_factor', 'instances')) 35 | ] 36 | test_pipeline = [ 37 | dict(type='mmdet.LoadImageFromFile', backend_args=backend_args), 38 | dict(type='mmdet.Resize', scale=(1024, 1024), keep_ratio=True), 39 | dict( 40 | type='mmdet.PackDetInputs', 41 | meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 42 | 'scale_factor')) 43 | ] 44 | 45 | metainfo = dict( 46 | classes=('plane', 'baseball-diamond', 'bridge', 'ground-track-field', 47 | 'small-vehicle', 'large-vehicle', 'ship', 'tennis-court', 48 | 'basketball-court', 'storage-tank', 'soccer-ball-field', 49 | 'roundabout', 'harbor', 'swimming-pool', 'helicopter')) 50 | 51 | train_dataloader = dict( 52 | batch_size=2, 53 | num_workers=2, 54 | persistent_workers=True, 55 | sampler=dict(type='DefaultSampler', shuffle=True), 56 | batch_sampler=None, 57 | dataset=dict( 58 | type=dataset_type, 59 | metainfo=metainfo, 60 | data_root=data_root, 61 | ann_file='train/train.json', 62 | data_prefix=dict(img='train/images/'), 63 | filter_cfg=dict(filter_empty_gt=True), 64 | pipeline=train_pipeline, 65 | backend_args=backend_args)) 66 | val_dataloader = dict( 67 | batch_size=1, 68 | num_workers=2, 69 | persistent_workers=True, 70 | drop_last=False, 71 | sampler=dict(type='DefaultSampler', shuffle=False), 72 | dataset=dict( 73 | type=dataset_type, 74 | metainfo=metainfo, 75 | data_root=data_root, 76 | ann_file='val/val.json', 77 | data_prefix=dict(img='val/images/'), 78 | test_mode=True, 79 | pipeline=val_pipeline, 80 | backend_args=backend_args)) 81 | test_dataloader = val_dataloader 82 | 83 | val_evaluator = dict( 84 | type='RotatedCocoMetric', 85 | metric='bbox', 86 | classwise=True, 87 | backend_args=backend_args) 88 | 89 | test_evaluator = val_evaluator 90 | 91 | # inference on test dataset and format the output results 92 | # for submission. Note: the test set has no annotation. 93 | # test_dataloader = dict( 94 | # batch_size=1, 95 | # num_workers=2, 96 | # persistent_workers=True, 97 | # drop_last=False, 98 | # sampler=dict(type='DefaultSampler', shuffle=False), 99 | # dataset=dict( 100 | # type=dataset_type, 101 | # ann_file='test/test.json', 102 | # data_prefix=dict(img='test/images/'), 103 | # test_mode=True, 104 | # pipeline=test_pipeline)) 105 | # test_evaluator = dict( 106 | # type='DOTAMetric', 107 | # format_only=True, 108 | # merge_patches=True, 109 | # outfile_prefix='./work_dirs/dota/Task1') 110 | --------------------------------------------------------------------------------