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.
Files changed (404) hide show
  1. mblt_vision/__init__.py +86 -0
  2. mblt_vision/_api.py +53 -0
  3. mblt_vision/_compat.py +227 -0
  4. mblt_vision/_model_paths.py +137 -0
  5. mblt_vision/_tasks.py +30 -0
  6. mblt_vision/benchmark/__init__.py +1 -0
  7. mblt_vision/benchmark/argparse_utils.py +106 -0
  8. mblt_vision/benchmark/chart_utils.py +146 -0
  9. mblt_vision/benchmark/io_utils.py +64 -0
  10. mblt_vision/benchmark/summary_utils.py +770 -0
  11. mblt_vision/cli/__init__.py +5 -0
  12. mblt_vision/cli/__main__.py +5 -0
  13. mblt_vision/cli/_vision.py +337 -0
  14. mblt_vision/cli/compile.py +117 -0
  15. mblt_vision/cli/main.py +35 -0
  16. mblt_vision/cli/predict.py +64 -0
  17. mblt_vision/cli/val.py +562 -0
  18. mblt_vision/compile/__init__.py +21 -0
  19. mblt_vision/compile/vision.py +1120 -0
  20. mblt_vision/datasets/__init__.py +15 -0
  21. mblt_vision/datasets/ade20k.yaml +164 -0
  22. mblt_vision/datasets/cityscapes.yaml +54 -0
  23. mblt_vision/datasets/coco.yaml +178 -0
  24. mblt_vision/datasets/dotav1.yaml +28 -0
  25. mblt_vision/datasets/imagenet.yaml +1019 -0
  26. mblt_vision/datasets/imagenet_synsets.txt +1000 -0
  27. mblt_vision/datasets/nyu-depth.yaml +7 -0
  28. mblt_vision/datasets/registry.py +158 -0
  29. mblt_vision/datasets/widerface.yaml +9 -0
  30. mblt_vision/depth_estimation/__init__.py +19 -0
  31. mblt_vision/face_detection/__init__.py +43 -0
  32. mblt_vision/image_classification/__init__.py +311 -0
  33. mblt_vision/instance_segmentation/__init__.py +65 -0
  34. mblt_vision/models/AlexNet.yaml +23 -0
  35. mblt_vision/models/CAFormer_B36.yaml +22 -0
  36. mblt_vision/models/CAFormer_M36.yaml +22 -0
  37. mblt_vision/models/CAFormer_S18.yaml +22 -0
  38. mblt_vision/models/CAFormer_S36.yaml +22 -0
  39. mblt_vision/models/CoAtNet_0_RW_224.yaml +22 -0
  40. mblt_vision/models/CoAtNet_1_RW_224.yaml +22 -0
  41. mblt_vision/models/CoAtNet_2_RW_224.yaml +22 -0
  42. mblt_vision/models/ConvFormer_B36.yaml +22 -0
  43. mblt_vision/models/ConvFormer_M36.yaml +22 -0
  44. mblt_vision/models/ConvFormer_S18.yaml +22 -0
  45. mblt_vision/models/ConvFormer_S36.yaml +22 -0
  46. mblt_vision/models/ConvNext_Base.yaml +23 -0
  47. mblt_vision/models/ConvNext_Large.yaml +23 -0
  48. mblt_vision/models/ConvNext_Small.yaml +23 -0
  49. mblt_vision/models/ConvNext_Tiny.yaml +23 -0
  50. mblt_vision/models/DeiT3_Base_Patch16_224.yaml +22 -0
  51. mblt_vision/models/DeiT3_Base_Patch16_384.yaml +22 -0
  52. mblt_vision/models/DeiT3_Large_Patch16_224.yaml +22 -0
  53. mblt_vision/models/DeiT3_Large_Patch16_384.yaml +22 -0
  54. mblt_vision/models/DeiT3_Medium_Patch16_224.yaml +22 -0
  55. mblt_vision/models/DeiT3_Small_Patch16_224.yaml +22 -0
  56. mblt_vision/models/DeiT3_Small_Patch16_384.yaml +22 -0
  57. mblt_vision/models/DeiT_Base_Patch16_224.yaml +22 -0
  58. mblt_vision/models/DeiT_Base_Patch16_384.yaml +22 -0
  59. mblt_vision/models/DeiT_Small_Patch16_224.yaml +22 -0
  60. mblt_vision/models/DeiT_Tiny_Patch16_224.yaml +22 -0
  61. mblt_vision/models/DenseNet121.yaml +23 -0
  62. mblt_vision/models/DenseNet161.yaml +23 -0
  63. mblt_vision/models/DenseNet169.yaml +23 -0
  64. mblt_vision/models/DenseNet201.yaml +23 -0
  65. mblt_vision/models/EfficientFormer_L1.yaml +22 -0
  66. mblt_vision/models/EfficientFormer_L3.yaml +22 -0
  67. mblt_vision/models/EfficientFormer_L7.yaml +22 -0
  68. mblt_vision/models/EfficientNet_B0.yaml +23 -0
  69. mblt_vision/models/EfficientNet_B1.yaml +32 -0
  70. mblt_vision/models/EfficientNet_B2.yaml +23 -0
  71. mblt_vision/models/EfficientNet_B3.yaml +23 -0
  72. mblt_vision/models/EfficientNet_B4.yaml +23 -0
  73. mblt_vision/models/EfficientNet_B5.yaml +23 -0
  74. mblt_vision/models/EfficientNet_B6.yaml +23 -0
  75. mblt_vision/models/EfficientNet_B7.yaml +23 -0
  76. mblt_vision/models/EfficientNet_V2_L.yaml +23 -0
  77. mblt_vision/models/EfficientNet_V2_M.yaml +23 -0
  78. mblt_vision/models/EfficientNet_V2_S.yaml +23 -0
  79. mblt_vision/models/FlexiVit_Base.yaml +22 -0
  80. mblt_vision/models/FlexiVit_Large.yaml +22 -0
  81. mblt_vision/models/FlexiVit_Small.yaml +22 -0
  82. mblt_vision/models/GELANc-seg.yaml +29 -0
  83. mblt_vision/models/GELANc.yaml +28 -0
  84. mblt_vision/models/GELANe.yaml +28 -0
  85. mblt_vision/models/GELANm.yaml +28 -0
  86. mblt_vision/models/GELANs.yaml +28 -0
  87. mblt_vision/models/GoogLeNet.yaml +23 -0
  88. mblt_vision/models/Inception_V3.yaml +23 -0
  89. mblt_vision/models/LeViT_Conv_128.yaml +22 -0
  90. mblt_vision/models/LeViT_Conv_128S.yaml +22 -0
  91. mblt_vision/models/LeViT_Conv_192.yaml +22 -0
  92. mblt_vision/models/LeViT_Conv_256.yaml +22 -0
  93. mblt_vision/models/LeViT_Conv_384.yaml +22 -0
  94. mblt_vision/models/MNASNet0_5.yaml +23 -0
  95. mblt_vision/models/MNASNet0_75.yaml +23 -0
  96. mblt_vision/models/MNASNet1_0.yaml +23 -0
  97. mblt_vision/models/MNASNet1_3.yaml +23 -0
  98. mblt_vision/models/MobileNet_V2.yaml +32 -0
  99. mblt_vision/models/MobileNet_V3_Large.yaml +32 -0
  100. mblt_vision/models/MobileNet_V3_Small.yaml +23 -0
  101. mblt_vision/models/RegNet_X_16GF.yaml +32 -0
  102. mblt_vision/models/RegNet_X_1_6GF.yaml +32 -0
  103. mblt_vision/models/RegNet_X_32GF.yaml +32 -0
  104. mblt_vision/models/RegNet_X_3_2GF.yaml +32 -0
  105. mblt_vision/models/RegNet_X_400MF.yaml +32 -0
  106. mblt_vision/models/RegNet_X_800MF.yaml +32 -0
  107. mblt_vision/models/RegNet_X_8GF.yaml +32 -0
  108. mblt_vision/models/RegNet_Y_16GF.yaml +76 -0
  109. mblt_vision/models/RegNet_Y_1_6GF.yaml +32 -0
  110. mblt_vision/models/RegNet_Y_32GF.yaml +76 -0
  111. mblt_vision/models/RegNet_Y_3_2GF.yaml +32 -0
  112. mblt_vision/models/RegNet_Y_400MF.yaml +32 -0
  113. mblt_vision/models/RegNet_Y_800MF.yaml +32 -0
  114. mblt_vision/models/RegNet_Y_8GF.yaml +32 -0
  115. mblt_vision/models/RepViT_M0_9.yaml +22 -0
  116. mblt_vision/models/RepViT_M1.yaml +22 -0
  117. mblt_vision/models/RepViT_M1_0.yaml +22 -0
  118. mblt_vision/models/RepViT_M1_1.yaml +22 -0
  119. mblt_vision/models/RepViT_M1_5.yaml +22 -0
  120. mblt_vision/models/RepViT_M2.yaml +22 -0
  121. mblt_vision/models/RepViT_M2_3.yaml +22 -0
  122. mblt_vision/models/RepViT_M3.yaml +22 -0
  123. mblt_vision/models/ResNeXt101_32X8D.yaml +32 -0
  124. mblt_vision/models/ResNeXt101_64X4D.yaml +23 -0
  125. mblt_vision/models/ResNeXt50_32X4D.yaml +32 -0
  126. mblt_vision/models/ResNet101.yaml +32 -0
  127. mblt_vision/models/ResNet152.yaml +32 -0
  128. mblt_vision/models/ResNet18.yaml +23 -0
  129. mblt_vision/models/ResNet34.yaml +23 -0
  130. mblt_vision/models/ResNet50.yaml +32 -0
  131. mblt_vision/models/ShuffleNet_V2_X0_5.yaml +23 -0
  132. mblt_vision/models/ShuffleNet_V2_X1_0.yaml +23 -0
  133. mblt_vision/models/ShuffleNet_V2_X1_5.yaml +23 -0
  134. mblt_vision/models/ShuffleNet_V2_X2_0.yaml +23 -0
  135. mblt_vision/models/SqueezeNet1_0.yaml +23 -0
  136. mblt_vision/models/SqueezeNet1_1.yaml +23 -0
  137. mblt_vision/models/Swin_B.yaml +23 -0
  138. mblt_vision/models/Swin_S.yaml +23 -0
  139. mblt_vision/models/Swin_T.yaml +23 -0
  140. mblt_vision/models/VGG11.yaml +23 -0
  141. mblt_vision/models/VGG11_BN.yaml +23 -0
  142. mblt_vision/models/VGG13.yaml +23 -0
  143. mblt_vision/models/VGG13_BN.yaml +23 -0
  144. mblt_vision/models/VGG16.yaml +23 -0
  145. mblt_vision/models/VGG16_BN.yaml +23 -0
  146. mblt_vision/models/VGG19.yaml +23 -0
  147. mblt_vision/models/VGG19_BN.yaml +23 -0
  148. mblt_vision/models/ViT_B_16.yaml +67 -0
  149. mblt_vision/models/ViT_B_32.yaml +23 -0
  150. mblt_vision/models/ViT_Base_Patch16_224.yaml +22 -0
  151. mblt_vision/models/ViT_Base_Patch16_384.yaml +22 -0
  152. mblt_vision/models/ViT_Base_Patch32_224.yaml +22 -0
  153. mblt_vision/models/ViT_Base_Patch32_384.yaml +22 -0
  154. mblt_vision/models/ViT_Base_Patch8_224.yaml +22 -0
  155. mblt_vision/models/ViT_L_16.yaml +67 -0
  156. mblt_vision/models/ViT_L_32.yaml +23 -0
  157. mblt_vision/models/ViT_Large_Patch16_224.yaml +22 -0
  158. mblt_vision/models/ViT_Large_Patch16_384.yaml +22 -0
  159. mblt_vision/models/ViT_Large_Patch32_384.yaml +22 -0
  160. mblt_vision/models/ViT_Small_Patch16_224.yaml +22 -0
  161. mblt_vision/models/ViT_Small_Patch16_384.yaml +22 -0
  162. mblt_vision/models/ViT_Small_Patch32_224.yaml +22 -0
  163. mblt_vision/models/ViT_Small_Patch32_384.yaml +22 -0
  164. mblt_vision/models/ViT_Tiny_Patch16_224.yaml +22 -0
  165. mblt_vision/models/ViT_Tiny_Patch16_384.yaml +22 -0
  166. mblt_vision/models/VisFormer_Small.yaml +22 -0
  167. mblt_vision/models/VisFormer_Tiny.yaml +22 -0
  168. mblt_vision/models/Wide_ResNet101_2.yaml +32 -0
  169. mblt_vision/models/Wide_ResNet50_2.yaml +32 -0
  170. mblt_vision/models/YOLO11l-cls.yaml +23 -0
  171. mblt_vision/models/YOLO11l-face.yaml +27 -0
  172. mblt_vision/models/YOLO11l-obb.yaml +28 -0
  173. mblt_vision/models/YOLO11l-pose.yaml +28 -0
  174. mblt_vision/models/YOLO11l-seg.yaml +28 -0
  175. mblt_vision/models/YOLO11l.yaml +27 -0
  176. mblt_vision/models/YOLO11m-cls.yaml +23 -0
  177. mblt_vision/models/YOLO11m-face.yaml +27 -0
  178. mblt_vision/models/YOLO11m-obb.yaml +28 -0
  179. mblt_vision/models/YOLO11m-pose.yaml +28 -0
  180. mblt_vision/models/YOLO11m-seg.yaml +28 -0
  181. mblt_vision/models/YOLO11m.yaml +27 -0
  182. mblt_vision/models/YOLO11n-cls.yaml +23 -0
  183. mblt_vision/models/YOLO11n-face.yaml +27 -0
  184. mblt_vision/models/YOLO11n-obb.yaml +28 -0
  185. mblt_vision/models/YOLO11n-pose.yaml +28 -0
  186. mblt_vision/models/YOLO11n-seg.yaml +28 -0
  187. mblt_vision/models/YOLO11n.yaml +27 -0
  188. mblt_vision/models/YOLO11s-cls.yaml +23 -0
  189. mblt_vision/models/YOLO11s-face.yaml +27 -0
  190. mblt_vision/models/YOLO11s-obb.yaml +28 -0
  191. mblt_vision/models/YOLO11s-pose.yaml +28 -0
  192. mblt_vision/models/YOLO11s-seg.yaml +28 -0
  193. mblt_vision/models/YOLO11s.yaml +27 -0
  194. mblt_vision/models/YOLO11x-cls.yaml +23 -0
  195. mblt_vision/models/YOLO11x-obb.yaml +28 -0
  196. mblt_vision/models/YOLO11x-pose.yaml +28 -0
  197. mblt_vision/models/YOLO11x-seg.yaml +28 -0
  198. mblt_vision/models/YOLO11x.yaml +27 -0
  199. mblt_vision/models/YOLO12l-face.yaml +27 -0
  200. mblt_vision/models/YOLO12l-seg.yaml +28 -0
  201. mblt_vision/models/YOLO12l.yaml +27 -0
  202. mblt_vision/models/YOLO12m-face.yaml +27 -0
  203. mblt_vision/models/YOLO12m-seg.yaml +28 -0
  204. mblt_vision/models/YOLO12m.yaml +27 -0
  205. mblt_vision/models/YOLO12n-face.yaml +27 -0
  206. mblt_vision/models/YOLO12n-seg.yaml +28 -0
  207. mblt_vision/models/YOLO12n.yaml +27 -0
  208. mblt_vision/models/YOLO12s-face.yaml +27 -0
  209. mblt_vision/models/YOLO12s-seg.yaml +28 -0
  210. mblt_vision/models/YOLO12s.yaml +27 -0
  211. mblt_vision/models/YOLO12x-seg.yaml +28 -0
  212. mblt_vision/models/YOLO12x.yaml +27 -0
  213. mblt_vision/models/YOLO26l-cls.yaml +23 -0
  214. mblt_vision/models/YOLO26l-depth.yaml +17 -0
  215. mblt_vision/models/YOLO26l-distill.yaml +27 -0
  216. mblt_vision/models/YOLO26l-obb.yaml +28 -0
  217. mblt_vision/models/YOLO26l-pose.yaml +28 -0
  218. mblt_vision/models/YOLO26l-seg.yaml +28 -0
  219. mblt_vision/models/YOLO26l-sem-ade20k.yaml +17 -0
  220. mblt_vision/models/YOLO26l-sem.yaml +17 -0
  221. mblt_vision/models/YOLO26l.yaml +27 -0
  222. mblt_vision/models/YOLO26m-cls.yaml +23 -0
  223. mblt_vision/models/YOLO26m-depth.yaml +17 -0
  224. mblt_vision/models/YOLO26m-distill.yaml +27 -0
  225. mblt_vision/models/YOLO26m-obb.yaml +28 -0
  226. mblt_vision/models/YOLO26m-pose.yaml +28 -0
  227. mblt_vision/models/YOLO26m-seg.yaml +28 -0
  228. mblt_vision/models/YOLO26m-sem-ade20k.yaml +17 -0
  229. mblt_vision/models/YOLO26m-sem.yaml +17 -0
  230. mblt_vision/models/YOLO26m.yaml +27 -0
  231. mblt_vision/models/YOLO26n-cls.yaml +23 -0
  232. mblt_vision/models/YOLO26n-depth.yaml +17 -0
  233. mblt_vision/models/YOLO26n-distill.yaml +27 -0
  234. mblt_vision/models/YOLO26n-obb.yaml +28 -0
  235. mblt_vision/models/YOLO26n-pose.yaml +28 -0
  236. mblt_vision/models/YOLO26n-seg.yaml +28 -0
  237. mblt_vision/models/YOLO26n-sem-ade20k.yaml +17 -0
  238. mblt_vision/models/YOLO26n-sem.yaml +17 -0
  239. mblt_vision/models/YOLO26n.yaml +27 -0
  240. mblt_vision/models/YOLO26s-cls.yaml +23 -0
  241. mblt_vision/models/YOLO26s-depth.yaml +17 -0
  242. mblt_vision/models/YOLO26s-distill.yaml +27 -0
  243. mblt_vision/models/YOLO26s-obb.yaml +28 -0
  244. mblt_vision/models/YOLO26s-pose.yaml +28 -0
  245. mblt_vision/models/YOLO26s-seg.yaml +28 -0
  246. mblt_vision/models/YOLO26s-sem-ade20k.yaml +17 -0
  247. mblt_vision/models/YOLO26s-sem.yaml +17 -0
  248. mblt_vision/models/YOLO26s.yaml +27 -0
  249. mblt_vision/models/YOLO26x-cls.yaml +23 -0
  250. mblt_vision/models/YOLO26x-depth.yaml +17 -0
  251. mblt_vision/models/YOLO26x-distill.yaml +27 -0
  252. mblt_vision/models/YOLO26x-obb.yaml +28 -0
  253. mblt_vision/models/YOLO26x-pose.yaml +28 -0
  254. mblt_vision/models/YOLO26x-seg.yaml +28 -0
  255. mblt_vision/models/YOLO26x-sem-ade20k.yaml +17 -0
  256. mblt_vision/models/YOLO26x-sem.yaml +17 -0
  257. mblt_vision/models/YOLO26x.yaml +27 -0
  258. mblt_vision/models/YOLOv10b.yaml +28 -0
  259. mblt_vision/models/YOLOv10l-face.yaml +28 -0
  260. mblt_vision/models/YOLOv10l.yaml +28 -0
  261. mblt_vision/models/YOLOv10m-face.yaml +28 -0
  262. mblt_vision/models/YOLOv10m.yaml +28 -0
  263. mblt_vision/models/YOLOv10n-face.yaml +28 -0
  264. mblt_vision/models/YOLOv10n.yaml +28 -0
  265. mblt_vision/models/YOLOv10s-face.yaml +28 -0
  266. mblt_vision/models/YOLOv10s.yaml +28 -0
  267. mblt_vision/models/YOLOv10x.yaml +28 -0
  268. mblt_vision/models/YOLOv3-spp.yaml +44 -0
  269. mblt_vision/models/YOLOv3-sppu.yaml +27 -0
  270. mblt_vision/models/YOLOv3-tiny.yaml +38 -0
  271. mblt_vision/models/YOLOv3-tinyu.yaml +27 -0
  272. mblt_vision/models/YOLOv3.yaml +44 -0
  273. mblt_vision/models/YOLOv3u.yaml +27 -0
  274. mblt_vision/models/YOLOv5l-cls.yaml +22 -0
  275. mblt_vision/models/YOLOv5l-seg.yaml +45 -0
  276. mblt_vision/models/YOLOv5l.yaml +44 -0
  277. mblt_vision/models/YOLOv5l6.yaml +50 -0
  278. mblt_vision/models/YOLOv5l6u.yaml +27 -0
  279. mblt_vision/models/YOLOv5lu.yaml +27 -0
  280. mblt_vision/models/YOLOv5m-cls.yaml +22 -0
  281. mblt_vision/models/YOLOv5m-seg.yaml +45 -0
  282. mblt_vision/models/YOLOv5m.yaml +45 -0
  283. mblt_vision/models/YOLOv5m6.yaml +50 -0
  284. mblt_vision/models/YOLOv5m6u.yaml +27 -0
  285. mblt_vision/models/YOLOv5mu.yaml +27 -0
  286. mblt_vision/models/YOLOv5n-cls.yaml +22 -0
  287. mblt_vision/models/YOLOv5n-seg.yaml +45 -0
  288. mblt_vision/models/YOLOv5n.yaml +44 -0
  289. mblt_vision/models/YOLOv5n6.yaml +50 -0
  290. mblt_vision/models/YOLOv5n6u.yaml +27 -0
  291. mblt_vision/models/YOLOv5nu.yaml +27 -0
  292. mblt_vision/models/YOLOv5s-cls.yaml +22 -0
  293. mblt_vision/models/YOLOv5s-seg.yaml +45 -0
  294. mblt_vision/models/YOLOv5s.yaml +44 -0
  295. mblt_vision/models/YOLOv5s6.yaml +50 -0
  296. mblt_vision/models/YOLOv5s6u.yaml +27 -0
  297. mblt_vision/models/YOLOv5su.yaml +27 -0
  298. mblt_vision/models/YOLOv5x-cls.yaml +22 -0
  299. mblt_vision/models/YOLOv5x-seg.yaml +45 -0
  300. mblt_vision/models/YOLOv5x.yaml +44 -0
  301. mblt_vision/models/YOLOv5x6.yaml +50 -0
  302. mblt_vision/models/YOLOv5x6u.yaml +27 -0
  303. mblt_vision/models/YOLOv5xu.yaml +27 -0
  304. mblt_vision/models/YOLOv6m-face.yaml +27 -0
  305. mblt_vision/models/YOLOv6n-face.yaml +27 -0
  306. mblt_vision/models/YOLOv7.yaml +44 -0
  307. mblt_vision/models/YOLOv7d6.yaml +50 -0
  308. mblt_vision/models/YOLOv7e6.yaml +50 -0
  309. mblt_vision/models/YOLOv7e6e.yaml +50 -0
  310. mblt_vision/models/YOLOv7w6.yaml +50 -0
  311. mblt_vision/models/YOLOv7x.yaml +44 -0
  312. mblt_vision/models/YOLOv8l-cls.yaml +23 -0
  313. mblt_vision/models/YOLOv8l-face.yaml +27 -0
  314. mblt_vision/models/YOLOv8l-obb.yaml +28 -0
  315. mblt_vision/models/YOLOv8l-pose.yaml +28 -0
  316. mblt_vision/models/YOLOv8l-seg.yaml +28 -0
  317. mblt_vision/models/YOLOv8l.yaml +27 -0
  318. mblt_vision/models/YOLOv8m-cls.yaml +23 -0
  319. mblt_vision/models/YOLOv8m-face.yaml +27 -0
  320. mblt_vision/models/YOLOv8m-obb.yaml +28 -0
  321. mblt_vision/models/YOLOv8m-pose.yaml +28 -0
  322. mblt_vision/models/YOLOv8m-seg.yaml +28 -0
  323. mblt_vision/models/YOLOv8m.yaml +27 -0
  324. mblt_vision/models/YOLOv8n-cls.yaml +23 -0
  325. mblt_vision/models/YOLOv8n-face.yaml +27 -0
  326. mblt_vision/models/YOLOv8n-obb.yaml +28 -0
  327. mblt_vision/models/YOLOv8n-pose.yaml +28 -0
  328. mblt_vision/models/YOLOv8n-seg.yaml +28 -0
  329. mblt_vision/models/YOLOv8n.yaml +27 -0
  330. mblt_vision/models/YOLOv8s-cls.yaml +23 -0
  331. mblt_vision/models/YOLOv8s-obb.yaml +28 -0
  332. mblt_vision/models/YOLOv8s-pose.yaml +28 -0
  333. mblt_vision/models/YOLOv8s-seg.yaml +28 -0
  334. mblt_vision/models/YOLOv8s.yaml +27 -0
  335. mblt_vision/models/YOLOv8x-cls.yaml +23 -0
  336. mblt_vision/models/YOLOv8x-obb.yaml +28 -0
  337. mblt_vision/models/YOLOv8x-pose-p6.yaml +28 -0
  338. mblt_vision/models/YOLOv8x-pose.yaml +28 -0
  339. mblt_vision/models/YOLOv8x-seg.yaml +28 -0
  340. mblt_vision/models/YOLOv8x.yaml +27 -0
  341. mblt_vision/models/YOLOv9c-seg.yaml +28 -0
  342. mblt_vision/models/YOLOv9c.yaml +27 -0
  343. mblt_vision/models/YOLOv9e-seg.yaml +28 -0
  344. mblt_vision/models/YOLOv9e.yaml +27 -0
  345. mblt_vision/models/YOLOv9m.yaml +27 -0
  346. mblt_vision/models/YOLOv9s.yaml +27 -0
  347. mblt_vision/models/YOLOv9t.yaml +27 -0
  348. mblt_vision/obb/__init__.py +39 -0
  349. mblt_vision/object_detection/__init__.py +153 -0
  350. mblt_vision/pose_estimation/__init__.py +41 -0
  351. mblt_vision/py.typed +1 -0
  352. mblt_vision/semantic_segmentation/__init__.py +29 -0
  353. mblt_vision/utils/__init__.py +0 -0
  354. mblt_vision/utils/datasets/__init__.py +85 -0
  355. mblt_vision/utils/datasets/ade20k.py +41 -0
  356. mblt_vision/utils/datasets/cityscapes.py +66 -0
  357. mblt_vision/utils/datasets/coco.py +243 -0
  358. mblt_vision/utils/datasets/dataloader.py +1016 -0
  359. mblt_vision/utils/datasets/dotav1.py +59 -0
  360. mblt_vision/utils/datasets/imagenet.py +29 -0
  361. mblt_vision/utils/datasets/organizer.py +2145 -0
  362. mblt_vision/utils/datasets/readiness.py +1063 -0
  363. mblt_vision/utils/evaluation/__init__.py +51 -0
  364. mblt_vision/utils/evaluation/_result.py +22 -0
  365. mblt_vision/utils/evaluation/eval_ade20k.py +302 -0
  366. mblt_vision/utils/evaluation/eval_cityscapes.py +32 -0
  367. mblt_vision/utils/evaluation/eval_coco.py +465 -0
  368. mblt_vision/utils/evaluation/eval_dota.py +878 -0
  369. mblt_vision/utils/evaluation/eval_imagenet.py +151 -0
  370. mblt_vision/utils/evaluation/eval_nyu_depth.py +189 -0
  371. mblt_vision/utils/evaluation/eval_widerface.py +440 -0
  372. mblt_vision/utils/letterbox.py +118 -0
  373. mblt_vision/utils/postprocess/__init__.py +9 -0
  374. mblt_vision/utils/postprocess/_letterbox.py +102 -0
  375. mblt_vision/utils/postprocess/base.py +743 -0
  376. mblt_vision/utils/postprocess/build_post.py +120 -0
  377. mblt_vision/utils/postprocess/cls_post.py +117 -0
  378. mblt_vision/utils/postprocess/common.py +1571 -0
  379. mblt_vision/utils/postprocess/depth_post.py +106 -0
  380. mblt_vision/utils/postprocess/semantic_seg_post.py +192 -0
  381. mblt_vision/utils/postprocess/yolo_anchor_post.py +469 -0
  382. mblt_vision/utils/postprocess/yolo_anchorless_post.py +952 -0
  383. mblt_vision/utils/postprocess/yolo_dflfree_post.py +983 -0
  384. mblt_vision/utils/postprocess/yolo_nmsfree_post.py +176 -0
  385. mblt_vision/utils/preprocess/__init__.py +27 -0
  386. mblt_vision/utils/preprocess/_validation.py +66 -0
  387. mblt_vision/utils/preprocess/base.py +157 -0
  388. mblt_vision/utils/preprocess/build_pre.py +48 -0
  389. mblt_vision/utils/preprocess/center_crop.py +75 -0
  390. mblt_vision/utils/preprocess/letterbox.py +123 -0
  391. mblt_vision/utils/preprocess/normalize.py +94 -0
  392. mblt_vision/utils/preprocess/order.py +74 -0
  393. mblt_vision/utils/preprocess/reader.py +94 -0
  394. mblt_vision/utils/preprocess/resize.py +202 -0
  395. mblt_vision/utils/preprocess/yolo_pre.py +7 -0
  396. mblt_vision/utils/results.py +725 -0
  397. mblt_vision/utils/types.py +15 -0
  398. mblt_vision/wrapper.py +1121 -0
  399. mblt_vision_python-0.0.0.dist-info/METADATA +152 -0
  400. mblt_vision_python-0.0.0.dist-info/RECORD +404 -0
  401. mblt_vision_python-0.0.0.dist-info/WHEEL +5 -0
  402. mblt_vision_python-0.0.0.dist-info/entry_points.txt +2 -0
  403. mblt_vision_python-0.0.0.dist-info/licenses/LICENSE +28 -0
  404. mblt_vision_python-0.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1016 @@
