Unverified Commit e3f0e8b0 authored by Danila Rukhovich's avatar Danila Rukhovich Committed by GitHub
Browse files

[Feature] add scannet instance dataset with metrics (#1230)



* add scannet instance dataset with metrics

* fix import

* add missing import

* fix comments and docstrings

* merge v1.0.0.dev0 to scannet_instance_dataset (#1)

* Bump to v0.18.0 (#1148)

* Update README & getting_started & changelog & version.py

* resolve comments

* Update the required maximum version of mmcv-full

* Update changelog.md

* Update getting_started.md

* Add highlight in changelog.md

* update imvoxelnet citation (#1153)

* deprecate the support for "python setup.py test" (#1164)

* add OpenMMLab website and platform links (#1176)

* [Fix] Update regnet metafile (#1184)

* update regnet metafile

* Add Architechture in RegNet metafile

* fix axis=0 rotation in master branch (#1182)

* [Enhance] support semantic seg in Flip3D augmentation (#1181)

* support semantic seg in flip

* change box_dtype_3d to bbox3d_fields

* add point cloud annotation in doc (#1185)

* [Fix] Fix bug in non-distributed multi-gpu training/testing (#1197)

* Fix bug in non-distributed multi-gpu training/testing

* add deprecated warning to void BC-breaking

* Add missing explanation of cam_intrinsic in the nuScenes dataset doc (#1193)

* [Fix] Fix corner bug in different coordinates (#1212)

* fix corner bug in cam coord

* fix corner bugs in depth & lidar coord

* Bump to v0.18.1 (#1218)

* bump to v0.18.1

* fix comments

* update bazel version (#1223)

* [Fix] fix pointpillars bug on kitti in master branch (#1163)

* fix pointpillars bug on kitti in master branch

* replace with AlignedAnchorGenerator

* Update the installation of MMCV (#1226)

* [Fix] Fix a potential overflow bug when post_max_size is set too large in the circle_nms (#1225)

* [Fix] overflow bug

* [Fix] typo
Co-authored-by: default avatarzeyuzeng <zeyuzeng@autox.ai>
Co-authored-by: default avatarzeyu-hello <zeyuzeng@hotmail.com>

* Fix PointRCNN bugs (#1224)

* fix bug to allow pointnet to train in fp16 (#1207)

* fix bug to allow pointnet to train in fp16

* remove unused import

* fix lint

* fix lint for gather_points_cuda.cu
Co-authored-by: default avatarpeng <maskjp@tamu.edu>

* [Fix] Recheck import sorting (#1242)

* fix missed mmcv

* reinstall pre-commit and recheck

* fix inference_demo.ipynb bug (#1236)

* [Enhance] upgrade PointPillars performace on dev branch (#1166)

* upgrade PointPillars performace on dev branch

* update DynamicPillarFeatureNet

* fix comments

* change to AlignedAnchor3DRangeGenerator

* change to AlignedAnchor3DRangeGenerator

* fix

* replace with AlignedAnchorGenerator

* fix lint

* update using isort

* Bump to v1.0.0.rc0 (#928)

* [Refactor] Main code modification for coordinate system refactor (#677)

* [Enhance] Add script for data update (#774)

* Fixed wrong config paths and fixed a bug in test

* Fixed metafile

* Coord sys refactor (main code)

* Update test_waymo_dataset.py

* Manually resolve conflict

* Removed unused lines and fixed imports

* remove coord2box and box2coord

* update dir_limit_offset

* Some minor improvements

* Removed some \s in comments

* Revert a change

* Change Box3DMode to Coord3DMode where points are converted

* Fix points_in_bbox function

* Fix Imvoxelnet config

* Revert adding a line

* Fix rotation bug when batch size is 0

* Keep sign of dir_scores as before

* Fix several comments

* Add a comment

* Fix docstring

* Add data update scripts

* Fix comments

* fix import (#839)

* [Enhance]  refactor  iou_neg_piecewise_sampler.py (#842)

* [Refactor] Main code modification for coordinate system refactor (#677)

* [Enhance] Add script for data update (#774)

* Fixed wrong config paths and fixed a bug in test

* Fixed metafile

* Coord sys refactor (main code)

* Update test_waymo_dataset.py

* Manually resolve conflict

* Removed unused lines and fixed imports

* remove coord2box and box2coord

* update dir_limit_offset

* Some minor improvements

* Removed some \s in comments

* Revert a change

* Change Box3DMode to Coord3DMode where points are converted

* Fix points_in_bbox function

* Fix Imvoxelnet config

* Revert adding a line

* Fix rotation bug when batch size is 0

* Keep sign of dir_scores as before

* Fix several comments

* Add a comment

* Fix docstring

* Add data update scripts

* Fix comments

* fix import

* refactor iou_neg_piecewise_sampler.py

* add docstring

* modify docstring
Co-authored-by: default avatarYezhen Cong <52420115+THU17cyz@users.noreply.github.com>
Co-authored-by: default avatarTHU17cyz <congyezhen71@hotmail.com>

* [Feature] Add roipooling cuda ops (#843)

* [Refactor] Main code modification for coordinate system refactor (#677)

* [Enhance] Add script for data update (#774)

* Fixed wrong config paths and fixed a bug in test

* Fixed metafile

* Coord sys refactor (main code)

* Update test_waymo_dataset.py

* Manually resolve conflict

* Removed unused lines and fixed imports

* remove coord2box and box2coord

* update dir_limit_offset

* Some minor improvements

* Removed some \s in comments

* Revert a change

* Change Box3DMode to Coord3DMode where points are converted

* Fix points_in_bbox function

* Fix Imvoxelnet config

* Revert adding a line

* Fix rotation bug when batch size is 0

* Keep sign of dir_scores as before

* Fix several comments

* Add a comment

* Fix docstring

* Add data update scripts

* Fix comments

* fix import

* add roipooling cuda ops

* add roi extractor

* add test_roi_extractor unittest

* Modify setup.py to install roipooling ops

* modify docstring

* remove enlarge bbox in roipoint pooling

* add_roipooling_ops

* modify docstring
Co-authored-by: default avatarYezhen Cong <52420115+THU17cyz@users.noreply.github.com>
Co-authored-by: default avatarTHU17cyz <congyezhen71@hotmail.com>

* [Refactor] Refactor code structure and docstrings (#803)

* refactor points_in_boxes

* Merge same functions of three boxes

* More docstring fixes and unify x/y/z size

* Add "optional" and fix "Default"

* Add "optional" and fix "Default"

* Add "optional" and fix "Default"

* Add "optional" and fix "Default"

* Add "optional" and fix "Default"

* Remove None in function param type

* Fix unittest

* Add comments for NMS functions

* Merge methods of Points

* Add unittest

* Add optional and default value

* Fix box conversion and add unittest

* Fix comments

* Add unit test

* Indent

* Fix CI

* Remove useless \\

* Remove useless \\

* Remove useless \\

* Remove useless \\

* Remove useless \\

* Add unit test for box bev

* More unit tests and refine docstrings in box_np_ops

* Fix comment

* Add deprecation warning

* [Feature] PointXYZWHLRBBoxCoder (#856)

* support PointBasedBoxCoder

* fix unittest bug

* support unittest in gpu

* support unittest in gpu

* modified docstring

* add args

* add args

* [Enhance] Change Groupfree3D config (#855)

* All mods

* PointSample

* PointSample

* [Doc] Add tutorials/data_pipeline Chinese version (#827)

* [Doc] Add tutorials/data_pipeline Chinese version

* refine doc

* Use the absolute link

* Use the absolute link
Co-authored-by: default avatarTai-Wang <tab_wang@outlook.com>

* [Doc] Add Chinese doc for `scannet_det.md` (#836)

* Part

* Complete

* Fix comments

* Fix comments

* [Doc] Add Chinese doc for `waymo_det.md` (#859)

* Add complete translation

* Refinements

* Fix comments

* Fix a minor typo
Co-authored-by: default avatarTai-Wang <tab_wang@outlook.com>

* Remove 2D annotations on Lyft (#867)

* Add header for files (#869)

* Add header for files

* Add header for files

* Add header for files

* Add header for files

* [fix] fix typos (#872)

* Fix 3 unworking configs (#882)

* [Fix] Fix `index.rst` for Chinese docs (#873)

* Fix index.rst for zh docs

* Change switch language

* [Fix] Centerpoint head nested list transpose  (#879)

* FIX Transpose nested lists without Numpy

* Removed unused Numpy import

* [Enhance] Update PointFusion (#791)

* update point fusion

* remove LIDAR hardcode

* move get_proj_mat_by_coord_type to utils

* fix lint

* remove todo

* fix lint

* [Doc] Add nuscenes_det.md Chinese version (#854)

* add nus chinese doc

* add nuScenes Chinese doc

* fix typo

* fix typo

* fix typo

* fix typo

* fix typo

* [Fix] Fix RegNet pretrained weight loading (#889)

* Fix regnet pretrained weight loading

* Remove unused file

* Fix centerpoint tta (#892)

* [Enhance] Add benchmark regression script (#808)

* Initial commit

* [Feature] Support DGCNN (v1.0.0.dev0) (#896)

* support dgcnn

* support dgcnn

* support dgcnn

* support dgcnn

* support dgcnn

* support dgcnn

* support dgcnn

* support dgcnn

* support dgcnn

* support dgcnn

* fix typo

* fix typo

* fix typo

* del gf&fa registry (wo reuse pointnet module)

* fix typo

* add benchmark and add copyright header (for DGCNN only)

* fix typo

* fix typo

* fix typo

* fix typo

* fix typo

* support dgcnn

* Change cam rot_3d_in_axis (#906)

* [Doc] Add coord sys tutorial pic and change links to dev branch (#912)

* Modify link branch and add pic

* Fix pic

* Update v1.0.0rc0 changelog

* Remove v1.0.0.rc0 changelog

* Init v1.0.0.rc0 changelog

* Fix minor typos in the zh-CN index.rst

* Add master updates in changelog v1.0.0

* Update changelog_v1.0.md

* Update changelog_v1.0.md

* Update changelog_v1.0.md

* Adjust the order of logs

* Update the number of developers

* Add v1.0.0.rc0 changelog

* Delete changelog_v1.0.md

* Add RoIPointPool3d back

* Change openmmlab pre-commit hook rev

* Add links for compatibility doc

* Refine details

* Update README.md

* Update highlights

* Update README_zh-CN.md

* Update getting_started.md

* Update getting_started.md

* Update version.py

* Fix the released version name

* Fix version name

* Update version name

* Update version name

* Update version name

* Update version name
Co-authored-by: default avatarYezhen Cong <52420115+THU17cyz@users.noreply.github.com>
Co-authored-by: default avatarXi Liu <75658786+xiliu8006@users.noreply.github.com>
Co-authored-by: default avatarTHU17cyz <congyezhen71@hotmail.com>
Co-authored-by: default avatarWenhao Wu <79644370+wHao-Wu@users.noreply.github.com>
Co-authored-by: default avatardingchang <hudingchang.vendor@sensetime.com>
Co-authored-by: default avatar谢恩泽 <Johnny_ez@163.com>
Co-authored-by: default avatarRobin Karlsson <34254153+robin-karlsson0@users.noreply.github.com>
Co-authored-by: default avatarDanila Rukhovich <danrukh@gmail.com>
Co-authored-by: default avatarChaimZhu <zhuchenming@pjlab.org.cn>
Co-authored-by: default avatarWenhao Wu <79644370+wHao-Wu@users.noreply.github.com>
Co-authored-by: default avatarChaimZhu <zhuchenming@pjlab.org.cn>
Co-authored-by: default avatarTai-Wang <tab_wang@outlook.com>
Co-authored-by: default avatarDouble-Z <zengzeyu@hotmail.com>
Co-authored-by: default avatarzeyuzeng <zeyuzeng@autox.ai>
Co-authored-by: default avatarzeyu-hello <zeyuzeng@hotmail.com>
Co-authored-by: default avatarmaskjp <maskjp@163.com>
Co-authored-by: default avatarpeng <maskjp@tamu.edu>
Co-authored-by: default avatarYezhen Cong <52420115+THU17cyz@users.noreply.github.com>
Co-authored-by: default avatarXi Liu <75658786+xiliu8006@users.noreply.github.com>
Co-authored-by: default avatarTHU17cyz <congyezhen71@hotmail.com>
Co-authored-by: default avatardingchang <hudingchang.vendor@sensetime.com>
Co-authored-by: default avatar谢恩泽 <Johnny_ez@163.com>
Co-authored-by: default avatarRobin Karlsson <34254153+robin-karlsson0@users.noreply.github.com>

* fix lint, add docstring

* V1.0.0.dev0 (#2)

* Bump to v0.18.0 (#1148)

* Update README & getting_started & changelog & version.py

* resolve comments

* Update the required maximum version of mmcv-full

* Update changelog.md

* Update getting_started.md

* Add highlight in changelog.md

* update imvoxelnet citation (#1153)

* deprecate the support for "python setup.py test" (#1164)

* add OpenMMLab website and platform links (#1176)

* [Fix] Update regnet metafile (#1184)

* update regnet metafile

* Add Architechture in RegNet metafile

* fix axis=0 rotation in master branch (#1182)

* [Enhance] support semantic seg in Flip3D augmentation (#1181)

* support semantic seg in flip

* change box_dtype_3d to bbox3d_fields

* add point cloud annotation in doc (#1185)

* [Fix] Fix bug in non-distributed multi-gpu training/testing (#1197)

* Fix bug in non-distributed multi-gpu training/testing

* add deprecated warning to void BC-breaking

* Add missing explanation of cam_intrinsic in the nuScenes dataset doc (#1193)

* [Fix] Fix corner bug in different coordinates (#1212)

* fix corner bug in cam coord

* fix corner bugs in depth & lidar coord

* Bump to v0.18.1 (#1218)

* bump to v0.18.1

* fix comments

* update bazel version (#1223)

* [Fix] fix pointpillars bug on kitti in master branch (#1163)

* fix pointpillars bug on kitti in master branch

* replace with AlignedAnchorGenerator

* Update the installation of MMCV (#1226)

* [Fix] Fix a potential overflow bug when post_max_size is set too large in the circle_nms (#1225)

* [Fix] overflow bug

* [Fix] typo
Co-authored-by: default avatarzeyuzeng <zeyuzeng@autox.ai>
Co-authored-by: default avatarzeyu-hello <zeyuzeng@hotmail.com>

* Fix PointRCNN bugs (#1224)

* fix bug to allow pointnet to train in fp16 (#1207)

* fix bug to allow pointnet to train in fp16

* remove unused import

* fix lint

* fix lint for gather_points_cuda.cu
Co-authored-by: default avatarpeng <maskjp@tamu.edu>

* [Fix] Recheck import sorting (#1242)

* fix missed mmcv

* reinstall pre-commit and recheck

* fix inference_demo.ipynb bug (#1236)

* [Enhance] upgrade PointPillars performace on dev branch (#1166)

* upgrade PointPillars performace on dev branch

* update DynamicPillarFeatureNet

* fix comments

* change to AlignedAnchor3DRangeGenerator

* change to AlignedAnchor3DRangeGenerator

* fix

* replace with AlignedAnchorGenerator

* fix lint

* update using isort

* Bump to v1.0.0.rc0 (#928)

* [Refactor] Main code modification for coordinate system refactor (#677)

* [Enhance] Add script for data update (#774)

* Fixed wrong config paths and fixed a bug in test

* Fixed metafile

* Coord sys refactor (main code)

* Update test_waymo_dataset.py

* Manually resolve conflict

* Removed unused lines and fixed imports

* remove coord2box and box2coord

* update dir_limit_offset

* Some minor improvements

* Removed some \s in comments

* Revert a change

* Change Box3DMode to Coord3DMode where points are converted

* Fix points_in_bbox function

* Fix Imvoxelnet config

* Revert adding a line

* Fix rotation bug when batch size is 0

* Keep sign of dir_scores as before

* Fix several comments

* Add a comment

* Fix docstring

* Add data update scripts

* Fix comments

* fix import (#839)

* [Enhance]  refactor  iou_neg_piecewise_sampler.py (#842)

* [Refactor] Main code modification for coordinate system refactor (#677)

* [Enhance] Add script for data update (#774)

* Fixed wrong config paths and fixed a bug in test

* Fixed metafile

* Coord sys refactor (main code)

* Update test_waymo_dataset.py

* Manually resolve conflict

* Removed unused lines and fixed imports

* remove coord2box and box2coord

* update dir_limit_offset

* Some minor improvements

* Removed some \s in comments

* Revert a change

* Change Box3DMode to Coord3DMode where points are converted

* Fix points_in_bbox function

* Fix Imvoxelnet config

* Revert adding a line

* Fix rotation bug when batch size is 0

* Keep sign of dir_scores as before

* Fix several comments

* Add a comment

* Fix docstring

* Add data update scripts

* Fix comments

* fix import

* refactor iou_neg_piecewise_sampler.py

* add docstring

* modify docstring
Co-authored-by: default avatarYezhen Cong <52420115+THU17cyz@users.noreply.github.com>
Co-authored-by: default avatarTHU17cyz <congyezhen71@hotmail.com>

* [Feature] Add roipooling cuda ops (#843)

* [Refactor] Main code modification for coordinate system refactor (#677)

* [Enhance] Add script for data update (#774)

* Fixed wrong config paths and fixed a bug in test

* Fixed metafile

* Coord sys refactor (main code)

* Update test_waymo_dataset.py

* Manually resolve conflict

* Removed unused lines and fixed imports

* remove coord2box and box2coord

* update dir_limit_offset

* Some minor improvements

* Removed some \s in comments

* Revert a change

* Change Box3DMode to Coord3DMode where points are converted

* Fix points_in_bbox function

* Fix Imvoxelnet config

* Revert adding a line

* Fix rotation bug when batch size is 0

* Keep sign of dir_scores as before

* Fix several comments

* Add a comment

* Fix docstring

* Add data update scripts

* Fix comments

* fix import

* add roipooling cuda ops

* add roi extractor

* add test_roi_extractor unittest

* Modify setup.py to install roipooling ops

* modify docstring

* remove enlarge bbox in roipoint pooling

* add_roipooling_ops

* modify docstring
Co-authored-by: default avatarYezhen Cong <52420115+THU17cyz@users.noreply.github.com>
Co-authored-by: default avatarTHU17cyz <congyezhen71@hotmail.com>

* [Refactor] Refactor code structure and docstrings (#803)

* refactor points_in_boxes

* Merge same functions of three boxes

* More docstring fixes and unify x/y/z size

* Add "optional" and fix "Default"

* Add "optional" and fix "Default"

* Add "optional" and fix "Default"

* Add "optional" and fix "Default"

* Add "optional" and fix "Default"

* Remove None in function param type

* Fix unittest

* Add comments for NMS functions

* Merge methods of Points

* Add unittest

* Add optional and default value

* Fix box conversion and add unittest

* Fix comments

* Add unit test

* Indent

* Fix CI

* Remove useless \\

* Remove useless \\

* Remove useless \\

* Remove useless \\

* Remove useless \\

* Add unit test for box bev

* More unit tests and refine docstrings in box_np_ops

* Fix comment

* Add deprecation warning

* [Feature] PointXYZWHLRBBoxCoder (#856)

* support PointBasedBoxCoder

* fix unittest bug

* support unittest in gpu

* support unittest in gpu

* modified docstring

* add args

* add args

* [Enhance] Change Groupfree3D config (#855)

* All mods

* PointSample

* PointSample

* [Doc] Add tutorials/data_pipeline Chinese version (#827)

* [Doc] Add tutorials/data_pipeline Chinese version

* refine doc

* Use the absolute link

* Use the absolute link
Co-authored-by: default avatarTai-Wang <tab_wang@outlook.com>

* [Doc] Add Chinese doc for `scannet_det.md` (#836)

* Part

* Complete

* Fix comments

* Fix comments

* [Doc] Add Chinese doc for `waymo_det.md` (#859)

* Add complete translation

* Refinements

* Fix comments

* Fix a minor typo
Co-authored-by: default avatarTai-Wang <tab_wang@outlook.com>

* Remove 2D annotations on Lyft (#867)

* Add header for files (#869)

* Add header for files

* Add header for files

* Add header for files

* Add header for files

* [fix] fix typos (#872)

* Fix 3 unworking configs (#882)

* [Fix] Fix `index.rst` for Chinese docs (#873)

* Fix index.rst for zh docs

* Change switch language

* [Fix] Centerpoint head nested list transpose  (#879)

* FIX Transpose nested lists without Numpy

* Removed unused Numpy import

* [Enhance] Update PointFusion (#791)

* update point fusion

* remove LIDAR hardcode

* move get_proj_mat_by_coord_type to utils

* fix lint

* remove todo

* fix lint

* [Doc] Add nuscenes_det.md Chinese version (#854)

* add nus chinese doc

* add nuScenes Chinese doc

* fix typo

* fix typo

* fix typo

* fix typo

* fix typo

* [Fix] Fix RegNet pretrained weight loading (#889)

* Fix regnet pretrained weight loading

* Remove unused file

* Fix centerpoint tta (#892)

* [Enhance] Add benchmark regression script (#808)

* Initial commit

* [Feature] Support DGCNN (v1.0.0.dev0) (#896)

* support dgcnn

* support dgcnn

* support dgcnn

* support dgcnn

* support dgcnn

* support dgcnn

* support dgcnn

* support dgcnn

* support dgcnn

* support dgcnn

* fix typo

* fix typo

* fix typo

* del gf&fa registry (wo reuse pointnet module)

* fix typo

* add benchmark and add copyright header (for DGCNN only)

* fix typo

* fix typo

* fix typo

* fix typo

* fix typo

* support dgcnn

* Change cam rot_3d_in_axis (#906)

* [Doc] Add coord sys tutorial pic and change links to dev branch (#912)

* Modify link branch and add pic

* Fix pic

* Update v1.0.0rc0 changelog

* Remove v1.0.0.rc0 changelog

* Init v1.0.0.rc0 changelog

* Fix minor typos in the zh-CN index.rst

* Add master updates in changelog v1.0.0

* Update changelog_v1.0.md

* Update changelog_v1.0.md

* Update changelog_v1.0.md

* Adjust the order of logs

* Update the number of developers

* Add v1.0.0.rc0 changelog

* Delete changelog_v1.0.md

* Add RoIPointPool3d back

* Change openmmlab pre-commit hook rev

* Add links for compatibility doc

* Refine details

* Update README.md

* Update highlights

* Update README_zh-CN.md

* Update getting_started.md

* Update getting_started.md

* Update version.py

* Fix the released version name

* Fix version name

* Update version name

* Update version name

* Update version name

* Update version name
Co-authored-by: default avatarYezhen Cong <52420115+THU17cyz@users.noreply.github.com>
Co-authored-by: default avatarXi Liu <75658786+xiliu8006@users.noreply.github.com>
Co-authored-by: default avatarTHU17cyz <congyezhen71@hotmail.com>
Co-authored-by: default avatarWenhao Wu <79644370+wHao-Wu@users.noreply.github.com>
Co-authored-by: default avatardingchang <hudingchang.vendor@sensetime.com>
Co-authored-by: default avatar谢恩泽 <Johnny_ez@163.com>
Co-authored-by: default avatarRobin Karlsson <34254153+robin-karlsson0@users.noreply.github.com>
Co-authored-by: default avatarDanila Rukhovich <danrukh@gmail.com>
Co-authored-by: default avatarChaimZhu <zhuchenming@pjlab.org.cn>

* fix ci in dev branch (#1264)
Co-authored-by: default avatarWenhao Wu <79644370+wHao-Wu@users.noreply.github.com>
Co-authored-by: default avatarChaimZhu <zhuchenming@pjlab.org.cn>
Co-authored-by: default avatarTai-Wang <tab_wang@outlook.com>
Co-authored-by: default avatarDouble-Z <zengzeyu@hotmail.com>
Co-authored-by: default avatarzeyuzeng <zeyuzeng@autox.ai>
Co-authored-by: default avatarzeyu-hello <zeyuzeng@hotmail.com>
Co-authored-by: default avatarmaskjp <maskjp@163.com>
Co-authored-by: default avatarpeng <maskjp@tamu.edu>
Co-authored-by: default avatarYezhen Cong <52420115+THU17cyz@users.noreply.github.com>
Co-authored-by: default avatarXi Liu <75658786+xiliu8006@users.noreply.github.com>
Co-authored-by: default avatarTHU17cyz <congyezhen71@hotmail.com>
Co-authored-by: default avatardingchang <hudingchang.vendor@sensetime.com>
Co-authored-by: default avatar谢恩泽 <Johnny_ez@163.com>
Co-authored-by: default avatarRobin Karlsson <34254153+robin-karlsson0@users.noreply.github.com>

* try revert imports
Co-authored-by: default avatarWenhao Wu <79644370+wHao-Wu@users.noreply.github.com>
Co-authored-by: default avatarChaimZhu <zhuchenming@pjlab.org.cn>
Co-authored-by: default avatarTai-Wang <tab_wang@outlook.com>
Co-authored-by: default avatarDouble-Z <zengzeyu@hotmail.com>
Co-authored-by: default avatarzeyuzeng <zeyuzeng@autox.ai>
Co-authored-by: default avatarzeyu-hello <zeyuzeng@hotmail.com>
Co-authored-by: default avatarmaskjp <maskjp@163.com>
Co-authored-by: default avatarpeng <maskjp@tamu.edu>
Co-authored-by: default avatarYezhen Cong <52420115+THU17cyz@users.noreply.github.com>
Co-authored-by: default avatarXi Liu <75658786+xiliu8006@users.noreply.github.com>
Co-authored-by: default avatarTHU17cyz <congyezhen71@hotmail.com>
Co-authored-by: default avatardingchang <hudingchang.vendor@sensetime.com>
Co-authored-by: default avatar谢恩泽 <Johnny_ez@163.com>
Co-authored-by: default avatarRobin Karlsson <34254153+robin-karlsson0@users.noreply.github.com>
parent e8fe89f5
# Copyright (c) OpenMMLab. All rights reserved.
from .indoor_eval import indoor_eval
from .instance_seg_eval import instance_seg_eval
from .kitti_utils import kitti_eval, kitti_eval_coco_style
from .lyft_eval import lyft_eval
from .seg_eval import seg_eval
__all__ = [
'kitti_eval_coco_style', 'kitti_eval', 'indoor_eval', 'lyft_eval',
'seg_eval'
'seg_eval', 'instance_seg_eval'
]
# Copyright (c) OpenMMLab. All rights reserved.
import numpy as np
from mmcv.utils import print_log
from terminaltables import AsciiTable
from .scannet_utils.evaluate_semantic_instance import scannet_eval
def aggregate_predictions(masks, labels, scores, valid_class_ids):
"""Maps predictions to ScanNet evaluator format.
Args:
masks (list[torch.Tensor]): Per scene predicted instance masks.
labels (list[torch.Tensor]): Per scene predicted instance labels.
scores (list[torch.Tensor]): Per scene predicted instance scores.
valid_class_ids (tuple[int]): Ids of valid categories.
Returns:
list[dict]: Per scene aggregated predictions.
"""
infos = []
for id, (mask, label, score) in enumerate(zip(masks, labels, scores)):
mask = mask.clone().numpy()
label = label.clone().numpy()
score = score.clone().numpy()
info = dict()
n_instances = mask.max() + 1
for i in range(n_instances):
# match pred_instance['filename'] from assign_instances_for_scan
file_name = f'{id}_{i}'
info[file_name] = dict()
info[file_name]['mask'] = (mask == i).astype(np.int)
info[file_name]['label_id'] = valid_class_ids[label[i]]
info[file_name]['conf'] = score[i]
infos.append(info)
return infos
def rename_gt(gt_semantic_masks, gt_instance_masks, valid_class_ids):
"""Maps gt instance and semantic masks to instance masks for ScanNet
evaluator.
Args:
gt_semantic_masks (list[torch.Tensor]): Per scene gt semantic masks.
gt_instance_masks (list[torch.Tensor]): Per scene gt instance masks.
valid_class_ids (tuple[int]): Ids of valid categories.
Returns:
list[np.array]: Per scene instance masks.
"""
renamed_instance_masks = []
for semantic_mask, instance_mask in zip(gt_semantic_masks,
gt_instance_masks):
semantic_mask = semantic_mask.clone().numpy()
instance_mask = instance_mask.clone().numpy()
unique = np.unique(instance_mask)
assert len(unique) < 1000
for i in unique:
semantic_instance = semantic_mask[instance_mask == i]
semantic_unique = np.unique(semantic_instance)
assert len(semantic_unique) == 1
if semantic_unique[0] < len(valid_class_ids):
instance_mask[
instance_mask ==
i] = 1000 * valid_class_ids[semantic_unique[0]] + i
renamed_instance_masks.append(instance_mask)
return renamed_instance_masks
def instance_seg_eval(gt_semantic_masks,
gt_instance_masks,
pred_instance_masks,
pred_instance_labels,
pred_instance_scores,
valid_class_ids,
class_labels,
options=None,
logger=None):
"""Instance Segmentation Evaluation.
Evaluate the result of the instance segmentation.
Args:
gt_semantic_masks (list[torch.Tensor]): Ground truth semantic masks.
gt_instance_masks (list[torch.Tensor]): Ground truth instance masks.
pred_instance_masks (list[torch.Tensor]): Predicted instance masks.
pred_instance_labels (list[torch.Tensor]): Predicted instance labels.
pred_instance_scores (list[torch.Tensor]): Predicted instance labels.
valid_class_ids (tuple[int]): Ids of valid categories.
class_labels (tuple[str]): Names of valid categories.
options (dict, optional): Additional options. Keys may contain:
`overlaps`, `min_region_sizes`, `distance_threshes`,
`distance_confs`. Default: None.
logger (logging.Logger | str, optional): The way to print the mAP
summary. See `mmdet.utils.print_log()` for details. Default: None.
Returns:
dict[str, float]: Dict of results.
"""
assert len(valid_class_ids) == len(class_labels)
id_to_label = {
valid_class_ids[i]: class_labels[i]
for i in range(len(valid_class_ids))
}
preds = aggregate_predictions(
masks=pred_instance_masks,
labels=pred_instance_labels,
scores=pred_instance_scores,
valid_class_ids=valid_class_ids)
gts = rename_gt(gt_semantic_masks, gt_instance_masks, valid_class_ids)
metrics = scannet_eval(
preds=preds,
gts=gts,
options=options,
valid_class_ids=valid_class_ids,
class_labels=class_labels,
id_to_label=id_to_label)
header = ['classes', 'AP_0.25', 'AP_0.50', 'AP']
rows = []
for label, data in metrics['classes'].items():
aps = [data['ap25%'], data['ap50%'], data['ap']]
rows.append([label] + [f'{ap:.4f}' for ap in aps])
aps = metrics['all_ap_25%'], metrics['all_ap_50%'], metrics['all_ap']
footer = ['Overall'] + [f'{ap:.4f}' for ap in aps]
table = AsciiTable([header] + rows + [footer])
table.inner_footing_row_border = True
print_log('\n' + table.table, logger=logger)
return metrics
# Copyright (c) OpenMMLab. All rights reserved.
# adapted from https://github.com/ScanNet/ScanNet/blob/master/BenchmarkScripts/3d_evaluation/evaluate_semantic_instance.py # noqa
from copy import deepcopy
import numpy as np
from . import util_3d
def evaluate_matches(matches, class_labels, options):
"""Evaluate instance segmentation from matched gt and predicted instances
for all scenes.
Args:
matches (dict): Contains gt2pred and pred2gt infos for every scene.
class_labels (tuple[str]): Class names.
options (dict): ScanNet evaluator options. See get_options.
Returns:
np.array: Average precision scores for all thresholds and categories.
"""
overlaps = options['overlaps']
min_region_sizes = [options['min_region_sizes'][0]]
dist_threshes = [options['distance_threshes'][0]]
dist_confs = [options['distance_confs'][0]]
# results: class x overlap
ap = np.zeros((len(dist_threshes), len(class_labels), len(overlaps)),
np.float)
for di, (min_region_size, distance_thresh, distance_conf) in enumerate(
zip(min_region_sizes, dist_threshes, dist_confs)):
for oi, overlap_th in enumerate(overlaps):
pred_visited = {}
for m in matches:
for label_name in class_labels:
for p in matches[m]['pred'][label_name]:
if 'filename' in p:
pred_visited[p['filename']] = False
for li, label_name in enumerate(class_labels):
y_true = np.empty(0)
y_score = np.empty(0)
hard_false_negatives = 0
has_gt = False
has_pred = False
for m in matches:
pred_instances = matches[m]['pred'][label_name]
gt_instances = matches[m]['gt'][label_name]
# filter groups in ground truth
gt_instances = [
gt for gt in gt_instances
if gt['instance_id'] >= 1000 and gt['vert_count'] >=
min_region_size and gt['med_dist'] <= distance_thresh
and gt['dist_conf'] >= distance_conf
]
if gt_instances:
has_gt = True
if pred_instances:
has_pred = True
cur_true = np.ones(len(gt_instances))
cur_score = np.ones(len(gt_instances)) * (-float('inf'))
cur_match = np.zeros(len(gt_instances), dtype=np.bool)
# collect matches
for (gti, gt) in enumerate(gt_instances):
found_match = False
for pred in gt['matched_pred']:
# greedy assignments
if pred_visited[pred['filename']]:
continue
overlap = float(pred['intersection']) / (
gt['vert_count'] + pred['vert_count'] -
pred['intersection'])
if overlap > overlap_th:
confidence = pred['confidence']
# if already have a prediction for this gt,
# the prediction with the lower score is automatically a false positive # noqa
if cur_match[gti]:
max_score = max(cur_score[gti], confidence)
min_score = min(cur_score[gti], confidence)
cur_score[gti] = max_score
# append false positive
cur_true = np.append(cur_true, 0)
cur_score = np.append(cur_score, min_score)
cur_match = np.append(cur_match, True)
# otherwise set score
else:
found_match = True
cur_match[gti] = True
cur_score[gti] = confidence
pred_visited[pred['filename']] = True
if not found_match:
hard_false_negatives += 1
# remove non-matched ground truth instances
cur_true = cur_true[cur_match]
cur_score = cur_score[cur_match]
# collect non-matched predictions as false positive
for pred in pred_instances:
found_gt = False
for gt in pred['matched_gt']:
overlap = float(gt['intersection']) / (
gt['vert_count'] + pred['vert_count'] -
gt['intersection'])
if overlap > overlap_th:
found_gt = True
break
if not found_gt:
num_ignore = pred['void_intersection']
for gt in pred['matched_gt']:
# group?
if gt['instance_id'] < 1000:
num_ignore += gt['intersection']
# small ground truth instances
if gt['vert_count'] < min_region_size or gt[
'med_dist'] > distance_thresh or gt[
'dist_conf'] < distance_conf:
num_ignore += gt['intersection']
proportion_ignore = float(
num_ignore) / pred['vert_count']
# if not ignored append false positive
if proportion_ignore <= overlap_th:
cur_true = np.append(cur_true, 0)
confidence = pred['confidence']
cur_score = np.append(cur_score, confidence)
# append to overall results
y_true = np.append(y_true, cur_true)
y_score = np.append(y_score, cur_score)
# compute average precision
if has_gt and has_pred:
# compute precision recall curve first
# sorting and cumsum
score_arg_sort = np.argsort(y_score)
y_score_sorted = y_score[score_arg_sort]
y_true_sorted = y_true[score_arg_sort]
y_true_sorted_cumsum = np.cumsum(y_true_sorted)
# unique thresholds
(thresholds, unique_indices) = np.unique(
y_score_sorted, return_index=True)
num_prec_recall = len(unique_indices) + 1
# prepare precision recall
num_examples = len(y_score_sorted)
# follow https://github.com/ScanNet/ScanNet/pull/26 ? # noqa
num_true_examples = y_true_sorted_cumsum[-1] if len(
y_true_sorted_cumsum) > 0 else 0
precision = np.zeros(num_prec_recall)
recall = np.zeros(num_prec_recall)
# deal with the first point
y_true_sorted_cumsum = np.append(y_true_sorted_cumsum, 0)
# deal with remaining
for idx_res, idx_scores in enumerate(unique_indices):
cumsum = y_true_sorted_cumsum[idx_scores - 1]
tp = num_true_examples - cumsum
fp = num_examples - idx_scores - tp
fn = cumsum + hard_false_negatives
p = float(tp) / (tp + fp)
r = float(tp) / (tp + fn)
precision[idx_res] = p
recall[idx_res] = r
# first point in curve is artificial
precision[-1] = 1.
recall[-1] = 0.
# compute average of precision-recall curve
recall_for_conv = np.copy(recall)
recall_for_conv = np.append(recall_for_conv[0],
recall_for_conv)
recall_for_conv = np.append(recall_for_conv, 0.)
stepWidths = np.convolve(recall_for_conv, [-0.5, 0, 0.5],
'valid')
# integrate is now simply a dot product
ap_current = np.dot(precision, stepWidths)
elif has_gt:
ap_current = 0.0
else:
ap_current = float('nan')
ap[di, li, oi] = ap_current
return ap
def compute_averages(aps, options, class_labels):
"""Averages AP scores for all categories.
Args:
aps (np.array): AP scores for all thresholds and categories.
options (dict): ScanNet evaluator options. See get_options.
class_labels (tuple[str]): Class names.
Returns:
dict: Overall and per-category AP scores.
"""
d_inf = 0
o50 = np.where(np.isclose(options['overlaps'], 0.5))
o25 = np.where(np.isclose(options['overlaps'], 0.25))
o_all_but25 = np.where(
np.logical_not(np.isclose(options['overlaps'], 0.25)))
avg_dict = {}
avg_dict['all_ap'] = np.nanmean(aps[d_inf, :, o_all_but25])
avg_dict['all_ap_50%'] = np.nanmean(aps[d_inf, :, o50])
avg_dict['all_ap_25%'] = np.nanmean(aps[d_inf, :, o25])
avg_dict['classes'] = {}
for (li, label_name) in enumerate(class_labels):
avg_dict['classes'][label_name] = {}
avg_dict['classes'][label_name]['ap'] = np.average(aps[d_inf, li,
o_all_but25])
avg_dict['classes'][label_name]['ap50%'] = np.average(aps[d_inf, li,
o50])
avg_dict['classes'][label_name]['ap25%'] = np.average(aps[d_inf, li,
o25])
return avg_dict
def assign_instances_for_scan(pred_info, gt_ids, options, valid_class_ids,
class_labels, id_to_label):
"""Assign gt and predicted instances for a single scene.
Args:
pred_info (dict): Predicted masks, labels and scores.
gt_ids (np.array): Ground truth instance masks.
options (dict): ScanNet evaluator options. See get_options.
valid_class_ids (tuple[int]): Ids of valid categories.
class_labels (tuple[str]): Class names.
id_to_label (dict[int, str]): Mapping of valid class id to class label.
Returns:
dict: Per class assigned gt to predicted instances.
dict: Per class assigned predicted to gt instances.
"""
# get gt instances
gt_instances = util_3d.get_instances(gt_ids, valid_class_ids, class_labels,
id_to_label)
# associate
gt2pred = deepcopy(gt_instances)
for label in gt2pred:
for gt in gt2pred[label]:
gt['matched_pred'] = []
pred2gt = {}
for label in class_labels:
pred2gt[label] = []
num_pred_instances = 0
# mask of void labels in the ground truth
bool_void = np.logical_not(np.in1d(gt_ids // 1000, valid_class_ids))
# go through all prediction masks
for pred_mask_file in pred_info:
label_id = int(pred_info[pred_mask_file]['label_id'])
conf = pred_info[pred_mask_file]['conf']
if not label_id in id_to_label: # noqa E713
continue
label_name = id_to_label[label_id]
# read the mask
pred_mask = pred_info[pred_mask_file]['mask']
if len(pred_mask) != len(gt_ids):
raise ValueError('len(pred_mask) != len(gt_ids)')
# convert to binary
pred_mask = np.not_equal(pred_mask, 0)
num = np.count_nonzero(pred_mask)
if num < options['min_region_sizes'][0]:
continue # skip if empty
pred_instance = {}
pred_instance['filename'] = pred_mask_file
pred_instance['pred_id'] = num_pred_instances
pred_instance['label_id'] = label_id
pred_instance['vert_count'] = num
pred_instance['confidence'] = conf
pred_instance['void_intersection'] = np.count_nonzero(
np.logical_and(bool_void, pred_mask))
# matched gt instances
matched_gt = []
# go through all gt instances with matching label
for (gt_num, gt_inst) in enumerate(gt2pred[label_name]):
intersection = np.count_nonzero(
np.logical_and(gt_ids == gt_inst['instance_id'], pred_mask))
if intersection > 0:
gt_copy = gt_inst.copy()
pred_copy = pred_instance.copy()
gt_copy['intersection'] = intersection
pred_copy['intersection'] = intersection
matched_gt.append(gt_copy)
gt2pred[label_name][gt_num]['matched_pred'].append(pred_copy)
pred_instance['matched_gt'] = matched_gt
num_pred_instances += 1
pred2gt[label_name].append(pred_instance)
return gt2pred, pred2gt
def scannet_eval(preds, gts, options, valid_class_ids, class_labels,
id_to_label):
"""Evaluate instance segmentation in ScanNet protocol.
Args:
preds (list[dict]): Per scene predictions of mask, label and
confidence.
gts (list[np.array]): Per scene ground truth instance masks.
options (dict): ScanNet evaluator options. See get_options.
valid_class_ids (tuple[int]): Ids of valid categories.
class_labels (tuple[str]): Class names.
id_to_label (dict[int, str]): Mapping of valid class id to class label.
Returns:
dict: Overall and per-category AP scores.
"""
options = get_options(options)
matches = {}
for i, (pred, gt) in enumerate(zip(preds, gts)):
matches_key = i
# assign gt to predictions
gt2pred, pred2gt = assign_instances_for_scan(pred, gt, options,
valid_class_ids,
class_labels, id_to_label)
matches[matches_key] = {}
matches[matches_key]['gt'] = gt2pred
matches[matches_key]['pred'] = pred2gt
ap_scores = evaluate_matches(matches, class_labels, options)
avgs = compute_averages(ap_scores, options, class_labels)
return avgs
def get_options(options=None):
"""Set ScanNet evaluator options.
Args:
options (dict, optional): Not default options. Default: None.
Returns:
dict: Updated options with all 4 keys.
"""
assert options is None or isinstance(options, dict)
_options = dict(
overlaps=np.append(np.arange(0.5, 0.95, 0.05), 0.25),
min_region_sizes=np.array([100]),
distance_threshes=np.array([float('inf')]),
distance_confs=np.array([-float('inf')]))
if options is not None:
_options.update(options)
return _options
# Copyright (c) OpenMMLab. All rights reserved.
# adapted from https://github.com/ScanNet/ScanNet/blob/master/BenchmarkScripts/util_3d.py # noqa
import json
import numpy as np
class Instance:
"""Single instance for ScanNet evaluator.
Args:
mesh_vert_instances (np.array): Instance ids for each point.
instance_id: Id of single instance.
"""
instance_id = 0
label_id = 0
vert_count = 0
med_dist = -1
dist_conf = 0.0
def __init__(self, mesh_vert_instances, instance_id):
if instance_id == -1:
return
self.instance_id = int(instance_id)
self.label_id = int(self.get_label_id(instance_id))
self.vert_count = int(
self.get_instance_verts(mesh_vert_instances, instance_id))
@staticmethod
def get_label_id(instance_id):
return int(instance_id // 1000)
@staticmethod
def get_instance_verts(mesh_vert_instances, instance_id):
return (mesh_vert_instances == instance_id).sum()
def to_json(self):
return json.dumps(
self, default=lambda o: o.__dict__, sort_keys=True, indent=4)
def to_dict(self):
dict = {}
dict['instance_id'] = self.instance_id
dict['label_id'] = self.label_id
dict['vert_count'] = self.vert_count
dict['med_dist'] = self.med_dist
dict['dist_conf'] = self.dist_conf
return dict
def from_json(self, data):
self.instance_id = int(data['instance_id'])
self.label_id = int(data['label_id'])
self.vert_count = int(data['vert_count'])
if 'med_dist' in data:
self.med_dist = float(data['med_dist'])
self.dist_conf = float(data['dist_conf'])
def __str__(self):
return '(' + str(self.instance_id) + ')'
def get_instances(ids, class_ids, class_labels, id2label):
"""Transform gt instance mask to Instance objects.
Args:
ids (np.array): Instance ids for each point.
class_ids: (tuple[int]): Ids of valid categories.
class_labels (tuple[str]): Class names.
id2label: (dict[int, str]): Mapping of valid class id to class label.
Returns:
dict [str, list]: Instance objects grouped by class label.
"""
instances = {}
for label in class_labels:
instances[label] = []
instance_ids = np.unique(ids)
for id in instance_ids:
if id == 0:
continue
inst = Instance(ids, id)
if inst.label_id in class_ids:
instances[id2label[inst.label_id]].append(inst.to_dict())
return instances
......@@ -21,7 +21,8 @@ from .pipelines import (AffineResize, BackgroundPointsFilter, GlobalAlignment,
VoxelBasedPointSampler)
# yapf: enable
from .s3dis_dataset import S3DISDataset, S3DISSegDataset
from .scannet_dataset import ScanNetDataset, ScanNetSegDataset
from .scannet_dataset import (ScanNetDataset, ScanNetInstanceSegDataset,
ScanNetSegDataset)
from .semantickitti_dataset import SemanticKITTIDataset
from .sunrgbd_dataset import SUNRGBDDataset
from .utils import get_loading_pipeline
......@@ -35,10 +36,10 @@ __all__ = [
'LoadPointsFromFile', 'S3DISSegDataset', 'S3DISDataset',
'NormalizePointsColor', 'IndoorPatchPointSample', 'IndoorPointSample',
'PointSample', 'LoadAnnotations3D', 'GlobalAlignment', 'SUNRGBDDataset',
'ScanNetDataset', 'ScanNetSegDataset', 'SemanticKITTIDataset',
'Custom3DDataset', 'Custom3DSegDataset', 'LoadPointsFromMultiSweeps',
'WaymoDataset', 'BackgroundPointsFilter', 'VoxelBasedPointSampler',
'get_loading_pipeline', 'RandomDropPointsColor', 'RandomJitterPoints',
'ObjectNameFilter', 'AffineResize', 'RandomShiftScale',
'LoadPointsFromDict'
'ScanNetDataset', 'ScanNetSegDataset', 'ScanNetInstanceSegDataset',
'SemanticKITTIDataset', 'Custom3DDataset', 'Custom3DSegDataset',
'LoadPointsFromMultiSweeps', 'WaymoDataset', 'BackgroundPointsFilter',
'VoxelBasedPointSampler', 'get_loading_pipeline', 'RandomDropPointsColor',
'RandomJitterPoints', 'ObjectNameFilter', 'AffineResize',
'RandomShiftScale', 'LoadPointsFromDict'
]
......@@ -5,7 +5,7 @@ from os import path as osp
import numpy as np
from mmdet3d.core import show_result, show_seg_result
from mmdet3d.core import instance_seg_eval, show_result, show_seg_result
from mmdet3d.core.bbox import DepthInstance3DBoxes
from mmdet.datasets import DATASETS
from mmseg.datasets import DATASETS as SEG_DATASETS
......@@ -460,3 +460,151 @@ class ScanNetSegDataset(Custom3DSegDataset):
outputs.append(dict(seg_mask=pred_label))
return outputs, tmp_dir
@DATASETS.register_module()
@SEG_DATASETS.register_module()
class ScanNetInstanceSegDataset(Custom3DSegDataset):
CLASSES = ('cabinet', 'bed', 'chair', 'sofa', 'table', 'door', 'window',
'bookshelf', 'picture', 'counter', 'desk', 'curtain',
'refrigerator', 'showercurtrain', 'toilet', 'sink', 'bathtub',
'garbagebin')
VALID_CLASS_IDS = (3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 24, 28, 33, 34,
36, 39)
ALL_CLASS_IDS = tuple(range(41))
def get_ann_info(self, index):
"""Get annotation info according to the given index.
Args:
index (int): Index of the annotation data to get.
Returns:
dict: annotation information consists of the following keys:
- pts_semantic_mask_path (str): Path of semantic masks.
- pts_instance_mask_path (str): Path of instance masks.
"""
# Use index to get the annos, thus the evalhook could also use this api
info = self.data_infos[index]
pts_instance_mask_path = osp.join(self.data_root,
info['pts_instance_mask_path'])
pts_semantic_mask_path = osp.join(self.data_root,
info['pts_semantic_mask_path'])
anns_results = dict(
pts_instance_mask_path=pts_instance_mask_path,
pts_semantic_mask_path=pts_semantic_mask_path)
return anns_results
def get_classes_and_palette(self, classes=None, palette=None):
"""Get class names of current dataset. Palette is simply ignored for
instance segmentation.
Args:
classes (Sequence[str] | str | None): If classes is None, use
default CLASSES defined by builtin dataset. If classes is a
string, take it as a file name. The file contains the name of
classes where each line contains one class name. If classes is
a tuple or list, override the CLASSES defined by the dataset.
Defaults to None.
palette (Sequence[Sequence[int]]] | np.ndarray | None):
The palette of segmentation map. If None is given, random
palette will be generated. Defaults to None.
"""
if classes is not None:
return classes, None
return self.CLASSES, None
def _build_default_pipeline(self):
"""Build the default pipeline for this dataset."""
pipeline = [
dict(
type='LoadPointsFromFile',
coord_type='DEPTH',
shift_height=False,
use_color=True,
load_dim=6,
use_dim=[0, 1, 2, 3, 4, 5]),
dict(
type='LoadAnnotations3D',
with_bbox_3d=False,
with_label_3d=False,
with_mask_3d=True,
with_seg_3d=True),
dict(
type='PointSegClassMapping',
valid_cat_ids=self.VALID_CLASS_IDS,
max_cat_id=40),
dict(
type='DefaultFormatBundle3D',
with_label=False,
class_names=self.CLASSES),
dict(
type='Collect3D',
keys=['points', 'pts_semantic_mask', 'pts_instance_mask'])
]
return Compose(pipeline)
def evaluate(self,
results,
metric=None,
options=None,
logger=None,
show=False,
out_dir=None,
pipeline=None):
"""Evaluation in instance segmentation protocol.
Args:
results (list[dict]): List of results.
metric (str | list[str]): Metrics to be evaluated.
options (dict, optional): options for instance_seg_eval.
logger (logging.Logger | None | str): Logger used for printing
related information during evaluation. Defaults to None.
show (bool, optional): Whether to visualize.
Defaults to False.
out_dir (str, optional): Path to save the visualization results.
Defaults to None.
pipeline (list[dict], optional): raw data loading for showing.
Default: None.
Returns:
dict: Evaluation results.
"""
assert isinstance(
results, list), f'Expect results to be list, got {type(results)}.'
assert len(results) > 0, 'Expect length of results > 0.'
assert len(results) == len(self.data_infos)
assert isinstance(
results[0], dict
), f'Expect elements in results to be dict, got {type(results[0])}.'
load_pipeline = self._get_pipeline(pipeline)
pred_instance_masks = [result['instance_mask'] for result in results]
pred_instance_labels = [result['instance_label'] for result in results]
pred_instance_scores = [result['instance_score'] for result in results]
gt_semantic_masks, gt_instance_masks = zip(*[
self._extract_data(
index=i,
pipeline=load_pipeline,
key=['pts_semantic_mask', 'pts_instance_mask'],
load_annos=True) for i in range(len(self.data_infos))
])
ret_dict = instance_seg_eval(
gt_semantic_masks,
gt_instance_masks,
pred_instance_masks,
pred_instance_labels,
pred_instance_scores,
valid_class_ids=self.VALID_CLASS_IDS,
class_labels=self.CLASSES,
options=options,
logger=logger)
if show:
raise NotImplementedError('show is not implemented for now')
return ret_dict
......@@ -5,7 +5,8 @@ import numpy as np
import pytest
import torch
from mmdet3d.datasets import ScanNetDataset, ScanNetSegDataset
from mmdet3d.datasets import (ScanNetDataset, ScanNetInstanceSegDataset,
ScanNetSegDataset)
def test_getitem():
......@@ -685,3 +686,152 @@ def test_seg_format_results():
expected_txt_path = osp.join(tmp_dir.name, 'results', 'scene0000_00.txt')
assert np.all(result_files[0]['seg_mask'] == expected_label)
mmcv.check_file_exist(expected_txt_path)
def test_instance_seg_getitem():
np.random.seed(0)
root_path = './tests/data/scannet/'
ann_file = './tests/data/scannet/scannet_infos.pkl'
class_names = ('cabinet', 'bed', 'chair', 'sofa', 'table', 'door',
'window', 'bookshelf', 'picture', 'counter', 'desk',
'curtain', 'refrigerator', 'showercurtrain', 'toilet',
'sink', 'bathtub', 'garbagebin')
train_pipeline = [
dict(
type='LoadPointsFromFile',
coord_type='DEPTH',
shift_height=False,
use_color=True,
load_dim=6,
use_dim=[0, 1, 2, 3, 4, 5]),
dict(
type='LoadAnnotations3D',
with_bbox_3d=False,
with_label_3d=False,
with_mask_3d=True,
with_seg_3d=True),
dict(
type='PointSegClassMapping',
valid_cat_ids=(3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 24, 28, 33,
34, 36, 39),
max_cat_id=40),
dict(type='NormalizePointsColor', color_mean=None),
dict(type='DefaultFormatBundle3D', class_names=class_names),
dict(
type='Collect3D',
keys=['points', 'pts_semantic_mask', 'pts_instance_mask'])
]
scannet_dataset = ScanNetInstanceSegDataset(
data_root=root_path,
ann_file=ann_file,
pipeline=train_pipeline,
classes=class_names,
test_mode=False)
expected_points = torch.tensor([[
-3.4742e+00, 7.8792e-01, 1.7397e+00, 3.3725e-01, 3.5294e-01, 3.0588e-01
], [
2.7216e+00, 3.4164e+00, 2.4572e+00, 6.6275e-01, 6.2745e-01, 5.1373e-01
],
[
1.3404e+00, -1.4675e+00, -4.4059e-02,
3.8431e-01, 3.6078e-01, 3.5686e-01
],
[
-3.0335e+00, 2.7273e+00, 1.5181e+00,
2.3137e-01, 1.6078e-01, 8.2353e-02
],
[
-4.3207e-01, 1.8154e+00, 1.7455e-01,
4.0392e-01, 3.8039e-01, 4.1961e-01
]])
expected_semantic_mask = torch.tensor([11, 18, 18, 0, 4]).long()
expected_instance_mask = torch.tensor([6, 56, 10, 9, 35]).long()
data = scannet_dataset[0]
assert torch.allclose(data['points']._data[:5], expected_points, 1e-2)
assert torch.allclose(data['pts_semantic_mask']._data[:5],
expected_semantic_mask)
assert torch.allclose(data['pts_instance_mask']._data[:5],
expected_instance_mask)
def test_instance_seg_evaluate():
root_path = './tests/data/scannet'
ann_file = './tests/data/scannet/scannet_infos.pkl'
class_names = ('cabinet', 'bed', 'chair', 'sofa', 'table', 'door',
'window', 'bookshelf', 'picture', 'counter', 'desk',
'curtain', 'refrigerator', 'showercurtrain', 'toilet',
'sink', 'bathtub', 'garbagebin')
test_pipeline = [
dict(
type='LoadPointsFromFile',
coord_type='DEPTH',
shift_height=False,
use_color=True,
load_dim=6,
use_dim=[0, 1, 2, 3, 4, 5]),
dict(type='NormalizePointsColor', color_mean=None),
dict(type='DefaultFormatBundle3D', class_names=class_names),
dict(type='Collect3D', keys=['points'])
]
scannet_dataset = ScanNetInstanceSegDataset(
data_root=root_path,
ann_file=ann_file,
pipeline=test_pipeline,
test_mode=True)
pred_mask = torch.tensor([
1, -1, -1, -1, 7, 11, 2, -1, 1, 10, -1, -1, 5, -1, -1, -1, -1, 1, -1,
-1, -1, -1, 0, -1, 1, -1, 12, -1, -1, -1, 8, 5, 1, 5, 2, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 8, -1, -1, -1,
0, 4, 3, -1, 9, -1, -1, 6, -1, -1, -1, -1, 13, -1, -1, 5, -1, 5, -1,
-1, 9, 0, 5, -1, -1, 2, 3, 4, -1, -1, -1, 2, -1, -1, -1, 5, 9, -1, 1,
-1, 4, 10, 4, -1
]).long()
pred_labels = torch.tensor(
[4, 11, 11, 10, 0, 3, 12, 4, 14, 1, 0, 0, 0, 5, 5]).long()
pred_scores = torch.tensor([.99 for _ in range(len(pred_labels))])
results = [
dict(
instance_mask=pred_mask,
instance_label=pred_labels,
instance_score=torch.tensor(pred_scores))
]
eval_pipeline = [
dict(
type='LoadPointsFromFile',
coord_type='DEPTH',
shift_height=False,
use_color=True,
load_dim=6,
use_dim=[0, 1, 2, 3, 4, 5]),
dict(
type='LoadAnnotations3D',
with_bbox_3d=False,
with_label_3d=False,
with_mask_3d=True,
with_seg_3d=True),
dict(
type='PointSegClassMapping',
valid_cat_ids=(3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 24, 28, 33,
34, 36, 39),
max_cat_id=40),
dict(type='NormalizePointsColor', color_mean=None),
dict(type='DefaultFormatBundle3D', class_names=class_names),
dict(
type='Collect3D',
keys=['points', 'pts_semantic_mask', 'pts_instance_mask'])
]
# We add options here as default min_region_size
# is much bigger than test instances.
ret_dict = scannet_dataset.evaluate(
results,
pipeline=eval_pipeline,
options=dict(min_region_sizes=np.array([1])))
assert abs(ret_dict['all_ap'] - 0.90625) < 0.001
assert abs(ret_dict['all_ap_50%'] - 0.90625) < 0.001
assert abs(ret_dict['all_ap_25%'] - 0.94444) < 0.001
assert abs(ret_dict['classes']['cabinet']['ap25%'] - 1.0) < 0.001
assert abs(ret_dict['classes']['cabinet']['ap50%'] - 0.65625) < 0.001
assert abs(ret_dict['classes']['door']['ap25%'] - 0.5) < 0.001
assert abs(ret_dict['classes']['door']['ap50%'] - 0.5) < 0.001
# Copyright (c) OpenMMLab. All rights reserved.
import numpy as np
import torch
from mmdet3d.core import instance_seg_eval
def test_instance_seg_eval():
valid_class_ids = (3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 24, 28, 33, 34,
36, 39)
class_labels = ('cabinet', 'bed', 'chair', 'sofa', 'table', 'door',
'window', 'bookshelf', 'picture', 'counter', 'desk',
'curtain', 'refrigerator', 'showercurtrain', 'toilet',
'sink', 'bathtub', 'garbagebin')
n_points_list = [3300, 3000]
gt_labels_list = [[0, 0, 0, 0, 0, 0, 14, 14, 2, 1],
[13, 13, 2, 1, 3, 3, 0, 0, 0]]
gt_instance_masks = []
gt_semantic_masks = []
pred_instance_masks = []
pred_instance_labels = []
pred_instance_scores = []
for n_points, gt_labels in zip(n_points_list, gt_labels_list):
gt_instance_mask = np.ones(n_points, dtype=np.int) * -1
gt_semantic_mask = np.ones(n_points, dtype=np.int) * -1
pred_instance_mask = np.ones(n_points, dtype=np.int) * -1
labels = []
scores = []
for i, gt_label in enumerate(gt_labels):
begin = i * 300
end = begin + 300
gt_instance_mask[begin:end] = i
gt_semantic_mask[begin:end] = gt_label
pred_instance_mask[begin:end] = i
labels.append(gt_label)
scores.append(.99)
gt_instance_masks.append(torch.tensor(gt_instance_mask))
gt_semantic_masks.append(torch.tensor(gt_semantic_mask))
pred_instance_masks.append(torch.tensor(pred_instance_mask))
pred_instance_labels.append(torch.tensor(labels))
pred_instance_scores.append(torch.tensor(scores))
ret_value = instance_seg_eval(
gt_semantic_masks=gt_semantic_masks,
gt_instance_masks=gt_instance_masks,
pred_instance_masks=pred_instance_masks,
pred_instance_labels=pred_instance_labels,
pred_instance_scores=pred_instance_scores,
valid_class_ids=valid_class_ids,
class_labels=class_labels)
for label in [
'cabinet', 'bed', 'chair', 'sofa', 'showercurtrain', 'toilet'
]:
metrics = ret_value['classes'][label]
assert metrics['ap'] == 1.0
assert metrics['ap50%'] == 1.0
assert metrics['ap25%'] == 1.0
pred_instance_masks[1][2240:2700] = -1
pred_instance_masks[0][2700:3000] = 8
pred_instance_labels[0][9] = 2
ret_value = instance_seg_eval(
gt_semantic_masks=gt_semantic_masks,
gt_instance_masks=gt_instance_masks,
pred_instance_masks=pred_instance_masks,
pred_instance_labels=pred_instance_labels,
pred_instance_scores=pred_instance_scores,
valid_class_ids=valid_class_ids,
class_labels=class_labels)
assert abs(ret_value['classes']['cabinet']['ap50%'] - 0.72916) < 0.01
assert abs(ret_value['classes']['cabinet']['ap25%'] - 0.88888) < 0.01
assert abs(ret_value['classes']['bed']['ap50%'] - 0.5) < 0.01
assert abs(ret_value['classes']['bed']['ap25%'] - 0.5) < 0.01
assert abs(ret_value['classes']['chair']['ap50%'] - 0.375) < 0.01
assert abs(ret_value['classes']['chair']['ap25%'] - 1.0) < 0.01
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment