mblt-vision-python 0.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mblt_vision/__init__.py +86 -0
- mblt_vision/_api.py +53 -0
- mblt_vision/_compat.py +227 -0
- mblt_vision/_model_paths.py +137 -0
- mblt_vision/_tasks.py +30 -0
- mblt_vision/benchmark/__init__.py +1 -0
- mblt_vision/benchmark/argparse_utils.py +106 -0
- mblt_vision/benchmark/chart_utils.py +146 -0
- mblt_vision/benchmark/io_utils.py +64 -0
- mblt_vision/benchmark/summary_utils.py +770 -0
- mblt_vision/cli/__init__.py +5 -0
- mblt_vision/cli/__main__.py +5 -0
- mblt_vision/cli/_vision.py +337 -0
- mblt_vision/cli/compile.py +117 -0
- mblt_vision/cli/main.py +35 -0
- mblt_vision/cli/predict.py +64 -0
- mblt_vision/cli/val.py +562 -0
- mblt_vision/compile/__init__.py +21 -0
- mblt_vision/compile/vision.py +1120 -0
- mblt_vision/datasets/__init__.py +15 -0
- mblt_vision/datasets/ade20k.yaml +164 -0
- mblt_vision/datasets/cityscapes.yaml +54 -0
- mblt_vision/datasets/coco.yaml +178 -0
- mblt_vision/datasets/dotav1.yaml +28 -0
- mblt_vision/datasets/imagenet.yaml +1019 -0
- mblt_vision/datasets/imagenet_synsets.txt +1000 -0
- mblt_vision/datasets/nyu-depth.yaml +7 -0
- mblt_vision/datasets/registry.py +158 -0
- mblt_vision/datasets/widerface.yaml +9 -0
- mblt_vision/depth_estimation/__init__.py +19 -0
- mblt_vision/face_detection/__init__.py +43 -0
- mblt_vision/image_classification/__init__.py +311 -0
- mblt_vision/instance_segmentation/__init__.py +65 -0
- mblt_vision/models/AlexNet.yaml +23 -0
- mblt_vision/models/CAFormer_B36.yaml +22 -0
- mblt_vision/models/CAFormer_M36.yaml +22 -0
- mblt_vision/models/CAFormer_S18.yaml +22 -0
- mblt_vision/models/CAFormer_S36.yaml +22 -0
- mblt_vision/models/CoAtNet_0_RW_224.yaml +22 -0
- mblt_vision/models/CoAtNet_1_RW_224.yaml +22 -0
- mblt_vision/models/CoAtNet_2_RW_224.yaml +22 -0
- mblt_vision/models/ConvFormer_B36.yaml +22 -0
- mblt_vision/models/ConvFormer_M36.yaml +22 -0
- mblt_vision/models/ConvFormer_S18.yaml +22 -0
- mblt_vision/models/ConvFormer_S36.yaml +22 -0
- mblt_vision/models/ConvNext_Base.yaml +23 -0
- mblt_vision/models/ConvNext_Large.yaml +23 -0
- mblt_vision/models/ConvNext_Small.yaml +23 -0
- mblt_vision/models/ConvNext_Tiny.yaml +23 -0
- mblt_vision/models/DeiT3_Base_Patch16_224.yaml +22 -0
- mblt_vision/models/DeiT3_Base_Patch16_384.yaml +22 -0
- mblt_vision/models/DeiT3_Large_Patch16_224.yaml +22 -0
- mblt_vision/models/DeiT3_Large_Patch16_384.yaml +22 -0
- mblt_vision/models/DeiT3_Medium_Patch16_224.yaml +22 -0
- mblt_vision/models/DeiT3_Small_Patch16_224.yaml +22 -0
- mblt_vision/models/DeiT3_Small_Patch16_384.yaml +22 -0
- mblt_vision/models/DeiT_Base_Patch16_224.yaml +22 -0
- mblt_vision/models/DeiT_Base_Patch16_384.yaml +22 -0
- mblt_vision/models/DeiT_Small_Patch16_224.yaml +22 -0
- mblt_vision/models/DeiT_Tiny_Patch16_224.yaml +22 -0
- mblt_vision/models/DenseNet121.yaml +23 -0
- mblt_vision/models/DenseNet161.yaml +23 -0
- mblt_vision/models/DenseNet169.yaml +23 -0
- mblt_vision/models/DenseNet201.yaml +23 -0
- mblt_vision/models/EfficientFormer_L1.yaml +22 -0
- mblt_vision/models/EfficientFormer_L3.yaml +22 -0
- mblt_vision/models/EfficientFormer_L7.yaml +22 -0
- mblt_vision/models/EfficientNet_B0.yaml +23 -0
- mblt_vision/models/EfficientNet_B1.yaml +32 -0
- mblt_vision/models/EfficientNet_B2.yaml +23 -0
- mblt_vision/models/EfficientNet_B3.yaml +23 -0
- mblt_vision/models/EfficientNet_B4.yaml +23 -0
- mblt_vision/models/EfficientNet_B5.yaml +23 -0
- mblt_vision/models/EfficientNet_B6.yaml +23 -0
- mblt_vision/models/EfficientNet_B7.yaml +23 -0
- mblt_vision/models/EfficientNet_V2_L.yaml +23 -0
- mblt_vision/models/EfficientNet_V2_M.yaml +23 -0
- mblt_vision/models/EfficientNet_V2_S.yaml +23 -0
- mblt_vision/models/FlexiVit_Base.yaml +22 -0
- mblt_vision/models/FlexiVit_Large.yaml +22 -0
- mblt_vision/models/FlexiVit_Small.yaml +22 -0
- mblt_vision/models/GELANc-seg.yaml +29 -0
- mblt_vision/models/GELANc.yaml +28 -0
- mblt_vision/models/GELANe.yaml +28 -0
- mblt_vision/models/GELANm.yaml +28 -0
- mblt_vision/models/GELANs.yaml +28 -0
- mblt_vision/models/GoogLeNet.yaml +23 -0
- mblt_vision/models/Inception_V3.yaml +23 -0
- mblt_vision/models/LeViT_Conv_128.yaml +22 -0
- mblt_vision/models/LeViT_Conv_128S.yaml +22 -0
- mblt_vision/models/LeViT_Conv_192.yaml +22 -0
- mblt_vision/models/LeViT_Conv_256.yaml +22 -0
- mblt_vision/models/LeViT_Conv_384.yaml +22 -0
- mblt_vision/models/MNASNet0_5.yaml +23 -0
- mblt_vision/models/MNASNet0_75.yaml +23 -0
- mblt_vision/models/MNASNet1_0.yaml +23 -0
- mblt_vision/models/MNASNet1_3.yaml +23 -0
- mblt_vision/models/MobileNet_V2.yaml +32 -0
- mblt_vision/models/MobileNet_V3_Large.yaml +32 -0
- mblt_vision/models/MobileNet_V3_Small.yaml +23 -0
- mblt_vision/models/RegNet_X_16GF.yaml +32 -0
- mblt_vision/models/RegNet_X_1_6GF.yaml +32 -0
- mblt_vision/models/RegNet_X_32GF.yaml +32 -0
- mblt_vision/models/RegNet_X_3_2GF.yaml +32 -0
- mblt_vision/models/RegNet_X_400MF.yaml +32 -0
- mblt_vision/models/RegNet_X_800MF.yaml +32 -0
- mblt_vision/models/RegNet_X_8GF.yaml +32 -0
- mblt_vision/models/RegNet_Y_16GF.yaml +76 -0
- mblt_vision/models/RegNet_Y_1_6GF.yaml +32 -0
- mblt_vision/models/RegNet_Y_32GF.yaml +76 -0
- mblt_vision/models/RegNet_Y_3_2GF.yaml +32 -0
- mblt_vision/models/RegNet_Y_400MF.yaml +32 -0
- mblt_vision/models/RegNet_Y_800MF.yaml +32 -0
- mblt_vision/models/RegNet_Y_8GF.yaml +32 -0
- mblt_vision/models/RepViT_M0_9.yaml +22 -0
- mblt_vision/models/RepViT_M1.yaml +22 -0
- mblt_vision/models/RepViT_M1_0.yaml +22 -0
- mblt_vision/models/RepViT_M1_1.yaml +22 -0
- mblt_vision/models/RepViT_M1_5.yaml +22 -0
- mblt_vision/models/RepViT_M2.yaml +22 -0
- mblt_vision/models/RepViT_M2_3.yaml +22 -0
- mblt_vision/models/RepViT_M3.yaml +22 -0
- mblt_vision/models/ResNeXt101_32X8D.yaml +32 -0
- mblt_vision/models/ResNeXt101_64X4D.yaml +23 -0
- mblt_vision/models/ResNeXt50_32X4D.yaml +32 -0
- mblt_vision/models/ResNet101.yaml +32 -0
- mblt_vision/models/ResNet152.yaml +32 -0
- mblt_vision/models/ResNet18.yaml +23 -0
- mblt_vision/models/ResNet34.yaml +23 -0
- mblt_vision/models/ResNet50.yaml +32 -0
- mblt_vision/models/ShuffleNet_V2_X0_5.yaml +23 -0
- mblt_vision/models/ShuffleNet_V2_X1_0.yaml +23 -0
- mblt_vision/models/ShuffleNet_V2_X1_5.yaml +23 -0
- mblt_vision/models/ShuffleNet_V2_X2_0.yaml +23 -0
- mblt_vision/models/SqueezeNet1_0.yaml +23 -0
- mblt_vision/models/SqueezeNet1_1.yaml +23 -0
- mblt_vision/models/Swin_B.yaml +23 -0
- mblt_vision/models/Swin_S.yaml +23 -0
- mblt_vision/models/Swin_T.yaml +23 -0
- mblt_vision/models/VGG11.yaml +23 -0
- mblt_vision/models/VGG11_BN.yaml +23 -0
- mblt_vision/models/VGG13.yaml +23 -0
- mblt_vision/models/VGG13_BN.yaml +23 -0
- mblt_vision/models/VGG16.yaml +23 -0
- mblt_vision/models/VGG16_BN.yaml +23 -0
- mblt_vision/models/VGG19.yaml +23 -0
- mblt_vision/models/VGG19_BN.yaml +23 -0
- mblt_vision/models/ViT_B_16.yaml +67 -0
- mblt_vision/models/ViT_B_32.yaml +23 -0
- mblt_vision/models/ViT_Base_Patch16_224.yaml +22 -0
- mblt_vision/models/ViT_Base_Patch16_384.yaml +22 -0
- mblt_vision/models/ViT_Base_Patch32_224.yaml +22 -0
- mblt_vision/models/ViT_Base_Patch32_384.yaml +22 -0
- mblt_vision/models/ViT_Base_Patch8_224.yaml +22 -0
- mblt_vision/models/ViT_L_16.yaml +67 -0
- mblt_vision/models/ViT_L_32.yaml +23 -0
- mblt_vision/models/ViT_Large_Patch16_224.yaml +22 -0
- mblt_vision/models/ViT_Large_Patch16_384.yaml +22 -0
- mblt_vision/models/ViT_Large_Patch32_384.yaml +22 -0
- mblt_vision/models/ViT_Small_Patch16_224.yaml +22 -0
- mblt_vision/models/ViT_Small_Patch16_384.yaml +22 -0
- mblt_vision/models/ViT_Small_Patch32_224.yaml +22 -0
- mblt_vision/models/ViT_Small_Patch32_384.yaml +22 -0
- mblt_vision/models/ViT_Tiny_Patch16_224.yaml +22 -0
- mblt_vision/models/ViT_Tiny_Patch16_384.yaml +22 -0
- mblt_vision/models/VisFormer_Small.yaml +22 -0
- mblt_vision/models/VisFormer_Tiny.yaml +22 -0
- mblt_vision/models/Wide_ResNet101_2.yaml +32 -0
- mblt_vision/models/Wide_ResNet50_2.yaml +32 -0
- mblt_vision/models/YOLO11l-cls.yaml +23 -0
- mblt_vision/models/YOLO11l-face.yaml +27 -0
- mblt_vision/models/YOLO11l-obb.yaml +28 -0
- mblt_vision/models/YOLO11l-pose.yaml +28 -0
- mblt_vision/models/YOLO11l-seg.yaml +28 -0
- mblt_vision/models/YOLO11l.yaml +27 -0
- mblt_vision/models/YOLO11m-cls.yaml +23 -0
- mblt_vision/models/YOLO11m-face.yaml +27 -0
- mblt_vision/models/YOLO11m-obb.yaml +28 -0
- mblt_vision/models/YOLO11m-pose.yaml +28 -0
- mblt_vision/models/YOLO11m-seg.yaml +28 -0
- mblt_vision/models/YOLO11m.yaml +27 -0
- mblt_vision/models/YOLO11n-cls.yaml +23 -0
- mblt_vision/models/YOLO11n-face.yaml +27 -0
- mblt_vision/models/YOLO11n-obb.yaml +28 -0
- mblt_vision/models/YOLO11n-pose.yaml +28 -0
- mblt_vision/models/YOLO11n-seg.yaml +28 -0
- mblt_vision/models/YOLO11n.yaml +27 -0
- mblt_vision/models/YOLO11s-cls.yaml +23 -0
- mblt_vision/models/YOLO11s-face.yaml +27 -0
- mblt_vision/models/YOLO11s-obb.yaml +28 -0
- mblt_vision/models/YOLO11s-pose.yaml +28 -0
- mblt_vision/models/YOLO11s-seg.yaml +28 -0
- mblt_vision/models/YOLO11s.yaml +27 -0
- mblt_vision/models/YOLO11x-cls.yaml +23 -0
- mblt_vision/models/YOLO11x-obb.yaml +28 -0
- mblt_vision/models/YOLO11x-pose.yaml +28 -0
- mblt_vision/models/YOLO11x-seg.yaml +28 -0
- mblt_vision/models/YOLO11x.yaml +27 -0
- mblt_vision/models/YOLO12l-face.yaml +27 -0
- mblt_vision/models/YOLO12l-seg.yaml +28 -0
- mblt_vision/models/YOLO12l.yaml +27 -0
- mblt_vision/models/YOLO12m-face.yaml +27 -0
- mblt_vision/models/YOLO12m-seg.yaml +28 -0
- mblt_vision/models/YOLO12m.yaml +27 -0
- mblt_vision/models/YOLO12n-face.yaml +27 -0
- mblt_vision/models/YOLO12n-seg.yaml +28 -0
- mblt_vision/models/YOLO12n.yaml +27 -0
- mblt_vision/models/YOLO12s-face.yaml +27 -0
- mblt_vision/models/YOLO12s-seg.yaml +28 -0
- mblt_vision/models/YOLO12s.yaml +27 -0
- mblt_vision/models/YOLO12x-seg.yaml +28 -0
- mblt_vision/models/YOLO12x.yaml +27 -0
- mblt_vision/models/YOLO26l-cls.yaml +23 -0
- mblt_vision/models/YOLO26l-depth.yaml +17 -0
- mblt_vision/models/YOLO26l-distill.yaml +27 -0
- mblt_vision/models/YOLO26l-obb.yaml +28 -0
- mblt_vision/models/YOLO26l-pose.yaml +28 -0
- mblt_vision/models/YOLO26l-seg.yaml +28 -0
- mblt_vision/models/YOLO26l-sem-ade20k.yaml +17 -0
- mblt_vision/models/YOLO26l-sem.yaml +17 -0
- mblt_vision/models/YOLO26l.yaml +27 -0
- mblt_vision/models/YOLO26m-cls.yaml +23 -0
- mblt_vision/models/YOLO26m-depth.yaml +17 -0
- mblt_vision/models/YOLO26m-distill.yaml +27 -0
- mblt_vision/models/YOLO26m-obb.yaml +28 -0
- mblt_vision/models/YOLO26m-pose.yaml +28 -0
- mblt_vision/models/YOLO26m-seg.yaml +28 -0
- mblt_vision/models/YOLO26m-sem-ade20k.yaml +17 -0
- mblt_vision/models/YOLO26m-sem.yaml +17 -0
- mblt_vision/models/YOLO26m.yaml +27 -0
- mblt_vision/models/YOLO26n-cls.yaml +23 -0
- mblt_vision/models/YOLO26n-depth.yaml +17 -0
- mblt_vision/models/YOLO26n-distill.yaml +27 -0
- mblt_vision/models/YOLO26n-obb.yaml +28 -0
- mblt_vision/models/YOLO26n-pose.yaml +28 -0
- mblt_vision/models/YOLO26n-seg.yaml +28 -0
- mblt_vision/models/YOLO26n-sem-ade20k.yaml +17 -0
- mblt_vision/models/YOLO26n-sem.yaml +17 -0
- mblt_vision/models/YOLO26n.yaml +27 -0
- mblt_vision/models/YOLO26s-cls.yaml +23 -0
- mblt_vision/models/YOLO26s-depth.yaml +17 -0
- mblt_vision/models/YOLO26s-distill.yaml +27 -0
- mblt_vision/models/YOLO26s-obb.yaml +28 -0
- mblt_vision/models/YOLO26s-pose.yaml +28 -0
- mblt_vision/models/YOLO26s-seg.yaml +28 -0
- mblt_vision/models/YOLO26s-sem-ade20k.yaml +17 -0
- mblt_vision/models/YOLO26s-sem.yaml +17 -0
- mblt_vision/models/YOLO26s.yaml +27 -0
- mblt_vision/models/YOLO26x-cls.yaml +23 -0
- mblt_vision/models/YOLO26x-depth.yaml +17 -0
- mblt_vision/models/YOLO26x-distill.yaml +27 -0
- mblt_vision/models/YOLO26x-obb.yaml +28 -0
- mblt_vision/models/YOLO26x-pose.yaml +28 -0
- mblt_vision/models/YOLO26x-seg.yaml +28 -0
- mblt_vision/models/YOLO26x-sem-ade20k.yaml +17 -0
- mblt_vision/models/YOLO26x-sem.yaml +17 -0
- mblt_vision/models/YOLO26x.yaml +27 -0
- mblt_vision/models/YOLOv10b.yaml +28 -0
- mblt_vision/models/YOLOv10l-face.yaml +28 -0
- mblt_vision/models/YOLOv10l.yaml +28 -0
- mblt_vision/models/YOLOv10m-face.yaml +28 -0
- mblt_vision/models/YOLOv10m.yaml +28 -0
- mblt_vision/models/YOLOv10n-face.yaml +28 -0
- mblt_vision/models/YOLOv10n.yaml +28 -0
- mblt_vision/models/YOLOv10s-face.yaml +28 -0
- mblt_vision/models/YOLOv10s.yaml +28 -0
- mblt_vision/models/YOLOv10x.yaml +28 -0
- mblt_vision/models/YOLOv3-spp.yaml +44 -0
- mblt_vision/models/YOLOv3-sppu.yaml +27 -0
- mblt_vision/models/YOLOv3-tiny.yaml +38 -0
- mblt_vision/models/YOLOv3-tinyu.yaml +27 -0
- mblt_vision/models/YOLOv3.yaml +44 -0
- mblt_vision/models/YOLOv3u.yaml +27 -0
- mblt_vision/models/YOLOv5l-cls.yaml +22 -0
- mblt_vision/models/YOLOv5l-seg.yaml +45 -0
- mblt_vision/models/YOLOv5l.yaml +44 -0
- mblt_vision/models/YOLOv5l6.yaml +50 -0
- mblt_vision/models/YOLOv5l6u.yaml +27 -0
- mblt_vision/models/YOLOv5lu.yaml +27 -0
- mblt_vision/models/YOLOv5m-cls.yaml +22 -0
- mblt_vision/models/YOLOv5m-seg.yaml +45 -0
- mblt_vision/models/YOLOv5m.yaml +45 -0
- mblt_vision/models/YOLOv5m6.yaml +50 -0
- mblt_vision/models/YOLOv5m6u.yaml +27 -0
- mblt_vision/models/YOLOv5mu.yaml +27 -0
- mblt_vision/models/YOLOv5n-cls.yaml +22 -0
- mblt_vision/models/YOLOv5n-seg.yaml +45 -0
- mblt_vision/models/YOLOv5n.yaml +44 -0
- mblt_vision/models/YOLOv5n6.yaml +50 -0
- mblt_vision/models/YOLOv5n6u.yaml +27 -0
- mblt_vision/models/YOLOv5nu.yaml +27 -0
- mblt_vision/models/YOLOv5s-cls.yaml +22 -0
- mblt_vision/models/YOLOv5s-seg.yaml +45 -0
- mblt_vision/models/YOLOv5s.yaml +44 -0
- mblt_vision/models/YOLOv5s6.yaml +50 -0
- mblt_vision/models/YOLOv5s6u.yaml +27 -0
- mblt_vision/models/YOLOv5su.yaml +27 -0
- mblt_vision/models/YOLOv5x-cls.yaml +22 -0
- mblt_vision/models/YOLOv5x-seg.yaml +45 -0
- mblt_vision/models/YOLOv5x.yaml +44 -0
- mblt_vision/models/YOLOv5x6.yaml +50 -0
- mblt_vision/models/YOLOv5x6u.yaml +27 -0
- mblt_vision/models/YOLOv5xu.yaml +27 -0
- mblt_vision/models/YOLOv6m-face.yaml +27 -0
- mblt_vision/models/YOLOv6n-face.yaml +27 -0
- mblt_vision/models/YOLOv7.yaml +44 -0
- mblt_vision/models/YOLOv7d6.yaml +50 -0
- mblt_vision/models/YOLOv7e6.yaml +50 -0
- mblt_vision/models/YOLOv7e6e.yaml +50 -0
- mblt_vision/models/YOLOv7w6.yaml +50 -0
- mblt_vision/models/YOLOv7x.yaml +44 -0
- mblt_vision/models/YOLOv8l-cls.yaml +23 -0
- mblt_vision/models/YOLOv8l-face.yaml +27 -0
- mblt_vision/models/YOLOv8l-obb.yaml +28 -0
- mblt_vision/models/YOLOv8l-pose.yaml +28 -0
- mblt_vision/models/YOLOv8l-seg.yaml +28 -0
- mblt_vision/models/YOLOv8l.yaml +27 -0
- mblt_vision/models/YOLOv8m-cls.yaml +23 -0
- mblt_vision/models/YOLOv8m-face.yaml +27 -0
- mblt_vision/models/YOLOv8m-obb.yaml +28 -0
- mblt_vision/models/YOLOv8m-pose.yaml +28 -0
- mblt_vision/models/YOLOv8m-seg.yaml +28 -0
- mblt_vision/models/YOLOv8m.yaml +27 -0
- mblt_vision/models/YOLOv8n-cls.yaml +23 -0
- mblt_vision/models/YOLOv8n-face.yaml +27 -0
- mblt_vision/models/YOLOv8n-obb.yaml +28 -0
- mblt_vision/models/YOLOv8n-pose.yaml +28 -0
- mblt_vision/models/YOLOv8n-seg.yaml +28 -0
- mblt_vision/models/YOLOv8n.yaml +27 -0
- mblt_vision/models/YOLOv8s-cls.yaml +23 -0
- mblt_vision/models/YOLOv8s-obb.yaml +28 -0
- mblt_vision/models/YOLOv8s-pose.yaml +28 -0
- mblt_vision/models/YOLOv8s-seg.yaml +28 -0
- mblt_vision/models/YOLOv8s.yaml +27 -0
- mblt_vision/models/YOLOv8x-cls.yaml +23 -0
- mblt_vision/models/YOLOv8x-obb.yaml +28 -0
- mblt_vision/models/YOLOv8x-pose-p6.yaml +28 -0
- mblt_vision/models/YOLOv8x-pose.yaml +28 -0
- mblt_vision/models/YOLOv8x-seg.yaml +28 -0
- mblt_vision/models/YOLOv8x.yaml +27 -0
- mblt_vision/models/YOLOv9c-seg.yaml +28 -0
- mblt_vision/models/YOLOv9c.yaml +27 -0
- mblt_vision/models/YOLOv9e-seg.yaml +28 -0
- mblt_vision/models/YOLOv9e.yaml +27 -0
- mblt_vision/models/YOLOv9m.yaml +27 -0
- mblt_vision/models/YOLOv9s.yaml +27 -0
- mblt_vision/models/YOLOv9t.yaml +27 -0
- mblt_vision/obb/__init__.py +39 -0
- mblt_vision/object_detection/__init__.py +153 -0
- mblt_vision/pose_estimation/__init__.py +41 -0
- mblt_vision/py.typed +1 -0
- mblt_vision/semantic_segmentation/__init__.py +29 -0
- mblt_vision/utils/__init__.py +0 -0
- mblt_vision/utils/datasets/__init__.py +85 -0
- mblt_vision/utils/datasets/ade20k.py +41 -0
- mblt_vision/utils/datasets/cityscapes.py +66 -0
- mblt_vision/utils/datasets/coco.py +243 -0
- mblt_vision/utils/datasets/dataloader.py +1016 -0
- mblt_vision/utils/datasets/dotav1.py +59 -0
- mblt_vision/utils/datasets/imagenet.py +29 -0
- mblt_vision/utils/datasets/organizer.py +2145 -0
- mblt_vision/utils/datasets/readiness.py +1063 -0
- mblt_vision/utils/evaluation/__init__.py +51 -0
- mblt_vision/utils/evaluation/_result.py +22 -0
- mblt_vision/utils/evaluation/eval_ade20k.py +302 -0
- mblt_vision/utils/evaluation/eval_cityscapes.py +32 -0
- mblt_vision/utils/evaluation/eval_coco.py +465 -0
- mblt_vision/utils/evaluation/eval_dota.py +878 -0
- mblt_vision/utils/evaluation/eval_imagenet.py +151 -0
- mblt_vision/utils/evaluation/eval_nyu_depth.py +189 -0
- mblt_vision/utils/evaluation/eval_widerface.py +440 -0
- mblt_vision/utils/letterbox.py +118 -0
- mblt_vision/utils/postprocess/__init__.py +9 -0
- mblt_vision/utils/postprocess/_letterbox.py +102 -0
- mblt_vision/utils/postprocess/base.py +743 -0
- mblt_vision/utils/postprocess/build_post.py +120 -0
- mblt_vision/utils/postprocess/cls_post.py +117 -0
- mblt_vision/utils/postprocess/common.py +1571 -0
- mblt_vision/utils/postprocess/depth_post.py +106 -0
- mblt_vision/utils/postprocess/semantic_seg_post.py +192 -0
- mblt_vision/utils/postprocess/yolo_anchor_post.py +469 -0
- mblt_vision/utils/postprocess/yolo_anchorless_post.py +952 -0
- mblt_vision/utils/postprocess/yolo_dflfree_post.py +983 -0
- mblt_vision/utils/postprocess/yolo_nmsfree_post.py +176 -0
- mblt_vision/utils/preprocess/__init__.py +27 -0
- mblt_vision/utils/preprocess/_validation.py +66 -0
- mblt_vision/utils/preprocess/base.py +157 -0
- mblt_vision/utils/preprocess/build_pre.py +48 -0
- mblt_vision/utils/preprocess/center_crop.py +75 -0
- mblt_vision/utils/preprocess/letterbox.py +123 -0
- mblt_vision/utils/preprocess/normalize.py +94 -0
- mblt_vision/utils/preprocess/order.py +74 -0
- mblt_vision/utils/preprocess/reader.py +94 -0
- mblt_vision/utils/preprocess/resize.py +202 -0
- mblt_vision/utils/preprocess/yolo_pre.py +7 -0
- mblt_vision/utils/results.py +725 -0
- mblt_vision/utils/types.py +15 -0
- mblt_vision/wrapper.py +1121 -0
- mblt_vision_python-0.0.0.dist-info/METADATA +152 -0
- mblt_vision_python-0.0.0.dist-info/RECORD +404 -0
- mblt_vision_python-0.0.0.dist-info/WHEEL +5 -0
- mblt_vision_python-0.0.0.dist-info/entry_points.txt +2 -0
- mblt_vision_python-0.0.0.dist-info/licenses/LICENSE +28 -0
- mblt_vision_python-0.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,725 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Results processing and plotting.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from collections.abc import Sequence
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import cast
|
|
10
|
+
|
|
11
|
+
import cv2
|
|
12
|
+
import numpy as np
|
|
13
|
+
import torch
|
|
14
|
+
from PIL import Image
|
|
15
|
+
|
|
16
|
+
from .._tasks import normalize_vision_task
|
|
17
|
+
from .datasets import (
|
|
18
|
+
get_ade20k_palette,
|
|
19
|
+
get_cityscapes_palette,
|
|
20
|
+
get_coco_det_palette,
|
|
21
|
+
get_coco_keypoint_palette,
|
|
22
|
+
get_coco_label,
|
|
23
|
+
get_coco_limb_palette,
|
|
24
|
+
get_coco_pose_skeleton,
|
|
25
|
+
get_dotav1_label,
|
|
26
|
+
get_dotav1_palette,
|
|
27
|
+
get_imagenet_label,
|
|
28
|
+
)
|
|
29
|
+
from .letterbox import LetterBoxGeometry
|
|
30
|
+
from mblt_vision.utils.postprocess.common import (
|
|
31
|
+
crop_mask,
|
|
32
|
+
scale_boxes,
|
|
33
|
+
scale_coords,
|
|
34
|
+
scale_masks,
|
|
35
|
+
scale_rboxes,
|
|
36
|
+
xywhr2xyxyxyxy,
|
|
37
|
+
)
|
|
38
|
+
from .preprocess._validation import normalize_uint8_rgb_array
|
|
39
|
+
from .types import ListTensorLike, NestedListTensorLike, TensorLike
|
|
40
|
+
|
|
41
|
+
LW = 2 # line width
|
|
42
|
+
RADIUS = 5 # circle radius
|
|
43
|
+
ALPHA = 0.3 # alpha for overlay
|
|
44
|
+
DENSE_OVERLAY_ALPHA = 0.6
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class Results:
|
|
48
|
+
"""Handle, process, and plot model inference results."""
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
pre_cfg: dict,
|
|
53
|
+
post_cfg: dict,
|
|
54
|
+
output: TensorLike | ListTensorLike | NestedListTensorLike,
|
|
55
|
+
**kwargs,
|
|
56
|
+
) -> None:
|
|
57
|
+
"""
|
|
58
|
+
Initializes the Results object.
|
|
59
|
+
Args:
|
|
60
|
+
pre_cfg (dict): Preprocessing configuration.
|
|
61
|
+
post_cfg (dict): Postprocessing configuration.
|
|
62
|
+
output (TensorLike | ListTensorLike | NestedListTensorLike): Raw model output.
|
|
63
|
+
**kwargs: Additional arguments.
|
|
64
|
+
"""
|
|
65
|
+
self.pre_cfg = pre_cfg
|
|
66
|
+
self.post_cfg = post_cfg
|
|
67
|
+
self.task = normalize_vision_task(post_cfg["task"])
|
|
68
|
+
self.conf_thres = kwargs.get("conf_thres", 0.25)
|
|
69
|
+
self.acc: torch.Tensor | np.ndarray | None = None
|
|
70
|
+
self.box_cls: torch.Tensor | np.ndarray | None = None
|
|
71
|
+
self.mask: torch.Tensor | np.ndarray | None = None
|
|
72
|
+
self.depth: torch.Tensor | np.ndarray | list[TensorLike] | None = None
|
|
73
|
+
self.semantic_mask: torch.Tensor | np.ndarray | list[TensorLike] | None = None
|
|
74
|
+
self.output: TensorLike | ListTensorLike | NestedListTensorLike | None = None
|
|
75
|
+
self.labels: torch.Tensor | None = None
|
|
76
|
+
self.scores: torch.Tensor | None = None
|
|
77
|
+
self.boxes: torch.Tensor | None = None
|
|
78
|
+
self.rboxes: torch.Tensor | None = None
|
|
79
|
+
self.kpts: torch.Tensor | None = None
|
|
80
|
+
self.set_output(output)
|
|
81
|
+
|
|
82
|
+
def _read_image(
|
|
83
|
+
self, source_path: str | Path | np.ndarray | Image.Image
|
|
84
|
+
) -> np.ndarray:
|
|
85
|
+
"""
|
|
86
|
+
Internal method to read an image from various input types and convert to BGR format.
|
|
87
|
+
Args:
|
|
88
|
+
source_path (str | np.ndarray | Image.Image): Path to image or image object.
|
|
89
|
+
Returns:
|
|
90
|
+
np.ndarray: Image in BGR format (cv2 style).
|
|
91
|
+
"""
|
|
92
|
+
source_img = None
|
|
93
|
+
if isinstance(source_path, Image.Image): # PIL image open
|
|
94
|
+
source_img = source_path.convert("RGB")
|
|
95
|
+
source_img = np.array(source_img)
|
|
96
|
+
source_img = cv2.cvtColor(source_img, cv2.COLOR_RGB2BGR)
|
|
97
|
+
elif isinstance(source_path, np.ndarray):
|
|
98
|
+
source_img = np.array(source_path)
|
|
99
|
+
if source_img.ndim != 3 or source_img.shape[2] != 3:
|
|
100
|
+
raise ValueError(
|
|
101
|
+
f"Image arrays must have HWC shape with three channels, got {source_img.shape}."
|
|
102
|
+
)
|
|
103
|
+
source_img = normalize_uint8_rgb_array(source_img, operation="Results.plot")
|
|
104
|
+
source_img = cv2.cvtColor(source_img, cv2.COLOR_RGB2BGR)
|
|
105
|
+
elif isinstance(source_path, (str, Path)):
|
|
106
|
+
image_path = Path(source_path)
|
|
107
|
+
if not image_path.is_file():
|
|
108
|
+
raise FileNotFoundError(f"Image file not found: {image_path}")
|
|
109
|
+
source_img = cv2.imread(str(image_path), cv2.IMREAD_COLOR)
|
|
110
|
+
else:
|
|
111
|
+
raise TypeError(
|
|
112
|
+
f"Unsupported image source type: {type(source_path).__name__}."
|
|
113
|
+
)
|
|
114
|
+
if source_img is None:
|
|
115
|
+
raise ValueError(f"Failed to decode image from {source_path!r}.")
|
|
116
|
+
return source_img
|
|
117
|
+
|
|
118
|
+
@staticmethod
|
|
119
|
+
def _save_image(save_path: str | Path, image: np.ndarray) -> None:
|
|
120
|
+
"""Save an image and report encoder or filesystem failures."""
|
|
121
|
+
|
|
122
|
+
path = Path(save_path)
|
|
123
|
+
if path.parent != Path("."):
|
|
124
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
125
|
+
if not cv2.imwrite(str(path), image):
|
|
126
|
+
raise OSError(f"Failed to write result image: {path}")
|
|
127
|
+
|
|
128
|
+
def set_output(
|
|
129
|
+
self, output: TensorLike | ListTensorLike | NestedListTensorLike
|
|
130
|
+
) -> None:
|
|
131
|
+
"""
|
|
132
|
+
Sets variables from the raw model output based on the task.
|
|
133
|
+
Args:
|
|
134
|
+
output (TensorLike | ListTensorLike | NestedListTensorLike): Raw model output.
|
|
135
|
+
Raises:
|
|
136
|
+
NotImplementedError: If the task is not supported.
|
|
137
|
+
"""
|
|
138
|
+
self.acc = None
|
|
139
|
+
self.box_cls = None
|
|
140
|
+
self.mask = None
|
|
141
|
+
self.depth = None
|
|
142
|
+
self.semantic_mask = None
|
|
143
|
+
if self.task == "image_classification":
|
|
144
|
+
if not isinstance(output, (np.ndarray, torch.Tensor)):
|
|
145
|
+
raise TypeError(
|
|
146
|
+
f"Expected tensor output for task {self.task}, got {type(output).__name__}."
|
|
147
|
+
)
|
|
148
|
+
self.acc = cast(TensorLike, output)
|
|
149
|
+
elif self.task in {
|
|
150
|
+
"object_detection",
|
|
151
|
+
"face_detection",
|
|
152
|
+
"pose_estimation",
|
|
153
|
+
"obb",
|
|
154
|
+
}:
|
|
155
|
+
if not isinstance(output, Sequence):
|
|
156
|
+
raise TypeError(
|
|
157
|
+
f"Expected list output for task {self.task}, got {type(output).__name__}."
|
|
158
|
+
)
|
|
159
|
+
if len(output) == 0:
|
|
160
|
+
raise ValueError(
|
|
161
|
+
f"Expected a non-empty output list for task {self.task}."
|
|
162
|
+
)
|
|
163
|
+
if not isinstance(output[0], (np.ndarray, torch.Tensor)):
|
|
164
|
+
raise TypeError(
|
|
165
|
+
f"Expected a tensor as the first output for task {self.task}, got {type(output[0]).__name__}."
|
|
166
|
+
)
|
|
167
|
+
self.box_cls = cast(TensorLike, output[0])
|
|
168
|
+
elif self.task == "instance_segmentation":
|
|
169
|
+
if not isinstance(output, Sequence):
|
|
170
|
+
raise TypeError(
|
|
171
|
+
f"Expected nested list output for task {self.task}, got {type(output).__name__}."
|
|
172
|
+
)
|
|
173
|
+
if len(output) == 0:
|
|
174
|
+
raise ValueError(
|
|
175
|
+
f"Expected a non-empty output list for task {self.task}."
|
|
176
|
+
)
|
|
177
|
+
if not isinstance(output[0], Sequence):
|
|
178
|
+
raise TypeError(
|
|
179
|
+
f"Expected a nested output sequence for task {self.task}, got {type(output[0]).__name__}."
|
|
180
|
+
)
|
|
181
|
+
if len(output[0]) < 2:
|
|
182
|
+
raise ValueError(
|
|
183
|
+
"Instance segmentation output must contain detections and masks."
|
|
184
|
+
)
|
|
185
|
+
seg_output = cast(ListTensorLike, output[0])
|
|
186
|
+
if not all(
|
|
187
|
+
isinstance(item, (np.ndarray, torch.Tensor)) for item in seg_output[:2]
|
|
188
|
+
):
|
|
189
|
+
raise TypeError(
|
|
190
|
+
"Instance segmentation detections and masks must be tensors."
|
|
191
|
+
)
|
|
192
|
+
self.box_cls = cast(TensorLike, seg_output[0])
|
|
193
|
+
self.mask = cast(TensorLike, seg_output[1])
|
|
194
|
+
elif self.task == "depth_estimation":
|
|
195
|
+
if isinstance(output, Sequence) and not isinstance(
|
|
196
|
+
output, (np.ndarray, torch.Tensor)
|
|
197
|
+
):
|
|
198
|
+
if len(output) == 0:
|
|
199
|
+
raise ValueError("Expected at least one depth-map tensor.")
|
|
200
|
+
if not all(
|
|
201
|
+
isinstance(item, (np.ndarray, torch.Tensor)) for item in output
|
|
202
|
+
):
|
|
203
|
+
raise TypeError(
|
|
204
|
+
f"Expected depth-map tensors for task {self.task}, got {type(output).__name__}."
|
|
205
|
+
)
|
|
206
|
+
self.depth = [cast(TensorLike, item) for item in output]
|
|
207
|
+
elif isinstance(output, (np.ndarray, torch.Tensor)):
|
|
208
|
+
self.depth = output
|
|
209
|
+
else:
|
|
210
|
+
raise TypeError(
|
|
211
|
+
f"Expected tensor depth output for task {self.task}, got {type(output)}."
|
|
212
|
+
)
|
|
213
|
+
elif self.task == "semantic_segmentation":
|
|
214
|
+
if isinstance(output, Sequence) and not isinstance(
|
|
215
|
+
output, (np.ndarray, torch.Tensor)
|
|
216
|
+
):
|
|
217
|
+
if len(output) == 0:
|
|
218
|
+
raise ValueError("Expected at least one semantic-map tensor.")
|
|
219
|
+
if not all(
|
|
220
|
+
isinstance(item, (np.ndarray, torch.Tensor)) for item in output
|
|
221
|
+
):
|
|
222
|
+
raise TypeError(
|
|
223
|
+
f"Expected semantic-map tensors for task {self.task}, got {type(output).__name__}."
|
|
224
|
+
)
|
|
225
|
+
self.semantic_mask = [cast(TensorLike, item) for item in output]
|
|
226
|
+
elif isinstance(output, (np.ndarray, torch.Tensor)):
|
|
227
|
+
self.semantic_mask = output
|
|
228
|
+
else:
|
|
229
|
+
raise TypeError(
|
|
230
|
+
f"Expected tensor semantic output for task {self.task}, got {type(output)}."
|
|
231
|
+
)
|
|
232
|
+
else:
|
|
233
|
+
raise NotImplementedError(
|
|
234
|
+
f"Task {self.task} is not supported for plotting results."
|
|
235
|
+
)
|
|
236
|
+
self.output = output # store raw output
|
|
237
|
+
|
|
238
|
+
def plot(
|
|
239
|
+
self,
|
|
240
|
+
source_path: str | Path | np.ndarray | Image.Image,
|
|
241
|
+
save_path: str | Path | None = None,
|
|
242
|
+
**kwargs,
|
|
243
|
+
) -> np.ndarray | None:
|
|
244
|
+
"""Plot inference results on the source image.
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
source_path: Image path or object to plot on.
|
|
248
|
+
save_path: Optional output image path.
|
|
249
|
+
**kwargs: Additional task-specific plotting options (e.g., topk for classification).
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
Image with results visualized in BGR format, or ``None`` for classification without an output path.
|
|
253
|
+
|
|
254
|
+
Raises:
|
|
255
|
+
NotImplementedError: If the task is not supported for plotting.
|
|
256
|
+
"""
|
|
257
|
+
if self.task == "image_classification":
|
|
258
|
+
return self._plot_image_classification(source_path, save_path, **kwargs)
|
|
259
|
+
elif self.task in {"object_detection", "face_detection"}:
|
|
260
|
+
return self._plot_object_detection(source_path, save_path, **kwargs)
|
|
261
|
+
elif self.task == "instance_segmentation":
|
|
262
|
+
return self._plot_instance_segmentation(source_path, save_path, **kwargs)
|
|
263
|
+
elif self.task == "depth_estimation":
|
|
264
|
+
return self._plot_depth_estimation(source_path, save_path, **kwargs)
|
|
265
|
+
elif self.task == "semantic_segmentation":
|
|
266
|
+
return self._plot_semantic_segmentation(source_path, save_path, **kwargs)
|
|
267
|
+
elif self.task == "pose_estimation":
|
|
268
|
+
return self._plot_pose_estimation(source_path, save_path, **kwargs)
|
|
269
|
+
elif self.task == "obb":
|
|
270
|
+
return self._plot_obb(source_path, save_path, **kwargs)
|
|
271
|
+
else:
|
|
272
|
+
raise NotImplementedError(
|
|
273
|
+
f"Task {self.task} is not supported for plotting results."
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
def _plot_depth_estimation(
|
|
277
|
+
self,
|
|
278
|
+
source_path: str | Path | np.ndarray | Image.Image,
|
|
279
|
+
save_path: str | Path | None = None,
|
|
280
|
+
**kwargs,
|
|
281
|
+
) -> np.ndarray:
|
|
282
|
+
"""Colorize the first depth map with near objects in red and blend it over the original image."""
|
|
283
|
+
|
|
284
|
+
del kwargs
|
|
285
|
+
if self.depth is None:
|
|
286
|
+
raise ValueError("No depth output found.")
|
|
287
|
+
depth_value = self.depth[0] if isinstance(self.depth, list) else self.depth
|
|
288
|
+
depth = (
|
|
289
|
+
depth_value.detach().cpu().numpy()
|
|
290
|
+
if isinstance(depth_value, torch.Tensor)
|
|
291
|
+
else depth_value
|
|
292
|
+
)
|
|
293
|
+
if depth.ndim == 3:
|
|
294
|
+
depth = depth[0]
|
|
295
|
+
if depth.ndim != 2:
|
|
296
|
+
raise ValueError(
|
|
297
|
+
f"Expected a 2D depth map or [B, H, W], got {depth.shape}."
|
|
298
|
+
)
|
|
299
|
+
image = self._read_image(source_path)
|
|
300
|
+
image_shape = (int(image.shape[0]), int(image.shape[1]))
|
|
301
|
+
if tuple(depth.shape) != image_shape:
|
|
302
|
+
depth = self._restore_depth_map(depth, image_shape)
|
|
303
|
+
valid = np.isfinite(depth) & (depth > 0)
|
|
304
|
+
if not valid.any():
|
|
305
|
+
raise ValueError("Depth output contains no positive finite values.")
|
|
306
|
+
disparity = np.zeros(depth.shape, dtype=np.float32)
|
|
307
|
+
disparity[valid] = 1.0 / depth[valid]
|
|
308
|
+
lower, upper = np.percentile(disparity[valid], (2, 98))
|
|
309
|
+
if upper <= lower:
|
|
310
|
+
upper = lower + 1e-6
|
|
311
|
+
normalized = np.zeros(depth.shape, dtype=np.uint8)
|
|
312
|
+
normalized[valid] = np.clip(
|
|
313
|
+
(disparity[valid] - lower) * 255 / (upper - lower), 0, 255
|
|
314
|
+
).astype(np.uint8)
|
|
315
|
+
overlay = cv2.applyColorMap(normalized, cv2.COLORMAP_JET)
|
|
316
|
+
overlay[~valid] = 0
|
|
317
|
+
result = cv2.addWeighted(
|
|
318
|
+
image, 1.0 - DENSE_OVERLAY_ALPHA, overlay, DENSE_OVERLAY_ALPHA, 0
|
|
319
|
+
)
|
|
320
|
+
if save_path is not None:
|
|
321
|
+
self._save_image(save_path, result)
|
|
322
|
+
return result
|
|
323
|
+
|
|
324
|
+
def _plot_semantic_segmentation(
|
|
325
|
+
self,
|
|
326
|
+
source_path: str | Path | np.ndarray | Image.Image,
|
|
327
|
+
save_path: str | Path | None = None,
|
|
328
|
+
**kwargs,
|
|
329
|
+
) -> np.ndarray:
|
|
330
|
+
"""Colorize a semantic class map and blend it over the original image."""
|
|
331
|
+
|
|
332
|
+
del kwargs
|
|
333
|
+
if self.semantic_mask is None:
|
|
334
|
+
raise ValueError("No semantic output found.")
|
|
335
|
+
semantic_value = (
|
|
336
|
+
self.semantic_mask[0]
|
|
337
|
+
if isinstance(self.semantic_mask, list)
|
|
338
|
+
else self.semantic_mask
|
|
339
|
+
)
|
|
340
|
+
class_map = (
|
|
341
|
+
semantic_value.detach().cpu().numpy()
|
|
342
|
+
if isinstance(semantic_value, torch.Tensor)
|
|
343
|
+
else semantic_value
|
|
344
|
+
)
|
|
345
|
+
if class_map.ndim == 3:
|
|
346
|
+
class_map = class_map[0]
|
|
347
|
+
if class_map.ndim != 2:
|
|
348
|
+
raise ValueError(
|
|
349
|
+
f"Expected a 2D semantic map or [B, H, W], got {class_map.shape}."
|
|
350
|
+
)
|
|
351
|
+
image = self._read_image(source_path)
|
|
352
|
+
image_shape = (int(image.shape[0]), int(image.shape[1]))
|
|
353
|
+
if tuple(class_map.shape) != image_shape:
|
|
354
|
+
class_map = self._restore_semantic_map(class_map, image_shape)
|
|
355
|
+
dataset_value = self.post_cfg.get("dataset")
|
|
356
|
+
dataset = (
|
|
357
|
+
dataset_value.lower() if isinstance(dataset_value, str) else dataset_value
|
|
358
|
+
)
|
|
359
|
+
if dataset == "ade20k":
|
|
360
|
+
default_nc = 150
|
|
361
|
+
palette_getter = get_ade20k_palette
|
|
362
|
+
elif dataset == "cityscapes":
|
|
363
|
+
default_nc = 19
|
|
364
|
+
palette_getter = get_cityscapes_palette
|
|
365
|
+
else:
|
|
366
|
+
raise ValueError(
|
|
367
|
+
f"Unsupported semantic segmentation dataset palette: {dataset!r}."
|
|
368
|
+
)
|
|
369
|
+
nc = int(self.post_cfg.get("nc", default_nc))
|
|
370
|
+
valid = class_map != 255
|
|
371
|
+
if valid.any() and (
|
|
372
|
+
int(class_map[valid].min()) < 0 or int(class_map[valid].max()) >= nc
|
|
373
|
+
):
|
|
374
|
+
raise ValueError(
|
|
375
|
+
f"Semantic class-map values must be in [0, {nc - 1}] or 255."
|
|
376
|
+
)
|
|
377
|
+
palette = np.array(
|
|
378
|
+
[palette_getter(index) for index in range(nc)], dtype=np.uint8
|
|
379
|
+
)
|
|
380
|
+
overlay = np.zeros_like(image)
|
|
381
|
+
overlay[valid] = palette[class_map[valid].astype(np.int64)]
|
|
382
|
+
blended = cv2.addWeighted(
|
|
383
|
+
image, 1.0 - DENSE_OVERLAY_ALPHA, overlay, DENSE_OVERLAY_ALPHA, 0
|
|
384
|
+
)
|
|
385
|
+
result = image.copy()
|
|
386
|
+
result[valid] = blended[valid]
|
|
387
|
+
if save_path is not None:
|
|
388
|
+
self._save_image(save_path, result)
|
|
389
|
+
return result
|
|
390
|
+
|
|
391
|
+
def _restore_semantic_map(
|
|
392
|
+
self, class_map: np.ndarray, image_shape: tuple[int, int]
|
|
393
|
+
) -> np.ndarray:
|
|
394
|
+
"""Undo the configured letterbox transform using nearest-neighbor interpolation."""
|
|
395
|
+
|
|
396
|
+
return self._restore_dense_map(
|
|
397
|
+
class_map, image_shape, cv2.INTER_NEAREST, "Semantic"
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
def _restore_depth_map(
|
|
401
|
+
self, depth: np.ndarray, image_shape: tuple[int, int]
|
|
402
|
+
) -> np.ndarray:
|
|
403
|
+
"""Undo the configured letterbox transform and resize a depth map to an image."""
|
|
404
|
+
|
|
405
|
+
return self._restore_dense_map(depth, image_shape, cv2.INTER_LINEAR, "Depth")
|
|
406
|
+
|
|
407
|
+
def _restore_dense_map(
|
|
408
|
+
self,
|
|
409
|
+
output: np.ndarray,
|
|
410
|
+
image_shape: tuple[int, int],
|
|
411
|
+
interpolation: int,
|
|
412
|
+
task_name: str,
|
|
413
|
+
) -> np.ndarray:
|
|
414
|
+
"""Undo configured letterboxing for a dense two-dimensional output."""
|
|
415
|
+
|
|
416
|
+
letterbox_cfg = self.pre_cfg.get("LetterBox", {})
|
|
417
|
+
input_shape = letterbox_cfg.get("img_size")
|
|
418
|
+
if not isinstance(input_shape, list) or len(input_shape) != 2:
|
|
419
|
+
return cv2.resize(
|
|
420
|
+
output, (image_shape[1], image_shape[0]), interpolation=interpolation
|
|
421
|
+
)
|
|
422
|
+
geometry = LetterBoxGeometry.from_shapes(
|
|
423
|
+
(int(input_shape[0]), int(input_shape[1])), image_shape
|
|
424
|
+
)
|
|
425
|
+
output_shape = (int(output.shape[0]), int(output.shape[1]))
|
|
426
|
+
top, bottom, left, right = geometry.crop_bounds(output_shape)
|
|
427
|
+
cropped = output[top:bottom, left:right]
|
|
428
|
+
if cropped.size == 0:
|
|
429
|
+
raise ValueError(
|
|
430
|
+
f"{task_name} letterbox restoration produced an empty crop."
|
|
431
|
+
)
|
|
432
|
+
return cv2.resize(
|
|
433
|
+
cropped, (image_shape[1], image_shape[0]), interpolation=interpolation
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
def _plot_image_classification(
|
|
437
|
+
self,
|
|
438
|
+
source_path: str | Path | np.ndarray | Image.Image | None = None,
|
|
439
|
+
save_path: str | Path | None = None,
|
|
440
|
+
topk: int = 5,
|
|
441
|
+
**kwargs,
|
|
442
|
+
) -> np.ndarray | None:
|
|
443
|
+
if self.acc is None:
|
|
444
|
+
raise ValueError("No accuracy output found.")
|
|
445
|
+
if isinstance(topk, bool) or not isinstance(topk, int):
|
|
446
|
+
raise TypeError(f"topk must be an integer, got {type(topk).__name__}.")
|
|
447
|
+
if topk <= 0:
|
|
448
|
+
raise ValueError(f"topk must be positive, got {topk}.")
|
|
449
|
+
if isinstance(self.acc, np.ndarray):
|
|
450
|
+
self.acc = torch.tensor(self.acc)
|
|
451
|
+
scores = self.acc.squeeze()
|
|
452
|
+
if scores.ndim != 1:
|
|
453
|
+
raise ValueError(
|
|
454
|
+
f"Classification plotting expects one class-score vector, got shape {tuple(self.acc.shape)}."
|
|
455
|
+
)
|
|
456
|
+
topk = min(topk, int(scores.numel()))
|
|
457
|
+
topk_probs, topk_indices = torch.topk(scores, topk)
|
|
458
|
+
topk_probs = np.atleast_1d(topk_probs.squeeze().detach().cpu().numpy())
|
|
459
|
+
topk_indices = np.atleast_1d(topk_indices.squeeze().detach().cpu().numpy())
|
|
460
|
+
# load labels
|
|
461
|
+
labels = [get_imagenet_label(i) for i in topk_indices]
|
|
462
|
+
comments = []
|
|
463
|
+
for i in range(topk):
|
|
464
|
+
comments.append(f"{labels[i]}: {topk_probs[i] * 100:.2f}%")
|
|
465
|
+
print(f"Label: {labels[i]}, Probability: {topk_probs[i] * 100:.2f}%")
|
|
466
|
+
if source_path is not None and save_path is not None:
|
|
467
|
+
comments_str = "\n".join(comments)
|
|
468
|
+
img = self._read_image(source_path)
|
|
469
|
+
avg_color = img.mean(axis=(0, 1))
|
|
470
|
+
txt_color = (
|
|
471
|
+
int(255 - avg_color[0]),
|
|
472
|
+
int(255 - avg_color[1]),
|
|
473
|
+
int(255 - avg_color[2]),
|
|
474
|
+
)
|
|
475
|
+
for i, line in enumerate(comments_str.splitlines()):
|
|
476
|
+
(_, h), _ = cv2.getTextSize(
|
|
477
|
+
text=line,
|
|
478
|
+
fontFace=cv2.FONT_HERSHEY_SIMPLEX,
|
|
479
|
+
fontScale=0.5,
|
|
480
|
+
thickness=1,
|
|
481
|
+
)
|
|
482
|
+
img = cv2.putText(
|
|
483
|
+
img,
|
|
484
|
+
line,
|
|
485
|
+
(15, 15 + int(1.5 * i * h)), # line spacing
|
|
486
|
+
fontFace=cv2.FONT_HERSHEY_SIMPLEX,
|
|
487
|
+
fontScale=0.5,
|
|
488
|
+
color=txt_color,
|
|
489
|
+
thickness=1,
|
|
490
|
+
lineType=cv2.LINE_AA,
|
|
491
|
+
)
|
|
492
|
+
self._save_image(save_path, img)
|
|
493
|
+
return img
|
|
494
|
+
else:
|
|
495
|
+
return None
|
|
496
|
+
|
|
497
|
+
def _plot_object_detection(
|
|
498
|
+
self,
|
|
499
|
+
source_path: str | Path | np.ndarray | Image.Image,
|
|
500
|
+
save_path: str | Path | None = None,
|
|
501
|
+
**kwargs,
|
|
502
|
+
) -> np.ndarray:
|
|
503
|
+
box_cls = self._box_cls_tensor()
|
|
504
|
+
expected_columns = 6 + self.post_cfg.get("n_extra", 0)
|
|
505
|
+
if box_cls.ndim != 2 or box_cls.shape[1] != expected_columns:
|
|
506
|
+
raise ValueError(
|
|
507
|
+
f"Object detection output must have shape [N, {expected_columns}], got {tuple(box_cls.shape)}."
|
|
508
|
+
)
|
|
509
|
+
img = self._read_image(source_path)
|
|
510
|
+
img1_shape = cast(tuple[int, int], self.pre_cfg["LetterBox"]["img_size"])
|
|
511
|
+
img0_shape: tuple[int, int] = (img.shape[0], img.shape[1])
|
|
512
|
+
self.labels = box_cls[:, 5].to(torch.int64)
|
|
513
|
+
self.scores = box_cls[:, 4]
|
|
514
|
+
self.boxes = scale_boxes(
|
|
515
|
+
img1_shape,
|
|
516
|
+
box_cls[:, :4].clone(),
|
|
517
|
+
img0_shape,
|
|
518
|
+
)
|
|
519
|
+
boxes = self.boxes
|
|
520
|
+
scores = self.scores
|
|
521
|
+
labels = self.labels
|
|
522
|
+
contours: dict[int, list[np.ndarray]] = {}
|
|
523
|
+
for box, score, label in zip(boxes, scores, labels):
|
|
524
|
+
label_idx = int(label.item())
|
|
525
|
+
palette = self._get_detection_palette(label_idx)
|
|
526
|
+
img = cv2.putText(
|
|
527
|
+
img,
|
|
528
|
+
f"{self._get_detection_label(label_idx)} {int(100 * score)}%",
|
|
529
|
+
(int(box[0]), int(box[1]) - 10),
|
|
530
|
+
cv2.FONT_HERSHEY_SIMPLEX,
|
|
531
|
+
0.5,
|
|
532
|
+
palette,
|
|
533
|
+
1,
|
|
534
|
+
cv2.LINE_AA,
|
|
535
|
+
)
|
|
536
|
+
contours.setdefault(label_idx, []).append(
|
|
537
|
+
np.array(
|
|
538
|
+
[
|
|
539
|
+
[int(box[0]), int(box[1])],
|
|
540
|
+
[int(box[2]), int(box[1])],
|
|
541
|
+
[int(box[2]), int(box[3])],
|
|
542
|
+
[int(box[0]), int(box[3])],
|
|
543
|
+
]
|
|
544
|
+
)
|
|
545
|
+
)
|
|
546
|
+
for label, contour in contours.items():
|
|
547
|
+
if len(contour) > 0:
|
|
548
|
+
cv2.drawContours(
|
|
549
|
+
img,
|
|
550
|
+
contour,
|
|
551
|
+
-1,
|
|
552
|
+
self._get_detection_palette(label),
|
|
553
|
+
LW,
|
|
554
|
+
)
|
|
555
|
+
if save_path is not None:
|
|
556
|
+
self._save_image(save_path, img)
|
|
557
|
+
return img
|
|
558
|
+
|
|
559
|
+
def _plot_instance_segmentation(
|
|
560
|
+
self,
|
|
561
|
+
source_path: str | Path | np.ndarray | Image.Image,
|
|
562
|
+
save_path: str | Path | None = None,
|
|
563
|
+
**kwargs,
|
|
564
|
+
) -> np.ndarray:
|
|
565
|
+
img = self._plot_object_detection(source_path, None, **kwargs)
|
|
566
|
+
if self.mask is None:
|
|
567
|
+
raise RuntimeError("Instance segmentation output has no mask tensor.")
|
|
568
|
+
if self.boxes is None:
|
|
569
|
+
raise RuntimeError("Instance segmentation boxes were not initialized.")
|
|
570
|
+
if self.labels is None:
|
|
571
|
+
raise RuntimeError("Instance segmentation labels were not initialized.")
|
|
572
|
+
mask = self._mask_tensor()
|
|
573
|
+
img0_shape: tuple[int, int] = (img.shape[0], img.shape[1])
|
|
574
|
+
masks = (
|
|
575
|
+
crop_mask(scale_masks(mask, img0_shape), self.boxes)
|
|
576
|
+
.gt_(0.0)
|
|
577
|
+
.permute(1, 2, 0)
|
|
578
|
+
.to(torch.float32)
|
|
579
|
+
.cpu()
|
|
580
|
+
.numpy()
|
|
581
|
+
)
|
|
582
|
+
overlay = np.zeros((masks.shape[0], masks.shape[1], 3))
|
|
583
|
+
for i, label in enumerate(self.labels):
|
|
584
|
+
label_idx = int(label.item())
|
|
585
|
+
overlay = np.maximum(
|
|
586
|
+
overlay,
|
|
587
|
+
masks[:, :, i][:, :, np.newaxis]
|
|
588
|
+
* np.array(get_coco_det_palette(label_idx)).reshape(1, 1, 3),
|
|
589
|
+
)
|
|
590
|
+
total_mask = overlay.max(axis=2, keepdims=True)
|
|
591
|
+
inv_mask = 1 - ALPHA * total_mask / 255
|
|
592
|
+
img = (img * inv_mask + overlay * ALPHA).astype(np.uint8)
|
|
593
|
+
if save_path is not None:
|
|
594
|
+
self._save_image(save_path, img)
|
|
595
|
+
return img
|
|
596
|
+
|
|
597
|
+
def _plot_pose_estimation(
|
|
598
|
+
self,
|
|
599
|
+
source_path: str | Path | np.ndarray | Image.Image,
|
|
600
|
+
save_path: str | Path | None = None,
|
|
601
|
+
**kwargs,
|
|
602
|
+
) -> np.ndarray:
|
|
603
|
+
img = self._plot_object_detection(source_path, None, **kwargs)
|
|
604
|
+
box_cls = self._box_cls_tensor()
|
|
605
|
+
img0_shape: tuple[int, int] = (img.shape[0], img.shape[1])
|
|
606
|
+
self.kpts = scale_coords(
|
|
607
|
+
self.pre_cfg["LetterBox"]["img_size"],
|
|
608
|
+
box_cls[:, 6:].reshape(-1, 17, 3).clone(),
|
|
609
|
+
img0_shape,
|
|
610
|
+
)
|
|
611
|
+
kpts = self.kpts
|
|
612
|
+
if kpts is None:
|
|
613
|
+
raise ValueError("No keypoints output found.")
|
|
614
|
+
for kpt in kpts:
|
|
615
|
+
for i, (x, y, v) in enumerate(kpt):
|
|
616
|
+
color_k = get_coco_keypoint_palette(i)
|
|
617
|
+
if float(v) < self.conf_thres:
|
|
618
|
+
continue
|
|
619
|
+
cv2.circle(
|
|
620
|
+
img,
|
|
621
|
+
(int(x), int(y)),
|
|
622
|
+
RADIUS,
|
|
623
|
+
color_k,
|
|
624
|
+
-1,
|
|
625
|
+
lineType=cv2.LINE_AA,
|
|
626
|
+
)
|
|
627
|
+
for j, sk in enumerate(get_coco_pose_skeleton()):
|
|
628
|
+
conf1 = float(kpt[sk[0] - 1, 2])
|
|
629
|
+
conf2 = float(kpt[sk[1] - 1, 2])
|
|
630
|
+
if conf1 < self.conf_thres or conf2 < self.conf_thres:
|
|
631
|
+
continue
|
|
632
|
+
pos1 = (int(kpt[sk[0] - 1, 0]), int(kpt[sk[0] - 1, 1]))
|
|
633
|
+
pos2 = (int(kpt[sk[1] - 1, 0]), int(kpt[sk[1] - 1, 1]))
|
|
634
|
+
cv2.line(
|
|
635
|
+
img,
|
|
636
|
+
pos1,
|
|
637
|
+
pos2,
|
|
638
|
+
get_coco_limb_palette(j),
|
|
639
|
+
thickness=int(np.ceil(LW / 2)),
|
|
640
|
+
lineType=cv2.LINE_AA,
|
|
641
|
+
)
|
|
642
|
+
if save_path is not None:
|
|
643
|
+
self._save_image(save_path, img)
|
|
644
|
+
return img
|
|
645
|
+
|
|
646
|
+
def _plot_obb(
|
|
647
|
+
self,
|
|
648
|
+
source_path: str | Path | np.ndarray | Image.Image,
|
|
649
|
+
save_path: str | Path | None = None,
|
|
650
|
+
**kwargs,
|
|
651
|
+
) -> np.ndarray:
|
|
652
|
+
"""Plot OBB detections on an image.
|
|
653
|
+
|
|
654
|
+
Args:
|
|
655
|
+
source_path: Path or image object.
|
|
656
|
+
save_path: Optional path to save the plotted image.
|
|
657
|
+
**kwargs: Additional plotting arguments.
|
|
658
|
+
|
|
659
|
+
Returns:
|
|
660
|
+
The plotted BGR image.
|
|
661
|
+
"""
|
|
662
|
+
del kwargs
|
|
663
|
+
box_cls = self._box_cls_tensor()
|
|
664
|
+
if box_cls.ndim != 2 or box_cls.shape[1] != 7:
|
|
665
|
+
raise ValueError(
|
|
666
|
+
f"OBB output must have shape [N, 7], got {tuple(box_cls.shape)}."
|
|
667
|
+
)
|
|
668
|
+
img = self._read_image(source_path)
|
|
669
|
+
img0_shape: tuple[int, int] = (img.shape[0], img.shape[1])
|
|
670
|
+
self.labels = box_cls[:, 5].to(torch.int64)
|
|
671
|
+
self.scores = box_cls[:, 4]
|
|
672
|
+
self.rboxes = scale_rboxes(
|
|
673
|
+
self.pre_cfg["LetterBox"]["img_size"],
|
|
674
|
+
torch.cat([box_cls[:, :4], box_cls[:, 6:7]], dim=-1),
|
|
675
|
+
img0_shape,
|
|
676
|
+
)
|
|
677
|
+
polygons = xywhr2xyxyxyxy(self.rboxes).to(torch.int32).cpu().numpy()
|
|
678
|
+
for polygon, score, label in zip(polygons, self.scores, self.labels):
|
|
679
|
+
label_idx = int(label.item())
|
|
680
|
+
color = get_dotav1_palette(label_idx)
|
|
681
|
+
text_anchor = polygon.min(axis=0)
|
|
682
|
+
img = cv2.putText(
|
|
683
|
+
img,
|
|
684
|
+
f"{get_dotav1_label(label_idx)} {int(100 * score)}%",
|
|
685
|
+
(int(text_anchor[0]), int(text_anchor[1]) - 10),
|
|
686
|
+
cv2.FONT_HERSHEY_SIMPLEX,
|
|
687
|
+
0.5,
|
|
688
|
+
color,
|
|
689
|
+
1,
|
|
690
|
+
cv2.LINE_AA,
|
|
691
|
+
)
|
|
692
|
+
cv2.drawContours(img, [polygon.reshape(-1, 1, 2)], -1, color, LW)
|
|
693
|
+
if save_path is not None:
|
|
694
|
+
self._save_image(save_path, img)
|
|
695
|
+
return img
|
|
696
|
+
|
|
697
|
+
def _box_cls_tensor(self) -> torch.Tensor:
|
|
698
|
+
"""Returns detection output as a torch tensor."""
|
|
699
|
+
if self.box_cls is None:
|
|
700
|
+
raise ValueError("No box_cls output found.")
|
|
701
|
+
if isinstance(self.box_cls, np.ndarray):
|
|
702
|
+
return torch.from_numpy(self.box_cls)
|
|
703
|
+
return self.box_cls
|
|
704
|
+
|
|
705
|
+
def _get_detection_label(self, label_idx: int) -> str:
|
|
706
|
+
"""Return the display label for detection-style tasks."""
|
|
707
|
+
if self.task == "face_detection":
|
|
708
|
+
if label_idx != 0:
|
|
709
|
+
raise ValueError(f"Unexpected face_detection class index: {label_idx}.")
|
|
710
|
+
return "face"
|
|
711
|
+
return get_coco_label(label_idx)
|
|
712
|
+
|
|
713
|
+
def _get_detection_palette(self, label_idx: int) -> tuple[int, int, int]:
|
|
714
|
+
"""Return the display color for detection-style tasks."""
|
|
715
|
+
if self.task == "face_detection":
|
|
716
|
+
return get_coco_det_palette(0)
|
|
717
|
+
return get_coco_det_palette(label_idx)
|
|
718
|
+
|
|
719
|
+
def _mask_tensor(self) -> torch.Tensor:
|
|
720
|
+
"""Returns segmentation mask output as a torch tensor."""
|
|
721
|
+
if self.mask is None:
|
|
722
|
+
raise ValueError("No mask output found.")
|
|
723
|
+
if isinstance(self.mask, np.ndarray):
|
|
724
|
+
return torch.from_numpy(self.mask)
|
|
725
|
+
return self.mask
|