1
+ """
2
+ Custom dataloaders for vision datasets.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ import json
8
+ import os
9
+ from pathlib import Path
10
+ from typing import Any, Callable
11
+
12
+ import cv2
13
+ import numpy as np
14
+ import torch
15
+ from faster_coco_eval import COCO
16
+ from mblt_vision.utils.preprocess.letterbox import letterbox_semantic_mask
17
+ from PIL import Image
18
+
19
+ from .cityscapes import CITYSCAPES_SOURCE_TO_TRAIN_ID
20
+ from .readiness import IMAGE_SUFFIXES
21
+
22
+
23
+ def _unique_paths_by_stem(
24
+ directory: str, suffixes: tuple[str, ...], description: str
25
+ ) -> dict[str, str]:
26
+ """Return supported direct-child files keyed by unique case-preserving stems."""
27
+
28
+ names = [name for name in os.listdir(directory) if name.lower().endswith(suffixes)]
29
+ stems = [os.path.splitext(name)[0] for name in names]
30
+ if len(stems) != len(set(stems)):
31
+ raise ValueError(f"{description} contain duplicate filename stems.")
32
+ return {
33
+ stem: os.path.join(directory, name)
34
+ for stem, name in zip(stems, names, strict=True)
35
+ }
36
+
37
+
38
+ class CustomCOCODataset(torch.utils.data.Dataset[tuple[np.ndarray, int, int, int]]):
39
+ """Custom COCO dataset class for loading images and metadata.
40
+
41
+ This class provides a simple interface for accessing COCO formatted data
42
+ without requiring external library dependencies like torchvision.
43
+
44
+ Attributes:
45
+ root (str): Root directory path containing the images.
46
+ coco (COCO): COCO helper object from faster_coco_eval.
47
+ ids (list[int]): Sorted list of image IDs in the dataset.
48
+ """
49
+
50
+ def __init__(
51
+ self, root: str, annFile: str, min_keypoints: int | None = None
52
+ ) -> None:
53
+ """Initialize the custom COCO dataset.
54
+
55
+ Args:
56
+ root (str): Path to the directory containing images.
57
+ annFile (str): Path to the COCO annotation JSON file.
58
+ min_keypoints: If set, keep only images with at least one
59
+ annotation whose ``num_keypoints`` is greater than this value.
60
+ """
61
+ self.root = root
62
+ try:
63
+ raw_annotation = json.loads(Path(annFile).read_text(encoding="utf-8"))
64
+ except (OSError, UnicodeError, json.JSONDecodeError) as exc:
65
+ raise ValueError(
66
+ f"Unable to read COCO annotation file {annFile}: {exc}."
67
+ ) from exc
68
+ if not isinstance(raw_annotation, dict):
69
+ raise ValueError(
70
+ f"COCO annotation file {annFile} must contain a JSON object."
71
+ )
72
+ self.raw_annotation = raw_annotation
73
+ self.coco = COCO(annFile)
74
+ if min_keypoints is None:
75
+ self.ids = list(sorted(self.coco.imgs.keys()))
76
+ else:
77
+ self.ids = list(
78
+ sorted(
79
+ {
80
+ ann["image_id"]
81
+ for ann in self.coco.anns.values()
82
+ if ann.get("num_keypoints", 0) > min_keypoints
83
+ }
84
+ )
85
+ )
86
+
87
+ def _load_image(self, image_id: int) -> np.ndarray:
88
+ """Load image by ID"""
89
+ file_name = self.coco.loadImgs(image_id)[0]["file_name"]
90
+ if not isinstance(file_name, str) or not file_name:
91
+ raise ValueError(f"COCO image ID {image_id} has an invalid file_name.")
92
+ relative_path = Path(file_name)
93
+ if relative_path.is_absolute() or ".." in relative_path.parts:
94
+ raise ValueError(
95
+ f"COCO image ID {image_id} has an unsafe file_name: {file_name!r}."
96
+ )
97
+ image_root = Path(self.root).resolve()
98
+ image_path = (image_root / relative_path).resolve()
99
+ try:
100
+ image_path.relative_to(image_root)
101
+ except ValueError as exc:
102
+ raise ValueError(
103
+ f"COCO image ID {image_id} resolves outside the image root: {file_name!r}."
104
+ ) from exc
105
+ image = cv2.imread(str(image_path)) # Load image (BGR format)
106
+
107
+ if image is None:
108
+ raise FileNotFoundError(f"Image not found: {image_path}")
109
+
110
+ return cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # Convert to RGB
111
+
112
+ def __getitem__(self, index: int) -> tuple[np.ndarray, int, int, int]:
113
+ """Get the image and target by index"""
114
+ image_id = self.ids[index]
115
+ image = self._load_image(image_id)
116
+ height = self.coco.imgs[image_id]["height"]
117
+ width = self.coco.imgs[image_id]["width"]
118
+ if (height, width) != image.shape[:2]:
119
+ raise ValueError(
120
+ "COCO annotation geometry does not match decoded image for "
121
+ f"image ID {image_id}: annotation {(height, width)}, "
122
+ f"image {image.shape[:2]}."
123
+ )
124
+ return image, index, height, width
125
+
126
+ def __len__(self) -> int:
127
+ """Return the total number of images"""
128
+ return len(self.ids)
129
+
130
+
131
+ CustomCocodata = CustomCOCODataset
132
+
133
+
134
+ def get_coco_loader(
135
+ dataset: CustomCOCODataset,
136
+ batch_size: int,
137
+ preprocess_fn: Callable,
138
+ ) -> torch.utils.data.DataLoader:
139
+ """Creates a DataLoader for the COCO dataset.
140
+
141
+ Args:
142
+ dataset (CustomCOCODataset): The dataset instance to load from.
143
+ batch_size (int): Number of samples per batch.
144
+ preprocess_fn (Callable): Function used to preprocess images.
145
+
146
+ Returns:
147
+ torch.utils.data.DataLoader: A configured DataLoader for the COCO dataset.
148
+ """
149
+
150
+ def loader(
151
+ batch: list[Any],
152
+ ) -> tuple[np.ndarray, np.ndarray, list[Any], tuple[int, ...]]:
153
+ """Collate function for COCO DataLoader."""
154
+ batch = list(filter(lambda x: x is not None, batch))
155
+ images, idx, height, width = zip(*batch)
156
+
157
+ processed_images = []
158
+ ratio_pads = []
159
+ for img in images:
160
+ processed = preprocess_fn(img)
161
+ if (
162
+ isinstance(processed, tuple)
163
+ and len(processed) == 2
164
+ and isinstance(processed[1], dict)
165
+ ):
166
+ processed_img, metadata = processed
167
+ ratio_pads.append(metadata.get("ratio_pad"))
168
+ else:
169
+ processed_img = processed
170
+ ratio_pads.append(None)
171
+ processed_images.append(processed_img)
172
+
173
+ height_arr = np.array(height)
174
+ width_arr = np.array(width)
175
+
176
+ return (
177
+ np.stack(processed_images, axis=0),
178
+ np.stack((height_arr, width_arr), axis=1),
179
+ ratio_pads,
180
+ idx,
181
+ )
182
+
183
+ return torch.utils.data.DataLoader(
184
+ dataset,
185
+ batch_size=batch_size,
186
+ shuffle=False,
187
+ num_workers=0,
188
+ collate_fn=loader,
189
+ )
190
+
191
+
192
+ class CustomNYUDepth(torch.utils.data.Dataset[tuple[np.ndarray, np.ndarray, str]]):
193
+ """NYU Depth V2 validation dataset with paired RGB images and ``.npy`` depth maps."""
194
+
195
+ IMG_EXTENSIONS = (".jpg", ".jpeg", ".png", ".bmp")
196
+
197
+ def __init__(self, root: str) -> None:
198
+ """Validate the organizer's ``images/`` and ``depth/`` validation-only layout."""
199
+
200
+ self.root = root
201
+ image_root, depth_root = (
202
+ os.path.join(root, "images"),
203
+ os.path.join(root, "depth"),
204
+ )
205
+ if not os.path.isdir(image_root) or not os.path.isdir(depth_root):
206
+ raise FileNotFoundError(
207
+ f"NYU Depth requires images/ and depth/ directories under: {root}"
208
+ )
209
+ images = _unique_paths_by_stem(
210
+ image_root, self.IMG_EXTENSIONS, "NYU Depth images"
211
+ )
212
+ depths = _unique_paths_by_stem(depth_root, (".npy",), "NYU Depth depth maps")
213
+ missing_depths, missing_images = (
214
+ sorted(set(images) - set(depths)),
215
+ sorted(set(depths) - set(images)),
216
+ )
217
+ if missing_depths or missing_images:
218
+ details = []
219
+ if missing_depths:
220
+ details.append(
221
+ f"images without depth maps: {', '.join(missing_depths[:5])}"
222
+ )
223
+ if missing_images:
224
+ details.append(
225
+ f"depth maps without images: {', '.join(missing_images[:5])}"
226
+ )
227
+ raise ValueError(f"NYU Depth image/depth mismatch ({'; '.join(details)}).")
228
+ if not images:
229
+ raise ValueError(f"NYU Depth contains no image/depth pairs: {root}")
230
+ self.samples = [(images[stem], depths[stem], stem) for stem in sorted(images)]
231
+
232
+ def __getitem__(self, index: int) -> tuple[np.ndarray, np.ndarray, str]:
233
+ """Load an RGB image and finite-safe depth target."""
234
+
235
+ image_path, depth_path, stem = self.samples[index]
236
+ image = cv2.imread(image_path)
237
+ if image is None:
238
+ raise FileNotFoundError(f"NYU Depth image not found: {image_path}")
239
+ raw_depth = np.load(depth_path, allow_pickle=False)
240
+ if not np.issubdtype(raw_depth.dtype, np.number) or np.issubdtype(
241
+ raw_depth.dtype, np.complexfloating
242
+ ):
243
+ raise ValueError(
244
+ "NYU Depth target must use a real numeric dtype, "
245
+ f"got {raw_depth.dtype}: {depth_path}"
246
+ )
247
+ depth = np.asarray(raw_depth, dtype=np.float32)
248
+ if depth.ndim != 2:
249
+ raise ValueError(
250
+ f"NYU Depth target must be two-dimensional, got {depth.shape}: {depth_path}"
251
+ )
252
+ if depth.shape != image.shape[:2]:
253
+ raise ValueError(
254
+ "NYU Depth image and target shapes must match for "
255
+ f"{stem}: image {image.shape[:2]}, depth {depth.shape}."
256
+ )
257
+ if not bool(np.isfinite(depth).all()):
258
+ raise ValueError(
259
+ f"NYU Depth target must contain only finite values: {depth_path}"
260
+ )
261
+ if bool((depth < 0).any()):
262
+ raise ValueError(
263
+ f"NYU Depth target must not contain negative values: {depth_path}"
264
+ )
265
+ return (
266
+ cv2.cvtColor(image, cv2.COLOR_BGR2RGB),
267
+ depth,
268
+ stem,
269
+ )
270
+
271
+ def __len__(self) -> int:
272
+ """Return the number of paired validation samples."""
273
+
274
+ return len(self.samples)
275
+
276
+
277
+ def get_nyu_depth_loader(
278
+ dataset: CustomNYUDepth,
279
+ batch_size: int,
280
+ preprocess_fn: Callable,
281
+ image_size: tuple[int, int] | None = None,
282
+ ) -> torch.utils.data.DataLoader:
283
+ """Create a NYU Depth loader with optional stretch-to-size validation preprocessing.
284
+
285
+ Args:
286
+ dataset: Paired NYU Depth validation dataset.
287
+ batch_size: Number of samples per batch.
288
+ preprocess_fn: Preprocessing applied after an optional validation resize.
289
+ image_size: Optional ``(height, width)`` used to stretch RGB inputs with bilinear
290
+ interpolation and depth targets with nearest-neighbor interpolation. This
291
+ matches the Ultralytics depth validation pipeline.
292
+
293
+ Returns:
294
+ Configured NYU Depth validation loader.
295
+ """
296
+
297
+ def loader(
298
+ batch: list[Any],
299
+ ) -> tuple[
300
+ np.ndarray, list[np.ndarray], list[tuple[int, int]], list[Any], tuple[str, ...]
301
+ ]:
302
+ images, targets, stems = zip(*batch)
303
+ processed_images, shapes, ratio_pads = [], [], []
304
+ processed_targets = []
305
+ for image, target in zip(images, targets):
306
+ if image_size is not None:
307
+ height, width = image_size
308
+ image = cv2.resize(
309
+ image, (width, height), interpolation=cv2.INTER_LINEAR
310
+ )
311
+ target = cv2.resize(
312
+ target, (width, height), interpolation=cv2.INTER_NEAREST
313
+ )
314
+ shapes.append(tuple(image.shape[:2]))
315
+ processed = preprocess_fn(image)
316
+ if (
317
+ isinstance(processed, tuple)
318
+ and len(processed) == 2
319
+ and isinstance(processed[1], dict)
320
+ ):
321
+ processed_image, metadata = processed
322
+ ratio_pads.append(metadata.get("ratio_pad"))
323
+ else:
324
+ processed_image = processed
325
+ ratio_pads.append(None)
326
+ processed_images.append(processed_image)
327
+ processed_targets.append(target)
328
+ return np.stack(processed_images), processed_targets, shapes, ratio_pads, stems
329
+
330
+ return torch.utils.data.DataLoader(
331
+ dataset, batch_size=batch_size, shuffle=False, num_workers=0, collate_fn=loader
332
+ )
333
+
334
+
335
+ class CustomADE20K(torch.utils.data.Dataset[tuple[np.ndarray, np.ndarray, str]]):
336
+ """ADE20K validation dataset with paired RGB images and semantic PNG masks."""
337
+
338
+ IMG_EXTENSIONS = (".jpg", ".jpeg", ".png", ".bmp")
339
+
340
+ def __init__(self, root: str) -> None:
341
+ """Validate the organizer's flat ``images/`` and ``annotations/`` layout."""
342
+
343
+ self.root = root
344
+ image_root = os.path.join(root, "images")
345
+ annotation_root = os.path.join(root, "annotations")
346
+ if not os.path.isdir(image_root) or not os.path.isdir(annotation_root):
347
+ raise FileNotFoundError(
348
+ f"ADE20K requires images/ and annotations/ directories under: {root}"
349
+ )
350
+ images = _unique_paths_by_stem(image_root, self.IMG_EXTENSIONS, "ADE20K images")
351
+ annotations = _unique_paths_by_stem(
352
+ annotation_root, (".png",), "ADE20K annotations"
353
+ )
354
+ missing_annotations = sorted(set(images) - set(annotations))
355
+ missing_images = sorted(set(annotations) - set(images))
356
+ if missing_annotations or missing_images:
357
+ details = []
358
+ if missing_annotations:
359
+ details.append(
360
+ f"images without annotations: {', '.join(missing_annotations[:5])}"
361
+ )
362
+ if missing_images:
363
+ details.append(
364
+ f"annotations without images: {', '.join(missing_images[:5])}"
365
+ )
366
+ raise ValueError(
367
+ f"ADE20K image/annotation mismatch ({'; '.join(details)})."
368
+ )
369
+ if not images:
370
+ raise ValueError(f"ADE20K contains no image/annotation pairs: {root}")
371
+ self.samples = [
372
+ (images[stem], annotations[stem], stem) for stem in sorted(images)
373
+ ]
374
+
375
+ def __getitem__(self, index: int) -> tuple[np.ndarray, np.ndarray, str]:
376
+ """Load one RGB image and map its source labels to model class IDs."""
377
+
378
+ image_path, annotation_path, stem = self.samples[index]
379
+ image = cv2.imread(image_path, cv2.IMREAD_COLOR)
380
+ if image is None:
381
+ raise FileNotFoundError(f"ADE20K image not found: {image_path}")
382
+ try:
383
+ with Image.open(annotation_path) as annotation_image:
384
+ annotation = np.asarray(annotation_image)
385
+ except OSError as exc:
386
+ raise FileNotFoundError(
387
+ f"ADE20K annotation not found: {annotation_path}"
388
+ ) from exc
389
+ if annotation.ndim != 2 or annotation.dtype != np.uint8:
390
+ raise ValueError(
391
+ "ADE20K annotations must be single-channel 8-bit PNG masks: "
392
+ f"{annotation_path}"
393
+ )
394
+ if image.shape[:2] != annotation.shape:
395
+ raise ValueError(
396
+ f"ADE20K image and annotation shapes must match, got {image.shape[:2]} and {annotation.shape}: {stem}"
397
+ )
398
+ if annotation.size and int(annotation.max()) > 150:
399
+ raise ValueError(
400
+ f"ADE20K annotation values must be in [0, 150]: {annotation_path}"
401
+ )
402
+ target = np.full(annotation.shape, 255, dtype=np.uint8)
403
+ valid = annotation > 0
404
+ target[valid] = annotation[valid] - 1
405
+ if not valid.any():
406
+ raise ValueError(
407
+ f"ADE20K annotation contains no evaluable class IDs: {annotation_path}"
408
+ )
409
+ return cv2.cvtColor(image, cv2.COLOR_BGR2RGB), target, stem
410
+
411
+ def __len__(self) -> int:
412
+ """Return the number of paired validation samples."""
413
+
414
+ return len(self.samples)
415
+
416
+
417
+ def get_ade20k_loader(
418
+ dataset: CustomADE20K,
419
+ batch_size: int,
420
+ preprocess_fn: Callable,
421
+ image_size: tuple[int, int],
422
+ ) -> torch.utils.data.DataLoader:
423
+ """Create an ADE20K loader that applies matching letterbox geometry to masks.
424
+
425
+ Args:
426
+ dataset: Paired ADE20K validation dataset.
427
+ batch_size: Number of samples per batch.
428
+ preprocess_fn: Image preprocessing function that returns letterbox metadata.
429
+ image_size: Configured model input size as ``(height, width)``.
430
+
431
+ Returns:
432
+ Configured ADE20K validation loader.
433
+ """
434
+
435
+ def loader(
436
+ batch: list[Any],
437
+ ) -> tuple[
438
+ np.ndarray, np.ndarray, list[tuple[int, int]], list[Any], tuple[str, ...]
439
+ ]:
440
+ images, targets, stems = zip(*batch)
441
+ processed_images, processed_targets, shapes, ratio_pads = [], [], [], []
442
+ input_height, input_width = image_size
443
+ for image, target in zip(images, targets):
444
+ shapes.append(tuple(image.shape[:2]))
445
+ processed = preprocess_fn(image)
446
+ if not (
447
+ isinstance(processed, tuple)
448
+ and len(processed) == 2
449
+ and isinstance(processed[1], dict)
450
+ ):
451
+ raise ValueError(
452
+ "ADE20K preprocessing must return image data and letterbox metadata."
453
+ )
454
+ processed_image, metadata = processed
455
+ ratio_pad = metadata.get("ratio_pad")
456
+ if ratio_pad is None:
457
+ raise ValueError(
458
+ "ADE20K preprocessing requires LetterBox ratio_pad metadata."
459
+ )
460
+ processed_target, target_ratio_pad = letterbox_semantic_mask(
461
+ target,
462
+ [input_height, input_width],
463
+ )
464
+ if target_ratio_pad != ratio_pad:
465
+ raise ValueError(
466
+ "ADE20K image and mask LetterBox geometry do not match."
467
+ )
468
+ processed_images.append(processed_image)
469
+ processed_targets.append(processed_target)
470
+ ratio_pads.append(ratio_pad)
471
+ return (
472
+ np.stack(processed_images),
473
+ np.stack(processed_targets),
474
+ shapes,
475
+ ratio_pads,
476
+ stems,
477
+ )
478
+
479
+ return torch.utils.data.DataLoader(
480
+ dataset, batch_size=batch_size, shuffle=False, num_workers=0, collate_fn=loader
481
+ )
482
+
483
+
484
+ class CustomCityscapes(torch.utils.data.Dataset[tuple[np.ndarray, np.ndarray, str]]):
485
+ """Cityscapes validation dataset with paired RGB images and source-ID masks."""
486
+
487
+ IMG_EXTENSIONS = (".jpg", ".jpeg", ".png", ".bmp")
488
+
489
+ def __init__(self, root: str) -> None:
490
+ """Validate the organizer's flat ``images/`` and ``annotations/`` layout."""
491
+
492
+ self.root = root
493
+ image_root = os.path.join(root, "images")
494
+ annotation_root = os.path.join(root, "annotations")
495
+ if not os.path.isdir(image_root) or not os.path.isdir(annotation_root):
496
+ raise FileNotFoundError(
497
+ f"Cityscapes requires images/ and annotations/ directories under: {root}"
498
+ )
499
+ images = _unique_paths_by_stem(
500
+ image_root, self.IMG_EXTENSIONS, "Cityscapes images"
501
+ )
502
+ annotations = _unique_paths_by_stem(
503
+ annotation_root, (".png",), "Cityscapes annotations"
504
+ )
505
+ missing_annotations = sorted(set(images) - set(annotations))
506
+ missing_images = sorted(set(annotations) - set(images))
507
+ if missing_annotations or missing_images:
508
+ details = []
509
+ if missing_annotations:
510
+ details.append(
511
+ f"images without annotations: {', '.join(missing_annotations[:5])}"
512
+ )
513
+ if missing_images:
514
+ details.append(
515
+ f"annotations without images: {', '.join(missing_images[:5])}"
516
+ )
517
+ raise ValueError(
518
+ f"Cityscapes image/annotation mismatch ({'; '.join(details)})."
519
+ )
520
+ if not images:
521
+ raise ValueError(f"Cityscapes contains no image/annotation pairs: {root}")
522
+ self.samples = [
523
+ (images[stem], annotations[stem], stem) for stem in sorted(images)
524
+ ]
525
+
526
+ def __getitem__(self, index: int) -> tuple[np.ndarray, np.ndarray, str]:
527
+ """Load an image and map Cityscapes source IDs to contiguous train IDs."""
528
+
529
+ image_path, annotation_path, stem = self.samples[index]
530
+ image = cv2.imread(image_path, cv2.IMREAD_COLOR)
531
+ if image is None:
532
+ raise FileNotFoundError(f"Cityscapes image not found: {image_path}")
533
+ with Image.open(annotation_path) as annotation_image:
534
+ annotation = np.asarray(annotation_image)
535
+ if annotation.ndim == 3:
536
+ if annotation.shape[2] not in {3, 4} or not np.array_equal(
537
+ annotation[..., 0], annotation[..., 1]
538
+ ):
539
+ raise ValueError(
540
+ f"Cityscapes RGB annotation channels must contain identical source IDs: {annotation_path}"
541
+ )
542
+ if not np.array_equal(annotation[..., 0], annotation[..., 2]):
543
+ raise ValueError(
544
+ f"Cityscapes RGB annotation channels must contain identical source IDs: {annotation_path}"
545
+ )
546
+ annotation = annotation[..., 0]
547
+ if annotation.ndim != 2:
548
+ raise ValueError(
549
+ f"Cityscapes annotation must be grayscale or RGB-grayscale: {annotation_path}"
550
+ )
551
+ if image.shape[:2] != annotation.shape:
552
+ raise ValueError(
553
+ "Cityscapes image and annotation shapes must match, "
554
+ f"got {image.shape[:2]} and {annotation.shape}: {stem}"
555
+ )
556
+ if annotation.size and (
557
+ int(annotation.min()) < 0 or int(annotation.max()) > 255
558
+ ):
559
+ raise ValueError(
560
+ f"Cityscapes annotation values must be in [0, 255]: {annotation_path}"
561
+ )
562
+ source_ids = np.unique(annotation.astype(np.uint8))
563
+ known_ids = np.array([*range(34), 255], dtype=np.uint8)
564
+ unknown_ids = source_ids[~np.isin(source_ids, known_ids)]
565
+ if unknown_ids.size:
566
+ raise ValueError(
567
+ "Cityscapes annotation contains unsupported source IDs "
568
+ f"{unknown_ids.tolist()}: {annotation_path}"
569
+ )
570
+ target = CITYSCAPES_SOURCE_TO_TRAIN_ID[annotation.astype(np.uint8)]
571
+ if not (target != 255).any():
572
+ raise ValueError(
573
+ f"Cityscapes annotation contains no evaluable class IDs: {annotation_path}"
574
+ )
575
+ return cv2.cvtColor(image, cv2.COLOR_BGR2RGB), target, stem
576
+
577
+ def __len__(self) -> int:
578
+ """Return the number of paired validation samples."""
579
+
580
+ return len(self.samples)
581
+
582
+
583
+ def get_cityscapes_loader(
584
+ dataset: CustomCityscapes,
585
+ batch_size: int,
586
+ preprocess_fn: Callable,
587
+ image_size: tuple[int, int],
588
+ ) -> torch.utils.data.DataLoader:
589
+ """Create a Cityscapes loader with image-matching letterbox geometry."""
590
+
591
+ def loader(
592
+ batch: list[Any],
593
+ ) -> tuple[
594
+ np.ndarray, np.ndarray, list[tuple[int, int]], list[Any], tuple[str, ...]
595
+ ]:
596
+ images, targets, stems = zip(*batch)
597
+ processed_images, processed_targets, shapes, ratio_pads = [], [], [], []
598
+ input_height, input_width = image_size
599
+ for image, target in zip(images, targets):
600
+ shapes.append(tuple(image.shape[:2]))
601
+ processed = preprocess_fn(image)
602
+ if not (
603
+ isinstance(processed, tuple)
604
+ and len(processed) == 2
605
+ and isinstance(processed[1], dict)
606
+ ):
607
+ raise ValueError(
608
+ "Cityscapes preprocessing must return image data and letterbox metadata."
609
+ )
610
+ processed_image, metadata = processed
611
+ ratio_pad = metadata.get("ratio_pad")
612
+ if ratio_pad is None:
613
+ raise ValueError(
614
+ "Cityscapes preprocessing requires LetterBox ratio_pad metadata."
615
+ )
616
+ processed_target, target_ratio_pad = letterbox_semantic_mask(
617
+ target,
618
+ [input_height, input_width],
619
+ )
620
+ if target_ratio_pad != ratio_pad:
621
+ raise ValueError(
622
+ "Cityscapes image and mask LetterBox geometry do not match."
623
+ )
624
+ processed_images.append(processed_image)
625
+ processed_targets.append(processed_target)
626
+ ratio_pads.append(ratio_pad)
627
+ return (
628
+ np.stack(processed_images),
629
+ np.stack(processed_targets),
630
+ shapes,
631
+ ratio_pads,
632
+ stems,
633
+ )
634
+
635
+ return torch.utils.data.DataLoader(
636
+ dataset, batch_size=batch_size, shuffle=False, num_workers=0, collate_fn=loader
637
+ )
638
+
639
+
640
+ class CustomDOTAv1(torch.utils.data.Dataset[tuple[np.ndarray, str, int, int]]):
641
+ """Custom DOTAv1 validation dataset for OBB evaluation.
642
+
643
+ Attributes:
644
+ root: DOTAv1 dataset root.
645
+ image_root: Directory containing validation images.
646
+ ids: Image IDs derived from file stems.
647
+ """
648
+
649
+ IMG_EXTENSIONS = (".jpg", ".jpeg", ".png", ".bmp", ".tif", ".tiff")
650
+
651
+ def __init__(self, root: str) -> None:
652
+ """Initializes the DOTAv1 validation dataset.
653
+
654
+ Args:
655
+ root: DOTAv1 root containing flat ``images/`` or legacy
656
+ ``images/val`` validation images.
657
+
658
+ Raises:
659
+ FileNotFoundError: If the validation image directory is missing.
660
+ ValueError: If neither supported layout contains validation images.
661
+ """
662
+ self.root = root
663
+ self.image_root = os.path.join(root, "images")
664
+ if not os.path.isdir(self.image_root):
665
+ raise FileNotFoundError(
666
+ f"DOTAv1 image directory not found: {self.image_root}"
667
+ )
668
+ self.image_paths = self._find_image_paths(self.image_root)
669
+ legacy_image_root = os.path.join(self.image_root, "val")
670
+ if not self.image_paths and os.path.isdir(legacy_image_root):
671
+ self.image_root = legacy_image_root
672
+ self.image_paths = self._find_image_paths(self.image_root)
673
+ if not self.image_paths:
674
+ raise ValueError(
675
+ f"DOTAv1 validation images not found directly under {os.path.join(root, 'images')} "
676
+ "or its legacy `val` subdirectory."
677
+ )
678
+ self.ids = [
679
+ os.path.splitext(os.path.basename(path))[0] for path in self.image_paths
680
+ ]
681
+ if len(self.ids) != len(set(self.ids)):
682
+ raise ValueError(
683
+ "DOTAv1 validation images contain duplicate filename stems."
684
+ )
685
+
686
+ def _find_image_paths(self, image_root: str) -> list[str]:
687
+ """Return supported image files directly under a DOTAv1 image directory."""
688
+
689
+ return [
690
+ os.path.join(image_root, file_name)
691
+ for file_name in sorted(os.listdir(image_root))
692
+ if file_name.lower().endswith(self.IMG_EXTENSIONS)
693
+ ]
694
+
695
+ def _load_image(self, image_path: str) -> np.ndarray:
696
+ """Load an image as RGB."""
697
+ image = cv2.imread(image_path)
698
+ if image is None:
699
+ raise FileNotFoundError(f"Image not found: {image_path}")
700
+ return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
701
+
702
+ def __getitem__(self, index: int) -> tuple[np.ndarray, str, int, int]:
703
+ """Get the image and metadata by index."""
704
+ image_path = self.image_paths[index]
705
+ image = self._load_image(image_path)
706
+ height, width = image.shape[:2]
707
+ return image, self.ids[index], height, width
708
+
709
+ def __len__(self) -> int:
710
+ """Return the number of validation images."""
711
+ return len(self.image_paths)
712
+
713
+
714
+ def get_dota_loader(
715
+ dataset: CustomDOTAv1, batch_size: int, preprocess_fn: Callable
716
+ ) -> torch.utils.data.DataLoader:
717
+ """Creates a DataLoader for DOTAv1 validation.
718
+
719
+ Args:
720
+ dataset: The DOTAv1 dataset instance.
721
+ batch_size: Number of samples per batch.
722
+ preprocess_fn: Function used to preprocess images.
723
+
724
+ Returns:
725
+ Configured DataLoader for DOTAv1.
726
+ """
727
+
728
+ def loader(
729
+ batch: list[Any],
730
+ ) -> tuple[np.ndarray, np.ndarray, list[Any], tuple[str, ...]]:
731
+ """Collate function for DOTAv1 DataLoader."""
732
+ batch = list(filter(lambda x: x is not None, batch))
733
+ images, image_ids, height, width = zip(*batch)
734
+
735
+ processed_images = []
736
+ ratio_pads = []
737
+ for img in images:
738
+ processed = preprocess_fn(img)
739
+ if (
740
+ isinstance(processed, tuple)
741
+ and len(processed) == 2
742
+ and isinstance(processed[1], dict)
743
+ ):
744
+ processed_img, metadata = processed
745
+ ratio_pads.append(metadata.get("ratio_pad"))
746
+ else:
747
+ processed_img = processed
748
+ ratio_pads.append(None)
749
+ processed_images.append(processed_img)
750
+
751
+ return (
752
+ np.stack(processed_images, axis=0),
753
+ np.stack((np.array(height), np.array(width)), axis=1),
754
+ ratio_pads,
755
+ image_ids,
756
+ )
757
+
758
+ return torch.utils.data.DataLoader(
759
+ dataset,
760
+ batch_size=batch_size,
761
+ shuffle=False,
762
+ num_workers=0,
763
+ collate_fn=loader,
764
+ )
765
+
766
+
767
+ class CustomImageFolder(torch.utils.data.Dataset[tuple[Image.Image, int]]):
768
+ """Custom ImageFolder dataset for loading images from class-based directory structures.
769
+
770
+ Expects data to be organized in the format: root/class_name/image.jpg.
771
+
772
+ Attributes:
773
+ root (str): Root directory path.
774
+ classes (list[str]): List of class names found in the root directory.
775
+ class_to_idx (dict): Mapping from class name to class index.
776
+ samples (list[tuple]): List of (image_path, class_index) tuples.
777
+ """
778
+
779
+ def __init__(self, root: str) -> None:
780
+ """Initializes the CustomImageFolder instance.
781
+
782
+ Args:
783
+ root (str): Path to the root directory.
784
+ """
785
+ self.root = root
786
+ self.classes, self.class_to_idx = self.find_classes(root)
787
+ self.samples: list[tuple[str, int]] = []
788
+ self.make_dataset()
789
+
790
+ def make_dataset(self) -> None:
791
+ """Scans the root directory to create a list of samples."""
792
+ instances = []
793
+ for target_class in sorted(self.class_to_idx.keys()):
794
+ class_index = self.class_to_idx[target_class]
795
+ target_dir = os.path.join(self.root, target_class)
796
+ if not os.path.isdir(target_dir):
797
+ continue
798
+ for fname in sorted(os.listdir(target_dir)):
799
+ path = os.path.join(target_dir, fname)
800
+ if not os.path.isfile(path):
801
+ continue
802
+ if os.path.splitext(fname)[1].lower() not in IMAGE_SUFFIXES:
803
+ continue
804
+ instances.append((path, class_index))
805
+
806
+ self.samples = instances
807
+
808
+ def loader(self, path: str) -> Image.Image:
809
+ """Load image from path using PIL."""
810
+ with open(path, "rb") as f:
811
+ img = Image.open(f)
812
+ return img.convert("RGB")
813
+
814
+ def find_classes(self, directory: str) -> tuple[list[str], dict[str, int]]:
815
+ """Find classes in the specified directory."""
816
+ classes = sorted([d.name for d in os.scandir(directory) if d.is_dir()])
817
+ class_to_idx = {cls: i for i, cls in enumerate(classes)}
818
+ return classes, class_to_idx
819
+
820
+ def __getitem__(self, index: int) -> tuple[Image.Image, int]:
821
+ """
822
+ Get sample and target at the specified index.
823
+ Args:
824
+ index (int): Index of the sample to retrieve.
825
+ Returns:
826
+ tuple: (sample, target) where sample is the loaded image and target is the class index.
827
+ """
828
+ path, target = self.samples[index]
829
+ sample = self.loader(path)
830
+ return sample, target
831
+
832
+ def __len__(self) -> int:
833
+ """
834
+ Return the total number of samples.
835
+ Returns:
836
+ int: Number of samples in the dataset.
837
+ """
838
+ return len(self.samples)
839
+
840
+
841
+ def get_imagenet_loader(
842
+ dataset: CustomImageFolder, batch_size: int, preprocess_fn: Callable
843
+ ) -> torch.utils.data.DataLoader:
844
+ """Creates a DataLoader for the ImageNet dataset.
845
+
846
+ Args:
847
+ dataset (CustomImageFolder): The dataset instance to load from.
848
+ batch_size (int): Number of samples per batch.
849
+ preprocess_fn (Callable): Function used to preprocess images.
850
+
851
+ Returns:
852
+ torch.utils.data.DataLoader: A configured DataLoader for the ImageNet dataset.
853
+ """
854
+
855
+ def loader(batch: list[Any]) -> tuple[np.ndarray, np.ndarray]:
856
+ """Collate function for ImageNet DataLoader."""
857
+ batch = list(filter(lambda x: x is not None, batch)) # remove None
858
+ images, labels = zip(*batch)
859
+ processed_images = []
860
+ for img in images:
861
+ img = preprocess_fn(img)
862
+ processed_images.append(img)
863
+
864
+ return (
865
+ np.stack(processed_images, axis=0),
866
+ np.array(labels),
867
+ ) # BHWC, labels
868
+
869
+ return torch.utils.data.DataLoader(
870
+ dataset,
871
+ batch_size=batch_size,
872
+ shuffle=False,
873
+ num_workers=0,
874
+ collate_fn=loader,
875
+ )
876
+
877
+
878
+ class CustomWiderFaceDataset(torch.utils.data.Dataset[tuple[np.ndarray, str, str]]):
879
+ """Custom dataset class for the WiderFace dataset.
880
+
881
+ Attributes:
882
+ root (str): Path to the root directory containing WiderFace images.
883
+ classes (list[str]): List of class/event names found in the root.
884
+ samples (list[tuple]): List of (image_path, class_name, file_name) tuples.
885
+ """
886
+
887
+ def __init__(self, root: str) -> None:
888
+ """Initialize the custom WiderFace dataset.
889
+
890
+ Args:
891
+ root (str): Path to the directory containing WiderFace images.
892
+ """
893
+ self.root = root
894
+ self.classes = self.find_classes(root)
895
+ self.samples: list[tuple[str, str, str]] = []
896
+ self.make_dataset()
897
+
898
+ def make_dataset(self) -> None:
899
+ """Scans the root directory to create a list of samples."""
900
+ instances = []
901
+ for target_class in self.classes:
902
+ target_dir = os.path.join(self.root, target_class)
903
+ if not os.path.isdir(target_dir):
904
+ continue
905
+ for fname in sorted(os.listdir(target_dir)):
906
+ path = os.path.join(target_dir, fname)
907
+ if (
908
+ os.path.islink(path)
909
+ or not os.path.isfile(path)
910
+ or os.path.splitext(fname)[1].lower() not in IMAGE_SUFFIXES
911
+ ):
912
+ continue
913
+ instances.append((path, target_class, fname))
914
+
915
+ self.samples = instances
916
+
917
+ def loader(self, image_path: str) -> np.ndarray:
918
+ """Load image by image path"""
919
+ image = cv2.imread(image_path) # Load image (BGR format)
920
+ if image is None:
921
+ raise FileNotFoundError(f"Image not found: {image_path}")
922
+ return cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # Convert to RGB
923
+
924
+ def find_classes(self, directory: str) -> list[str]:
925
+ """Find classes in the specified directory."""
926
+ unsorted_classes = [d.name for d in os.scandir(directory) if d.is_dir()]
927
+ class_to_idx = {}
928
+ for cls_name in unsorted_classes:
929
+ cls_idx = int(cls_name.split("--")[0])
930
+ class_to_idx[cls_name] = cls_idx
931
+
932
+ sorted_classes = sorted(
933
+ class_to_idx.keys(), key=lambda x: class_to_idx[x]
934
+ ) # sort by dictionary value with ascending order
935
+
936
+ return sorted_classes
937
+
938
+ def __getitem__(self, index: int) -> tuple[np.ndarray, str, str]:
939
+ """
940
+ Get the image and target by index.
941
+ Args:
942
+ index (int): Index of the sample to retrieve.
943
+ Returns:
944
+ tuple: (image, target_class, fname) where image is the loaded image in RGB format.
945
+ """
946
+ image_path, target_class, fname = self.samples[index]
947
+ image = self.loader(image_path)
948
+
949
+ return image, target_class, fname
950
+
951
+ def __len__(self) -> int:
952
+ """
953
+ Return the total number of images.
954
+ Returns:
955
+ int: Number of images in the dataset.
956
+ """
957
+ return len(self.samples)
958
+
959
+
960
+ CustomWiderface = CustomWiderFaceDataset
961
+
962
+
963
+ def get_widerface_loader(
964
+ dataset: CustomWiderFaceDataset, batch_size: int, preprocess_fn: Callable
965
+ ) -> torch.utils.data.DataLoader:
966
+ """Creates a DataLoader for the WiderFace dataset.
967
+
968
+ Args:
969
+ dataset (CustomWiderFaceDataset): The dataset instance to load from.
970
+ batch_size (int): Number of samples per batch.
971
+ preprocess_fn (Callable): Function used to preprocess images.
972
+
973
+ Returns:
974
+ torch.utils.data.DataLoader: A configured DataLoader for the WiderFace dataset.
975
+ """
976
+
977
+ def loader(
978
+ batch: list[Any],
979
+ ) -> tuple[
980
+ np.ndarray, np.ndarray, list[Any | None], tuple[str, ...], tuple[str, ...]
981
+ ]:
982
+ """Collate function for WiderFace DataLoader."""
983
+ batch = list(filter(lambda x: x is not None, batch))
984
+ images, target_classes, fnames = zip(*batch)
985
+ processed_images = []
986
+ heights = []
987
+ widths = []
988
+ ratio_pads = []
989
+ for img in images:
990
+ height, width = img.shape[:2]
991
+ processed = preprocess_fn(img)
992
+ if isinstance(processed, tuple):
993
+ processed_img, metadata = processed
994
+ ratio_pads.append(metadata.get("ratio_pad"))
995
+ else:
996
+ processed_img = processed
997
+ ratio_pads.append(None)
998
+ processed_images.append(processed_img)
999
+ heights.append(height)
1000
+ widths.append(width)
1001
+
1002
+ return (
1003
+ np.stack(processed_images, axis=0),
1004
+ np.stack((heights, widths), axis=1),
1005
+ ratio_pads,
1006
+ target_classes,
1007
+ fnames,
1008
+ )
1009
+
1010
+ return torch.utils.data.DataLoader(
1011
+ dataset,
1012
+ batch_size=batch_size,
1013
+ shuffle=False,
1014
+ num_workers=0,
1015
+ collate_fn=loader,
1016
+ )