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,1063 @@
1
+ """Identity and completeness checks for organized vision validation datasets."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import json
7
+ import math
8
+ import os
9
+ import re
10
+ from importlib.resources import files
11
+ from pathlib import Path
12
+ from typing import Any
13
+
14
+ import numpy as np
15
+ from faster_coco_eval import mask as coco_mask
16
+ from PIL import Image
17
+ from scipy.io import loadmat
18
+ from scipy.io.matlab import MatReadError
19
+
20
+ from ..._tasks import normalize_vision_task
21
+ from ...datasets import get_dataset_category_ids
22
+ from .cityscapes import CITYSCAPES_SOURCE_TO_TRAIN_ID
23
+
24
+ IMAGE_SUFFIXES = {".bmp", ".jpeg", ".jpg", ".png", ".tif", ".tiff", ".webp"}
25
+ IMAGENET_CLASS_COUNT = 1000
26
+ IMAGENET_IMAGES_PER_CLASS = 50
27
+ COCO_VALIDATION_SAMPLE_COUNT = 5000
28
+ DOTAV1_VALIDATION_SAMPLE_COUNT = 458
29
+ WIDERFACE_EVENT_COUNT = 61
30
+ WIDERFACE_VALIDATION_SAMPLE_COUNT = 3226
31
+ NYU_DEPTH_VALIDATION_SAMPLE_COUNT = 654
32
+ ADE20K_VALIDATION_SAMPLE_COUNT = 2000
33
+ CITYSCAPES_VALIDATION_SAMPLE_COUNT = 500
34
+ ADE20K_METADATA_FILES = ("objectInfo150.txt", "sceneCategories.txt")
35
+ IMAGENET_CLASS_PATTERN = re.compile(r"n\d{8}")
36
+ IMAGENET_IMAGE_PATTERN = re.compile(r"ILSVRC2012_val_\d{8}")
37
+ COCO_IMAGE_PATTERN = re.compile(r"\d{12}")
38
+ WIDERFACE_EVENT_PATTERN = re.compile(r"\d+--\S.*")
39
+ CITYSCAPES_SAMPLE_ID_PATTERN = re.compile(
40
+ r"^(?P<city>[A-Za-z][A-Za-z0-9-]*)_\d{6}_\d{6}$"
41
+ )
42
+ CITYSCAPES_VALIDATION_CITY_COUNTS = {"frankfurt": 267, "lindau": 59, "munster": 174}
43
+ IMAGENET_SYNSET_ORDER = tuple(
44
+ files("mblt_vision.datasets")
45
+ .joinpath("imagenet_synsets.txt")
46
+ .read_text(encoding="utf-8")
47
+ .splitlines()
48
+ )
49
+ IMAGENET_SYNSETS = frozenset(IMAGENET_SYNSET_ORDER)
50
+ COCO_ANNOTATION_COUNTS = {
51
+ "instances_val2017.json": 36781,
52
+ "person_keypoints_val2017.json": 11004,
53
+ }
54
+ COCO_CATEGORY_COUNTS = {
55
+ "instances_val2017.json": 80,
56
+ "person_keypoints_val2017.json": 1,
57
+ }
58
+ COCO_CATEGORY_IDS = frozenset(get_dataset_category_ids("coco"))
59
+ COCO_PERSON_KEYPOINT_CATEGORY_IDS = frozenset({1})
60
+ COCO_VALIDATION_IMAGE_IDENTITIES_SHA256 = (
61
+ "f57f71ba25171a0fd99be8c425a91d4a6fdd43d25aadc7e5be51dd37a73281a7"
62
+ )
63
+
64
+
65
+ def _path_has_symlink_component(path: Path) -> bool:
66
+ """Return whether a path traversal or its normalized ancestors contain a symlink."""
67
+
68
+ expanded_path = path.expanduser()
69
+ traversal_path = (
70
+ expanded_path if expanded_path.is_absolute() else Path.cwd() / expanded_path
71
+ )
72
+ normalized_path = Path(os.path.abspath(expanded_path))
73
+ candidates = (
74
+ traversal_path,
75
+ *traversal_path.parents,
76
+ normalized_path,
77
+ *normalized_path.parents,
78
+ )
79
+ return any(component.is_symlink() for component in candidates)
80
+
81
+
82
+ def _files_by_stem(
83
+ directory: Path,
84
+ suffixes: set[str],
85
+ *,
86
+ reject_symlinks: bool = False,
87
+ ) -> dict[str, Path] | None:
88
+ """Collect direct child files with supported suffixes by stem.
89
+
90
+ Args:
91
+ directory: Directory containing candidate files.
92
+ suffixes: Accepted lowercase file suffixes.
93
+ reject_symlinks: Whether any symlinked directory or entry invalidates
94
+ the file collection.
95
+
96
+ Returns:
97
+ Files keyed by stem, an empty mapping for a missing directory, or
98
+ ``None`` for duplicate stems or rejected symlinks.
99
+ """
100
+
101
+ if (reject_symlinks and directory.is_symlink()) or not directory.is_dir():
102
+ return {}
103
+ entries = list(directory.iterdir())
104
+ if reject_symlinks and any(path.is_symlink() for path in entries):
105
+ return None
106
+ paths = [
107
+ path for path in entries if path.is_file() and path.suffix.lower() in suffixes
108
+ ]
109
+ files = {path.stem: path for path in paths}
110
+ return files if len(files) == len(paths) else None
111
+
112
+
113
+ def _has_positive_polygon_area(polygon: list[int | float]) -> bool:
114
+ """Return whether a finite flat polygon encloses non-zero signed area."""
115
+
116
+ points = np.asarray(polygon, dtype=np.float64).reshape(-1, 2)
117
+ signed_double_area = np.dot(points[:, 0], np.roll(points[:, 1], -1)) - np.dot(
118
+ points[:, 1], np.roll(points[:, 0], -1)
119
+ )
120
+ return bool(abs(signed_double_area) > 0)
121
+
122
+
123
+ def _canonicalize_quadrilateral(
124
+ coordinates: list[int | float] | tuple[int | float, ...],
125
+ ) -> tuple[float, ...]:
126
+ """Return a quadrilateral key independent of its start vertex and winding."""
127
+
128
+ if len(coordinates) != 8:
129
+ raise ValueError(
130
+ "A quadrilateral must contain exactly four two-dimensional vertices."
131
+ )
132
+ points = tuple(
133
+ (float(coordinates[index]), float(coordinates[index + 1]))
134
+ for index in range(0, len(coordinates), 2)
135
+ )
136
+ candidates = []
137
+ for winding in (points, tuple(reversed(points))):
138
+ candidates.extend(winding[index:] + winding[:index] for index in range(4))
139
+ return tuple(coordinate for point in min(candidates) for coordinate in point)
140
+
141
+
142
+ def _polygon_has_positive_image_overlap(
143
+ polygon: list[int | float], image_shape: tuple[int, int] | None
144
+ ) -> bool:
145
+ """Return whether a polygon covers non-zero area within an image rectangle."""
146
+
147
+ if image_shape is None:
148
+ return True
149
+ height, width = image_shape
150
+ if height <= 0 or width <= 0:
151
+ return False
152
+ points = [
153
+ tuple(point) for point in np.asarray(polygon, dtype=np.float64).reshape(-1, 2)
154
+ ]
155
+
156
+ def _clip(
157
+ vertices: list[tuple[float, float]],
158
+ inside: Any,
159
+ intersect: Any,
160
+ ) -> list[tuple[float, float]]:
161
+ clipped: list[tuple[float, float]] = []
162
+ if not vertices:
163
+ return clipped
164
+ previous = vertices[-1]
165
+ previous_inside = bool(inside(previous))
166
+ for current in vertices:
167
+ current_inside = bool(inside(current))
168
+ if current_inside != previous_inside:
169
+ clipped.append(intersect(previous, current))
170
+ if current_inside:
171
+ clipped.append(current)
172
+ previous = current
173
+ previous_inside = current_inside
174
+ return clipped
175
+
176
+ def _vertical_intersection(
177
+ x: float, start: tuple[float, float], end: tuple[float, float]
178
+ ) -> tuple[float, float]:
179
+ delta_x = end[0] - start[0]
180
+ if delta_x == 0:
181
+ return x, start[1]
182
+ ratio = (x - start[0]) / delta_x
183
+ return x, start[1] + ratio * (end[1] - start[1])
184
+
185
+ def _horizontal_intersection(
186
+ y: float, start: tuple[float, float], end: tuple[float, float]
187
+ ) -> tuple[float, float]:
188
+ delta_y = end[1] - start[1]
189
+ if delta_y == 0:
190
+ return start[0], y
191
+ ratio = (y - start[1]) / delta_y
192
+ return start[0] + ratio * (end[0] - start[0]), y
193
+
194
+ points = _clip(
195
+ points,
196
+ lambda point: point[0] >= 0,
197
+ lambda a, b: _vertical_intersection(0, a, b),
198
+ )
199
+ points = _clip(
200
+ points,
201
+ lambda point: point[0] <= width,
202
+ lambda a, b: _vertical_intersection(width, a, b),
203
+ )
204
+ points = _clip(
205
+ points,
206
+ lambda point: point[1] >= 0,
207
+ lambda a, b: _horizontal_intersection(0, a, b),
208
+ )
209
+ points = _clip(
210
+ points,
211
+ lambda point: point[1] <= height,
212
+ lambda a, b: _horizontal_intersection(height, a, b),
213
+ )
214
+ if len(points) < 3:
215
+ return False
216
+ clipped = [coordinate for point in points for coordinate in point]
217
+ return _has_positive_polygon_area(clipped)
218
+
219
+
220
+ def _imagenet_ready(root: Path) -> bool:
221
+ """Check the organizer's complete ImageNet-1k validation class tree."""
222
+
223
+ if not root.is_dir():
224
+ return False
225
+ class_dirs = [path for path in root.iterdir() if path.is_dir()]
226
+ if {path.name for path in class_dirs} != IMAGENET_SYNSETS:
227
+ return False
228
+ image_names: set[str] = set()
229
+ for class_dir in class_dirs:
230
+ if IMAGENET_CLASS_PATTERN.fullmatch(class_dir.name) is None:
231
+ return False
232
+ images = [
233
+ path
234
+ for path in class_dir.iterdir()
235
+ if path.is_file() and path.suffix.lower() in IMAGE_SUFFIXES
236
+ ]
237
+ if len(images) != IMAGENET_IMAGES_PER_CLASS or any(
238
+ path.suffix != ".JPEG"
239
+ or IMAGENET_IMAGE_PATTERN.fullmatch(path.stem) is None
240
+ for path in images
241
+ ):
242
+ return False
243
+ image_names.update(path.name for path in images)
244
+ return len(image_names) == IMAGENET_CLASS_COUNT * IMAGENET_IMAGES_PER_CLASS
245
+
246
+
247
+ def _load_coco_image_names(
248
+ annotation_path: Path, task: str = "object_detection"
249
+ ) -> set[str] | None:
250
+ """Load unique validation image filenames from a COCO annotation file."""
251
+
252
+ try:
253
+ annotation: Any = json.loads(annotation_path.read_text(encoding="utf-8"))
254
+ except (json.JSONDecodeError, OSError, UnicodeError):
255
+ return None
256
+ if not isinstance(annotation, dict):
257
+ return None
258
+ image_records = annotation.get("images")
259
+ if (
260
+ not isinstance(image_records, list)
261
+ or len(image_records) != COCO_VALIDATION_SAMPLE_COUNT
262
+ ):
263
+ return None
264
+ names: list[str] = []
265
+ image_ids: list[int] = []
266
+ image_shapes: dict[int, tuple[int, int] | None] = {}
267
+ for record in image_records:
268
+ if not isinstance(record, dict):
269
+ continue
270
+ file_name = record.get("file_name")
271
+ image_id = record.get("id")
272
+ if (
273
+ isinstance(file_name, str)
274
+ and isinstance(image_id, int)
275
+ and not isinstance(image_id, bool)
276
+ ):
277
+ names.append(file_name)
278
+ image_ids.append(image_id)
279
+ height, width = record.get("height"), record.get("width")
280
+ if (
281
+ isinstance(height, int)
282
+ and not isinstance(height, bool)
283
+ and height > 0
284
+ and isinstance(width, int)
285
+ and not isinstance(width, bool)
286
+ and width > 0
287
+ ):
288
+ image_shapes[image_id] = (height, width)
289
+ else:
290
+ return None
291
+ if (
292
+ len(names) != len(image_records)
293
+ or len(names) != len(set(names))
294
+ or len(image_ids) != len(set(image_ids))
295
+ ):
296
+ return None
297
+ if len(image_records) == 5000:
298
+ identity_payload = "".join(
299
+ f"{image_id}:{file_name}\n"
300
+ for image_id, file_name in sorted(zip(image_ids, names, strict=True))
301
+ ).encode()
302
+ if (
303
+ hashlib.sha256(identity_payload).hexdigest()
304
+ != COCO_VALIDATION_IMAGE_IDENTITIES_SHA256
305
+ ):
306
+ return None
307
+ annotation_records = annotation.get("annotations")
308
+ categories = annotation.get("categories")
309
+ expected_annotations = COCO_ANNOTATION_COUNTS.get(annotation_path.name)
310
+ expected_categories = COCO_CATEGORY_COUNTS.get(annotation_path.name)
311
+ if (
312
+ not isinstance(annotation_records, list)
313
+ or not isinstance(categories, list)
314
+ or len(annotation_records) != expected_annotations
315
+ or len(categories) != expected_categories
316
+ ):
317
+ return None
318
+ category_ids: list[int] = []
319
+ for category in categories:
320
+ if not isinstance(category, dict):
321
+ return None
322
+ category_id = category.get("id")
323
+ if not isinstance(category_id, int) or isinstance(category_id, bool):
324
+ return None
325
+ category_ids.append(category_id)
326
+ if len(category_ids) != len(set(category_ids)):
327
+ return None
328
+ expected_category_ids = (
329
+ COCO_PERSON_KEYPOINT_CATEGORY_IDS
330
+ if annotation_path.name == "person_keypoints_val2017.json"
331
+ else COCO_CATEGORY_IDS
332
+ )
333
+ if set(category_ids) != expected_category_ids:
334
+ return None
335
+ if not _coco_task_annotations_valid(
336
+ annotation_records,
337
+ image_ids=set(image_ids),
338
+ category_ids=set(category_ids),
339
+ image_shapes=image_shapes,
340
+ task=task,
341
+ ):
342
+ return None
343
+ return set(names)
344
+
345
+
346
+ def _coco_task_annotations_valid(
347
+ annotation_records: list[Any],
348
+ *,
349
+ image_ids: set[int],
350
+ category_ids: set[int],
351
+ image_shapes: dict[int, tuple[int, int] | None],
352
+ task: str,
353
+ ) -> bool:
354
+ """Validate task-specific COCO annotation payloads for readiness and APIs."""
355
+
356
+ annotation_ids: list[int] = []
357
+ for record in annotation_records:
358
+ if not isinstance(record, dict):
359
+ return False
360
+ annotation_id = record.get("id")
361
+ image_id = record.get("image_id")
362
+ category_id = record.get("category_id")
363
+ if (
364
+ not isinstance(annotation_id, int)
365
+ or isinstance(annotation_id, bool)
366
+ or not isinstance(image_id, int)
367
+ or isinstance(image_id, bool)
368
+ or image_id not in image_ids
369
+ or not isinstance(category_id, int)
370
+ or isinstance(category_id, bool)
371
+ or category_id not in category_ids
372
+ ):
373
+ return False
374
+ image_shape = image_shapes.get(image_id)
375
+ if image_shape is None:
376
+ return False
377
+ image_height, image_width = image_shape
378
+ bbox = record.get("bbox")
379
+ if (
380
+ not isinstance(bbox, list)
381
+ or len(bbox) != 4
382
+ or any(
383
+ not isinstance(value, (int, float))
384
+ or isinstance(value, bool)
385
+ or not np.isfinite(value)
386
+ for value in bbox
387
+ )
388
+ or bbox[2] <= 0
389
+ or bbox[3] <= 0
390
+ or bbox[0] >= image_width
391
+ or bbox[0] + bbox[2] <= 0
392
+ or bbox[1] >= image_height
393
+ or bbox[1] + bbox[3] <= 0
394
+ ):
395
+ return False
396
+ area = record.get("area")
397
+ iscrowd = record.get("iscrowd")
398
+ if (
399
+ not isinstance(area, (int, float))
400
+ or isinstance(area, bool)
401
+ or not np.isfinite(area)
402
+ or area <= 0
403
+ or area > image_height * image_width
404
+ or not isinstance(iscrowd, int)
405
+ or isinstance(iscrowd, bool)
406
+ or iscrowd not in {0, 1}
407
+ ):
408
+ return False
409
+ if task == "pose_estimation" and area > bbox[2] * bbox[3]:
410
+ return False
411
+ if task == "instance_segmentation":
412
+ segmentation = record.get("segmentation")
413
+ if isinstance(segmentation, list):
414
+ if not segmentation or any(
415
+ not isinstance(polygon, list)
416
+ or len(polygon) < 6
417
+ or len(polygon) % 2
418
+ or any(
419
+ not isinstance(value, (int, float))
420
+ or isinstance(value, bool)
421
+ or not np.isfinite(value)
422
+ for value in polygon
423
+ )
424
+ or not _has_positive_polygon_area(polygon)
425
+ or not _polygon_has_positive_image_overlap(
426
+ polygon, image_shapes.get(image_id)
427
+ )
428
+ or not _valid_coco_polygon(polygon, image_shapes.get(image_id))
429
+ for polygon in segmentation
430
+ ):
431
+ return False
432
+ elif isinstance(segmentation, dict):
433
+ if not _valid_coco_rle(segmentation, image_shapes.get(image_id)):
434
+ return False
435
+ else:
436
+ return False
437
+ if task == "pose_estimation":
438
+ keypoints = record.get("keypoints")
439
+ num_keypoints = record.get("num_keypoints")
440
+ if (
441
+ not isinstance(keypoints, list)
442
+ or len(keypoints) != 51
443
+ or any(
444
+ not isinstance(value, (int, float))
445
+ or isinstance(value, bool)
446
+ or not np.isfinite(value)
447
+ for value in keypoints
448
+ )
449
+ or not isinstance(num_keypoints, int)
450
+ or isinstance(num_keypoints, bool)
451
+ or not 0 <= num_keypoints <= 17
452
+ or any(
453
+ keypoints[index] not in {0, 1, 2}
454
+ for index in range(2, len(keypoints), 3)
455
+ )
456
+ or num_keypoints
457
+ != sum(keypoints[index] > 0 for index in range(2, len(keypoints), 3))
458
+ ):
459
+ return False
460
+ height, width = image_shape
461
+ if any(
462
+ keypoints[index + 2] > 0
463
+ and not (
464
+ 0 <= keypoints[index] < width and 0 <= keypoints[index + 1] < height
465
+ )
466
+ for index in range(0, len(keypoints), 3)
467
+ ):
468
+ return False
469
+ annotation_ids.append(annotation_id)
470
+ return len(annotation_ids) == len(set(annotation_ids))
471
+
472
+
473
+ def _decode_coco_rle_counts(counts: str) -> list[int] | None:
474
+ """Decode COCO's compact RLE run-length string without trusting its payload."""
475
+
476
+ run_counts: list[int] = []
477
+ position = 0
478
+ while position < len(counts):
479
+ value = 0
480
+ shift = 0
481
+ more = True
482
+ while more:
483
+ if position >= len(counts):
484
+ return None
485
+ code = ord(counts[position]) - 48
486
+ position += 1
487
+ if not 0 <= code <= 0x3F:
488
+ return None
489
+ value |= (code & 0x1F) << shift
490
+ more = bool(code & 0x20)
491
+ shift += 5
492
+ if shift > 60:
493
+ return None
494
+ if not more and code & 0x10:
495
+ value |= -1 << shift
496
+ if len(run_counts) > 2:
497
+ value += run_counts[-2]
498
+ if value < 0:
499
+ return None
500
+ run_counts.append(value)
501
+ return run_counts
502
+
503
+
504
+ def _valid_coco_rle(
505
+ segmentation: dict[str, Any], image_shape: tuple[int, int] | None
506
+ ) -> bool:
507
+ """Validate and decode an RLE mask against its referenced COCO image shape."""
508
+
509
+ counts = segmentation.get("counts")
510
+ size = segmentation.get("size")
511
+ if (
512
+ image_shape is None
513
+ or not isinstance(size, list)
514
+ or len(size) != 2
515
+ or any(
516
+ not isinstance(value, int) or isinstance(value, bool) or value <= 0
517
+ for value in size
518
+ )
519
+ or tuple(size) != image_shape
520
+ or not isinstance(counts, (str, list))
521
+ ):
522
+ return False
523
+ if isinstance(counts, list):
524
+ if any(
525
+ not isinstance(value, int) or isinstance(value, bool) or value < 0
526
+ for value in counts
527
+ ):
528
+ return False
529
+ run_counts = counts
530
+ else:
531
+ run_counts = _decode_coco_rle_counts(counts)
532
+ if run_counts is None:
533
+ return False
534
+ if sum(run_counts) != math.prod(size):
535
+ return False
536
+ try:
537
+ encoded = (
538
+ coco_mask.frPyObjects(segmentation, size[0], size[1])
539
+ if isinstance(counts, list)
540
+ else segmentation
541
+ )
542
+ decoded = np.asarray(coco_mask.decode(encoded))
543
+ except (RuntimeError, TypeError, ValueError):
544
+ return False
545
+ return decoded.shape == tuple(size) and bool(np.any(decoded))
546
+
547
+
548
+ def _valid_coco_polygon(
549
+ polygon: list[int | float], image_shape: tuple[int, int] | None
550
+ ) -> bool:
551
+ """Require a COCO polygon to rasterize to foreground in its image."""
552
+
553
+ if image_shape is None:
554
+ return True
555
+ height, width = image_shape
556
+ try:
557
+ encoded = coco_mask.frPyObjects([polygon], height, width)
558
+ decoded = np.asarray(coco_mask.decode(encoded))
559
+ except (RuntimeError, TypeError, ValueError):
560
+ return False
561
+ return bool(np.any(decoded))
562
+
563
+
564
+ def _coco_ready(root: Path, task: str) -> bool:
565
+ """Check the complete COCO 2017 image split and task annotation metadata."""
566
+
567
+ annotation_name = (
568
+ "person_keypoints_val2017.json"
569
+ if task == "pose_estimation"
570
+ else "instances_val2017.json"
571
+ )
572
+ annotation_names = _load_coco_image_names(root / annotation_name, task)
573
+ if annotation_names is None:
574
+ return False
575
+ image_dir = root / "val2017"
576
+ if not image_dir.is_dir():
577
+ return False
578
+ image_paths = [
579
+ path
580
+ for path in image_dir.iterdir()
581
+ if path.is_file() and path.suffix.lower() in IMAGE_SUFFIXES
582
+ ]
583
+ if len(image_paths) != COCO_VALIDATION_SAMPLE_COUNT or any(
584
+ path.suffix.lower() != ".jpg" or COCO_IMAGE_PATTERN.fullmatch(path.stem) is None
585
+ for path in image_paths
586
+ ):
587
+ return False
588
+ if {path.name for path in image_paths} != annotation_names:
589
+ return False
590
+ try:
591
+ payload = json.loads((root / annotation_name).read_text(encoding="utf-8"))
592
+ image_records = payload["images"]
593
+ image_shapes = {
594
+ record["file_name"]: (record["height"], record["width"])
595
+ for record in image_records
596
+ }
597
+ except (KeyError, TypeError, ValueError, json.JSONDecodeError, OSError):
598
+ return False
599
+ for image_path in image_paths:
600
+ expected_shape = image_shapes.get(image_path.name)
601
+ if (
602
+ not isinstance(expected_shape, tuple)
603
+ or len(expected_shape) != 2
604
+ or any(
605
+ not isinstance(value, int) or isinstance(value, bool) or value <= 0
606
+ for value in expected_shape
607
+ )
608
+ ):
609
+ return False
610
+ try:
611
+ with Image.open(image_path) as image:
612
+ image.load()
613
+ width, height = image.size
614
+ except OSError:
615
+ return False
616
+ if (height, width) != expected_shape:
617
+ return False
618
+ return True
619
+
620
+
621
+ def _dotav1_ready(root: Path) -> bool:
622
+ """Check complete paired DOTAv1 validation images and labels."""
623
+
624
+ flat_image_dir = root / "images"
625
+ flat_images = _files_by_stem(flat_image_dir, IMAGE_SUFFIXES)
626
+ if flat_images is None:
627
+ return False
628
+ image_dir = flat_image_dir if flat_images else flat_image_dir / "val"
629
+ images = flat_images if flat_images else _files_by_stem(image_dir, IMAGE_SUFFIXES)
630
+ if images is None or len(images) != DOTAV1_VALIDATION_SAMPLE_COUNT:
631
+ return False
632
+
633
+ normalized_labels = _files_by_stem(root / "labels" / "val", {".txt"})
634
+ original_labels = _files_by_stem(root / "labels" / "val_original", {".txt"})
635
+ if normalized_labels is None or original_labels is None:
636
+ return False
637
+ label_stems = normalized_labels.keys() | original_labels.keys()
638
+ return images.keys() == label_stems
639
+
640
+
641
+ def _widerface_ready(root: Path) -> bool:
642
+ """Check the complete WiderFace validation image tree and metadata files."""
643
+
644
+ required_files = (
645
+ "wider_face_val.mat",
646
+ "wider_easy_val.mat",
647
+ "wider_medium_val.mat",
648
+ "wider_hard_val.mat",
649
+ )
650
+ if not all((root / file_name).is_file() for file_name in required_files):
651
+ return False
652
+ expected_images = _load_widerface_image_names(root / "wider_face_val.mat")
653
+ if expected_images is None:
654
+ return False
655
+ image_root = root / "images"
656
+ if not image_root.is_dir():
657
+ return False
658
+ event_dirs = [path for path in image_root.iterdir() if path.is_dir()]
659
+ if len(event_dirs) != WIDERFACE_EVENT_COUNT or any(
660
+ WIDERFACE_EVENT_PATTERN.fullmatch(path.name) is None for path in event_dirs
661
+ ):
662
+ return False
663
+ if {path.name for path in event_dirs} != expected_images.keys():
664
+ return False
665
+ actual_images = {
666
+ event_dir.name: {
667
+ path.name
668
+ for path in event_dir.iterdir()
669
+ if path.is_file() and path.suffix.lower() in IMAGE_SUFFIXES
670
+ }
671
+ for event_dir in event_dirs
672
+ }
673
+ image_shapes = _widerface_image_shapes(root, expected_images)
674
+ return (
675
+ actual_images == expected_images
676
+ and sum(len(image_names) for image_names in actual_images.values())
677
+ == WIDERFACE_VALIDATION_SAMPLE_COUNT
678
+ and image_shapes is not None
679
+ and _widerface_difficulty_metadata_ready(
680
+ root, expected_images, image_shapes=image_shapes
681
+ )
682
+ )
683
+
684
+
685
+ def _widerface_difficulty_metadata_ready(
686
+ root: Path,
687
+ expected_images: dict[str, set[str]],
688
+ *,
689
+ image_shapes: list[list[tuple[int, int]]] | None = None,
690
+ ) -> bool:
691
+ """Validate WiderFace difficulty metadata and its decoded-image geometry."""
692
+
693
+ try:
694
+ main = loadmat(root / "wider_face_val.mat")
695
+ face_boxes = main["face_bbx_list"]
696
+ difficulties = [
697
+ loadmat(root / file_name)["gt_list"]
698
+ for file_name in (
699
+ "wider_easy_val.mat",
700
+ "wider_medium_val.mat",
701
+ "wider_hard_val.mat",
702
+ )
703
+ ]
704
+ except (IndexError, KeyError, MatReadError, OSError, TypeError, ValueError):
705
+ return False
706
+ if len(face_boxes) != len(expected_images) or any(
707
+ len(table) != len(expected_images) for table in difficulties
708
+ ):
709
+ return False
710
+ if image_shapes is not None and len(image_shapes) != len(expected_images):
711
+ return False
712
+ difficulty_has_eligible_face = [False] * len(difficulties)
713
+ for event_index, image_names in enumerate(expected_images.values()):
714
+ try:
715
+ event_faces = face_boxes[event_index][0]
716
+ except (IndexError, TypeError):
717
+ return False
718
+ if len(event_faces) != len(image_names):
719
+ return False
720
+ if image_shapes is not None and len(image_shapes[event_index]) != len(
721
+ image_names
722
+ ):
723
+ return False
724
+ face_counts: list[int] = []
725
+ for image_index, face_entry in enumerate(event_faces):
726
+ try:
727
+ face_array = np.asarray(face_entry[0])
728
+ except (IndexError, TypeError):
729
+ return False
730
+ if (
731
+ face_array.ndim != 2
732
+ or face_array.shape[1] != 4
733
+ or len(face_array) == 0
734
+ or not np.issubdtype(face_array.dtype, np.number)
735
+ or np.issubdtype(face_array.dtype, np.complexfloating)
736
+ or not np.isfinite(face_array).all()
737
+ or (face_array[:, 2:] <= 0).any()
738
+ or len(np.unique(face_array, axis=0)) != len(face_array)
739
+ ):
740
+ return False
741
+ if image_shapes is not None:
742
+ height, width = image_shapes[event_index][image_index]
743
+ if (
744
+ height <= 0
745
+ or width <= 0
746
+ or not (
747
+ (face_array[:, 0] < width)
748
+ & (face_array[:, 0] + face_array[:, 2] > 0)
749
+ & (face_array[:, 1] < height)
750
+ & (face_array[:, 1] + face_array[:, 3] > 0)
751
+ ).all()
752
+ ):
753
+ return False
754
+ face_counts.append(len(face_array))
755
+ for difficulty_index, table in enumerate(difficulties):
756
+ try:
757
+ event_indices = table[event_index][0]
758
+ except (IndexError, TypeError):
759
+ return False
760
+ if len(event_indices) != len(image_names):
761
+ return False
762
+ for image_index in range(len(event_faces)):
763
+ try:
764
+ keep_indices = np.asarray(event_indices[image_index][0])
765
+ except (IndexError, TypeError):
766
+ return False
767
+ if keep_indices.ndim == 0:
768
+ keep_indices = keep_indices.reshape(1)
769
+ elif keep_indices.ndim == 2:
770
+ if keep_indices.size == 0:
771
+ if keep_indices.shape[0] != 0:
772
+ return False
773
+ keep_indices = keep_indices.reshape(0)
774
+ elif keep_indices.shape[1] == 1:
775
+ keep_indices = keep_indices[:, 0]
776
+ else:
777
+ return False
778
+ elif keep_indices.ndim != 1:
779
+ return False
780
+ try:
781
+ valid_indices = (
782
+ np.isfinite(keep_indices).all()
783
+ and np.equal(keep_indices, np.trunc(keep_indices)).all()
784
+ )
785
+ except (TypeError, ValueError):
786
+ return False
787
+ if not valid_indices:
788
+ return False
789
+ if keep_indices.size and (
790
+ int(keep_indices.min()) < 1
791
+ or int(keep_indices.max()) > face_counts[image_index]
792
+ ):
793
+ return False
794
+ if len(np.unique(keep_indices)) != keep_indices.size:
795
+ return False
796
+ difficulty_has_eligible_face[difficulty_index] |= bool(
797
+ keep_indices.size
798
+ )
799
+ if not all(difficulty_has_eligible_face):
800
+ return False
801
+ return True
802
+
803
+
804
+ def _flatten_matlab_strings(value: Any) -> list[str]:
805
+ """Flatten strings stored inside nested MATLAB cell arrays."""
806
+
807
+ if isinstance(value, (str, np.str_)):
808
+ return [str(value)]
809
+ if isinstance(value, np.ndarray):
810
+ strings: list[str] = []
811
+ for item in value.flat:
812
+ strings.extend(_flatten_matlab_strings(item))
813
+ return strings
814
+ return []
815
+
816
+
817
+ def _load_widerface_image_names(annotation_path: Path) -> dict[str, set[str]] | None:
818
+ """Load exact event and image identities from WiderFace validation metadata."""
819
+
820
+ try:
821
+ annotation = loadmat(annotation_path)
822
+ event_list = annotation["event_list"]
823
+ file_list = annotation["file_list"]
824
+ except (IndexError, KeyError, MatReadError, OSError, TypeError, ValueError):
825
+ return None
826
+ if len(event_list) != len(file_list):
827
+ return None
828
+
829
+ expected: dict[str, set[str]] = {}
830
+ for event_cell, file_cell in zip(event_list, file_list, strict=True):
831
+ event_names = _flatten_matlab_strings(event_cell)
832
+ image_stems = _flatten_matlab_strings(file_cell)
833
+ if (
834
+ len(event_names) != 1
835
+ or not image_stems
836
+ or len(image_stems) != len(set(image_stems))
837
+ or WIDERFACE_EVENT_PATTERN.fullmatch(event_names[0]) is None
838
+ or any(not stem or Path(stem).name != stem for stem in image_stems)
839
+ or event_names[0] in expected
840
+ ):
841
+ return None
842
+ expected[event_names[0]] = {f"{stem}.jpg" for stem in image_stems}
843
+ if len(expected) != WIDERFACE_EVENT_COUNT:
844
+ return None
845
+ return expected
846
+
847
+
848
+ def _widerface_image_shapes(
849
+ root: Path, expected_images: dict[str, set[str]]
850
+ ) -> list[list[tuple[int, int]]] | None:
851
+ """Load WiderFace image shapes in the annotation's event and file order."""
852
+
853
+ try:
854
+ annotation = loadmat(root / "wider_face_val.mat")
855
+ event_list = annotation["event_list"]
856
+ file_list = annotation["file_list"]
857
+ except (IndexError, KeyError, MatReadError, OSError, TypeError, ValueError):
858
+ return None
859
+ if len(event_list) != len(file_list) or len(event_list) != len(expected_images):
860
+ return None
861
+
862
+ all_shapes: list[list[tuple[int, int]]] = []
863
+ for event_cell, file_cell in zip(event_list, file_list, strict=True):
864
+ event_names = _flatten_matlab_strings(event_cell)
865
+ image_stems = _flatten_matlab_strings(file_cell)
866
+ if (
867
+ len(event_names) != 1
868
+ or not image_stems
869
+ or expected_images.get(event_names[0])
870
+ != {f"{stem}.jpg" for stem in image_stems}
871
+ ):
872
+ return None
873
+ event_shapes: list[tuple[int, int]] = []
874
+ for stem in image_stems:
875
+ image_path = root / "images" / event_names[0] / f"{stem}.jpg"
876
+ if image_path.is_symlink():
877
+ return None
878
+ try:
879
+ with Image.open(image_path) as image:
880
+ image.load()
881
+ width, height = image.size
882
+ except OSError:
883
+ return None
884
+ event_shapes.append((height, width))
885
+ all_shapes.append(event_shapes)
886
+ return all_shapes
887
+
888
+
889
+ def dense_dataset_ready(data_path: str | Path, dataset: str) -> bool:
890
+ """Return whether a dense dataset matches its taxonomy and full validation split.
891
+
892
+ Args:
893
+ data_path: Organized dataset root.
894
+ dataset: Dense validation taxonomy.
895
+
896
+ Returns:
897
+ Whether the dataset has the expected filename identity, matched targets,
898
+ and complete validation sample count.
899
+ """
900
+
901
+ root = Path(data_path).expanduser()
902
+ if _path_has_symlink_component(root) or not root.is_dir():
903
+ return False
904
+ normalized = dataset.lower()
905
+ if normalized == "nyu-depth":
906
+ images = _files_by_stem(
907
+ root / "images", {".jpg", ".jpeg", ".png"}, reject_symlinks=True
908
+ )
909
+ depths = _files_by_stem(root / "depth", {".npy"}, reject_symlinks=True)
910
+ if images is None or depths is None:
911
+ return False
912
+ if not (
913
+ len(images) == NYU_DEPTH_VALIDATION_SAMPLE_COUNT
914
+ and len(depths) == NYU_DEPTH_VALIDATION_SAMPLE_COUNT
915
+ and images.keys() == depths.keys()
916
+ ):
917
+ return False
918
+ for stem, image_path in images.items():
919
+ try:
920
+ with Image.open(image_path) as image:
921
+ image.load()
922
+ image_shape = (image.height, image.width)
923
+ raw_depth = np.load(depths[stem], allow_pickle=False)
924
+ except (OSError, ValueError):
925
+ return False
926
+ if not np.issubdtype(raw_depth.dtype, np.number) or np.issubdtype(
927
+ raw_depth.dtype, np.complexfloating
928
+ ):
929
+ return False
930
+ with np.errstate(over="ignore", invalid="ignore"):
931
+ depth = np.asarray(raw_depth, dtype=np.float32)
932
+ if (
933
+ depth.ndim != 2
934
+ or depth.shape != image_shape
935
+ or not np.isfinite(depth).all()
936
+ or bool((depth < 0).any())
937
+ or not bool(((depth > 0.001) & (depth < 100.0)).any())
938
+ ):
939
+ return False
940
+ return True
941
+
942
+ images = _files_by_stem(
943
+ root / "images", {".jpg", ".jpeg", ".png"}, reject_symlinks=True
944
+ )
945
+ annotations = _files_by_stem(root / "annotations", {".png"}, reject_symlinks=True)
946
+ if images is None or annotations is None or images.keys() != annotations.keys():
947
+ return False
948
+
949
+ for stem, image_path in images.items():
950
+ try:
951
+ with Image.open(image_path) as image:
952
+ image.load()
953
+ image_shape = (image.height, image.width)
954
+ with Image.open(annotations[stem]) as annotation_image:
955
+ annotation = np.asarray(annotation_image)
956
+ except OSError:
957
+ return False
958
+ if normalized == "cityscapes" and annotation.ndim == 3:
959
+ if (
960
+ annotation.shape[2] not in {3, 4}
961
+ or not np.array_equal(annotation[..., 0], annotation[..., 1])
962
+ or not np.array_equal(annotation[..., 0], annotation[..., 2])
963
+ ):
964
+ return False
965
+ annotation = annotation[..., 0]
966
+ if annotation.ndim != 2 or annotation.shape != image_shape:
967
+ return False
968
+ if normalized == "ade20k":
969
+ if annotation.dtype != np.uint8 or (
970
+ annotation.size and int(annotation.max()) > 150
971
+ ):
972
+ return False
973
+ if not bool((annotation > 0).any()):
974
+ return False
975
+ elif normalized == "cityscapes":
976
+ if annotation.size and (
977
+ int(annotation.min()) < 0 or int(annotation.max()) > 255
978
+ ):
979
+ return False
980
+ if not bool(np.all((annotation <= 33) | (annotation == 255))):
981
+ return False
982
+ train_ids = CITYSCAPES_SOURCE_TO_TRAIN_ID[annotation.astype(np.uint8)]
983
+ if not bool((train_ids != 255).any()):
984
+ return False
985
+
986
+ if normalized == "ade20k":
987
+ return (
988
+ len(images) == ADE20K_VALIDATION_SAMPLE_COUNT
989
+ and all(stem.startswith("ADE_val_") for stem in images)
990
+ and all(
991
+ path.suffix.lower() in {".jpg", ".jpeg"} for path in images.values()
992
+ )
993
+ and all(
994
+ not (root / file_name).is_symlink() and (root / file_name).is_file()
995
+ for file_name in ADE20K_METADATA_FILES
996
+ )
997
+ )
998
+ if normalized == "cityscapes":
999
+ city_counts: dict[str, int] = {}
1000
+ for stem in images:
1001
+ match = CITYSCAPES_SAMPLE_ID_PATTERN.fullmatch(stem)
1002
+ if match is not None:
1003
+ city = match.group("city")
1004
+ city_counts[city] = city_counts.get(city, 0) + 1
1005
+ return (
1006
+ len(images) == CITYSCAPES_VALIDATION_SAMPLE_COUNT
1007
+ and all(
1008
+ CITYSCAPES_SAMPLE_ID_PATTERN.fullmatch(stem) is not None
1009
+ for stem in images
1010
+ )
1011
+ and all(path.suffix.lower() == ".png" for path in images.values())
1012
+ and (
1013
+ CITYSCAPES_VALIDATION_SAMPLE_COUNT != 500
1014
+ or city_counts == CITYSCAPES_VALIDATION_CITY_COUNTS
1015
+ )
1016
+ )
1017
+ return False
1018
+
1019
+
1020
+ def dataset_ready(data_path: str | Path, task: str, dataset: str | None = None) -> bool:
1021
+ """Return whether an organized dataset matches its task, taxonomy, and full validation split.
1022
+
1023
+ Args:
1024
+ data_path: Organized dataset root.
1025
+ task: Canonical vision task.
1026
+ dataset: Optional validation taxonomy.
1027
+
1028
+ Returns:
1029
+ Whether the dataset has the expected identity, metadata, and sample count.
1030
+ """
1031
+
1032
+ root = Path(data_path).expanduser()
1033
+ normalized_task = normalize_vision_task(task)
1034
+ expected_dataset = {
1035
+ "image_classification": "imagenet",
1036
+ "object_detection": "coco",
1037
+ "instance_segmentation": "coco",
1038
+ "pose_estimation": "coco",
1039
+ "face_detection": "widerface",
1040
+ "obb": "dotav1",
1041
+ "depth_estimation": "nyu-depth",
1042
+ }.get(normalized_task)
1043
+ normalized_dataset = (dataset or expected_dataset or "").lower()
1044
+
1045
+ if normalized_task == "semantic_segmentation":
1046
+ return dense_dataset_ready(root, normalized_dataset or "ade20k")
1047
+ if expected_dataset is None or normalized_dataset != expected_dataset:
1048
+ return False
1049
+ if normalized_task == "image_classification":
1050
+ return _imagenet_ready(root)
1051
+ if normalized_task in {
1052
+ "object_detection",
1053
+ "instance_segmentation",
1054
+ "pose_estimation",
1055
+ }:
1056
+ return _coco_ready(root, normalized_task)
1057
+ if normalized_task == "face_detection":
1058
+ return _widerface_ready(root)
1059
+ if normalized_task == "obb":
1060
+ return _dotav1_ready(root)
1061
+ if normalized_task == "depth_estimation":
1062
+ return dense_dataset_ready(root, normalized_dataset)
1063
+ return False