lightly-studio 0.4.6__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 (356) hide show
  1. lightly_studio/__init__.py +12 -0
  2. lightly_studio/api/__init__.py +0 -0
  3. lightly_studio/api/app.py +131 -0
  4. lightly_studio/api/cache.py +77 -0
  5. lightly_studio/api/db_tables.py +35 -0
  6. lightly_studio/api/features.py +5 -0
  7. lightly_studio/api/routes/api/annotation.py +305 -0
  8. lightly_studio/api/routes/api/annotation_label.py +87 -0
  9. lightly_studio/api/routes/api/annotations/__init__.py +7 -0
  10. lightly_studio/api/routes/api/annotations/create_annotation.py +52 -0
  11. lightly_studio/api/routes/api/caption.py +100 -0
  12. lightly_studio/api/routes/api/classifier.py +384 -0
  13. lightly_studio/api/routes/api/dataset.py +191 -0
  14. lightly_studio/api/routes/api/dataset_tag.py +266 -0
  15. lightly_studio/api/routes/api/embeddings2d.py +90 -0
  16. lightly_studio/api/routes/api/exceptions.py +114 -0
  17. lightly_studio/api/routes/api/export.py +114 -0
  18. lightly_studio/api/routes/api/features.py +17 -0
  19. lightly_studio/api/routes/api/frame.py +241 -0
  20. lightly_studio/api/routes/api/image.py +155 -0
  21. lightly_studio/api/routes/api/metadata.py +161 -0
  22. lightly_studio/api/routes/api/operator.py +75 -0
  23. lightly_studio/api/routes/api/sample.py +103 -0
  24. lightly_studio/api/routes/api/selection.py +87 -0
  25. lightly_studio/api/routes/api/settings.py +41 -0
  26. lightly_studio/api/routes/api/status.py +19 -0
  27. lightly_studio/api/routes/api/text_embedding.py +50 -0
  28. lightly_studio/api/routes/api/validators.py +17 -0
  29. lightly_studio/api/routes/api/video.py +133 -0
  30. lightly_studio/api/routes/healthz.py +13 -0
  31. lightly_studio/api/routes/images.py +104 -0
  32. lightly_studio/api/routes/video_frames_media.py +116 -0
  33. lightly_studio/api/routes/video_media.py +223 -0
  34. lightly_studio/api/routes/webapp.py +51 -0
  35. lightly_studio/api/server.py +94 -0
  36. lightly_studio/core/__init__.py +0 -0
  37. lightly_studio/core/add_samples.py +533 -0
  38. lightly_studio/core/add_videos.py +294 -0
  39. lightly_studio/core/dataset.py +780 -0
  40. lightly_studio/core/dataset_query/__init__.py +14 -0
  41. lightly_studio/core/dataset_query/boolean_expression.py +67 -0
  42. lightly_studio/core/dataset_query/dataset_query.py +317 -0
  43. lightly_studio/core/dataset_query/field.py +113 -0
  44. lightly_studio/core/dataset_query/field_expression.py +79 -0
  45. lightly_studio/core/dataset_query/match_expression.py +23 -0
  46. lightly_studio/core/dataset_query/order_by.py +79 -0
  47. lightly_studio/core/dataset_query/sample_field.py +37 -0
  48. lightly_studio/core/dataset_query/tags_expression.py +46 -0
  49. lightly_studio/core/image_sample.py +36 -0
  50. lightly_studio/core/loading_log.py +56 -0
  51. lightly_studio/core/sample.py +291 -0
  52. lightly_studio/core/start_gui.py +54 -0
  53. lightly_studio/core/video_sample.py +38 -0
  54. lightly_studio/dataset/__init__.py +0 -0
  55. lightly_studio/dataset/edge_embedding_generator.py +155 -0
  56. lightly_studio/dataset/embedding_generator.py +129 -0
  57. lightly_studio/dataset/embedding_manager.py +349 -0
  58. lightly_studio/dataset/env.py +20 -0
  59. lightly_studio/dataset/file_utils.py +49 -0
  60. lightly_studio/dataset/fsspec_lister.py +275 -0
  61. lightly_studio/dataset/mobileclip_embedding_generator.py +158 -0
  62. lightly_studio/dataset/perception_encoder_embedding_generator.py +260 -0
  63. lightly_studio/db_manager.py +166 -0
  64. lightly_studio/dist_lightly_studio_view_app/_app/env.js +1 -0
  65. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/0.GcXvs2l7.css +1 -0
  66. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/12.Dx6SXgAb.css +1 -0
  67. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/17.9X9_k6TP.css +1 -0
  68. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/18.BxiimdIO.css +1 -0
  69. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/2.CkOblLn7.css +1 -0
  70. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/ClassifierSamplesGrid.BJbCDlvs.css +1 -0
  71. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/LightlyLogo.BNjCIww-.png +0 -0
  72. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Bold.DGvYQtcs.ttf +0 -0
  73. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Italic-VariableFont_wdth_wght.B4AZ-wl6.ttf +0 -0
  74. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Medium.DVUZMR_6.ttf +0 -0
  75. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Regular.DxJTClRG.ttf +0 -0
  76. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-SemiBold.D3TTYgdB.ttf +0 -0
  77. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-VariableFont_wdth_wght.BZBpG5Iz.ttf +0 -0
  78. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_layout.CefECEWA.css +1 -0
  79. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_layout.D5tDcjY-.css +1 -0
  80. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_page.9X9_k6TP.css +1 -0
  81. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_page.BxiimdIO.css +1 -0
  82. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_page.Dx6SXgAb.css +1 -0
  83. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/transform._-1mPSEI.css +1 -0
  84. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/0dDyq72A.js +20 -0
  85. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/69_IOA4Y.js +1 -0
  86. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BK4An2kI.js +1 -0
  87. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BRmB-kJ9.js +1 -0
  88. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/B_1cpokE.js +1 -0
  89. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BiqpDEr0.js +1 -0
  90. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BpLiSKgx.js +1 -0
  91. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BscxbINH.js +39 -0
  92. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C1FmrZbK.js +1 -0
  93. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C80h3dJx.js +1 -0
  94. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C8mfFM-u.js +2 -0
  95. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CGY1p9L4.js +517 -0
  96. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/COfLknXM.js +1 -0
  97. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CWj6FrbW.js +1 -0
  98. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CYgJF_JY.js +1 -0
  99. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CmLg0ys7.js +1 -0
  100. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CvGjimpO.js +1 -0
  101. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D3RDXHoj.js +39 -0
  102. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D4y7iiT3.js +1 -0
  103. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D9SC3jBb.js +1 -0
  104. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DCuAdx1Q.js +20 -0
  105. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DDBy-_jD.js +1 -0
  106. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DIeogL5L.js +1 -0
  107. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DL9a7v5o.js +1 -0
  108. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DSKECuqX.js +39 -0
  109. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D_FFv0Oe.js +1 -0
  110. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DiZ5o5vz.js +1 -0
  111. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DkbXUtyG.js +1 -0
  112. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DmK2hulV.js +1 -0
  113. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DqnHaLTj.js +1 -0
  114. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DtWZc_tl.js +1 -0
  115. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DuUalyFS.js +1 -0
  116. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DwIonDAZ.js +1 -0
  117. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Il-mSPmK.js +1 -0
  118. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/KNLP4aJU.js +1 -0
  119. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/KjYeVjkE.js +1 -0
  120. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/MErlcOXj.js +1 -0
  121. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/VRI4prUD.js +1 -0
  122. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/VYb2dkNs.js +1 -0
  123. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/VqWvU2yF.js +1 -0
  124. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/dHC3otuL.js +1 -0
  125. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/da7Oy_lO.js +1 -0
  126. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/eAy8rZzC.js +2 -0
  127. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/erjNR5MX.js +1 -0
  128. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/f1oG3eFE.js +1 -0
  129. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/rsLi1iKv.js +20 -0
  130. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/rwuuBP9f.js +1 -0
  131. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/xGHZQ1pe.js +3 -0
  132. lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/app.DrTRUgT3.js +2 -0
  133. lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/start.BK5EOJl2.js +1 -0
  134. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/0.CIvTuljF.js +4 -0
  135. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/1.UBvSzxdA.js +1 -0
  136. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/10.CQ_tiLJa.js +1 -0
  137. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/11.KqkAcaxW.js +1 -0
  138. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/12.DoYsmxQc.js +1 -0
  139. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/13.571n2LZA.js +1 -0
  140. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/14.DGs689M-.js +1 -0
  141. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/15.CWG1ehzT.js +1 -0
  142. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/16.Dpq6jbSh.js +1 -0
  143. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/17.B5AZbHUU.js +1 -0
  144. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/18.CBga8cnq.js +1 -0
  145. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/2.D2HXgz-8.js +1090 -0
  146. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/3.f4HAg-y3.js +1 -0
  147. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/4.BKF4xuKQ.js +1 -0
  148. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/5.BAE0Pm_f.js +39 -0
  149. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/6.CouWWpzA.js +1 -0
  150. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/7.UBHT0ktp.js +1 -0
  151. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/8.FiYNElcc.js +1 -0
  152. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/9.B3-UaT23.js +1 -0
  153. lightly_studio/dist_lightly_studio_view_app/_app/immutable/workers/clustering.worker-DKqeLtG0.js +2 -0
  154. lightly_studio/dist_lightly_studio_view_app/_app/immutable/workers/search.worker-vNSty3B0.js +1 -0
  155. lightly_studio/dist_lightly_studio_view_app/_app/version.json +1 -0
  156. lightly_studio/dist_lightly_studio_view_app/apple-touch-icon-precomposed.png +0 -0
  157. lightly_studio/dist_lightly_studio_view_app/apple-touch-icon.png +0 -0
  158. lightly_studio/dist_lightly_studio_view_app/favicon.png +0 -0
  159. lightly_studio/dist_lightly_studio_view_app/index.html +45 -0
  160. lightly_studio/errors.py +5 -0
  161. lightly_studio/examples/example.py +25 -0
  162. lightly_studio/examples/example_coco.py +27 -0
  163. lightly_studio/examples/example_coco_caption.py +29 -0
  164. lightly_studio/examples/example_metadata.py +369 -0
  165. lightly_studio/examples/example_operators.py +111 -0
  166. lightly_studio/examples/example_selection.py +28 -0
  167. lightly_studio/examples/example_split_work.py +48 -0
  168. lightly_studio/examples/example_video.py +22 -0
  169. lightly_studio/examples/example_video_annotations.py +157 -0
  170. lightly_studio/examples/example_yolo.py +22 -0
  171. lightly_studio/export/coco_captions.py +69 -0
  172. lightly_studio/export/export_dataset.py +104 -0
  173. lightly_studio/export/lightly_studio_label_input.py +120 -0
  174. lightly_studio/export_schema.py +18 -0
  175. lightly_studio/export_version.py +57 -0
  176. lightly_studio/few_shot_classifier/__init__.py +0 -0
  177. lightly_studio/few_shot_classifier/classifier.py +80 -0
  178. lightly_studio/few_shot_classifier/classifier_manager.py +644 -0
  179. lightly_studio/few_shot_classifier/random_forest_classifier.py +495 -0
  180. lightly_studio/metadata/complex_metadata.py +47 -0
  181. lightly_studio/metadata/compute_similarity.py +84 -0
  182. lightly_studio/metadata/compute_typicality.py +67 -0
  183. lightly_studio/metadata/gps_coordinate.py +41 -0
  184. lightly_studio/metadata/metadata_protocol.py +17 -0
  185. lightly_studio/models/__init__.py +1 -0
  186. lightly_studio/models/annotation/__init__.py +0 -0
  187. lightly_studio/models/annotation/annotation_base.py +303 -0
  188. lightly_studio/models/annotation/instance_segmentation.py +56 -0
  189. lightly_studio/models/annotation/links.py +17 -0
  190. lightly_studio/models/annotation/object_detection.py +47 -0
  191. lightly_studio/models/annotation/semantic_segmentation.py +44 -0
  192. lightly_studio/models/annotation_label.py +47 -0
  193. lightly_studio/models/caption.py +49 -0
  194. lightly_studio/models/classifier.py +20 -0
  195. lightly_studio/models/dataset.py +70 -0
  196. lightly_studio/models/embedding_model.py +30 -0
  197. lightly_studio/models/image.py +96 -0
  198. lightly_studio/models/metadata.py +208 -0
  199. lightly_studio/models/range.py +17 -0
  200. lightly_studio/models/sample.py +154 -0
  201. lightly_studio/models/sample_embedding.py +36 -0
  202. lightly_studio/models/settings.py +69 -0
  203. lightly_studio/models/tag.py +96 -0
  204. lightly_studio/models/two_dim_embedding.py +16 -0
  205. lightly_studio/models/video.py +161 -0
  206. lightly_studio/plugins/__init__.py +0 -0
  207. lightly_studio/plugins/base_operator.py +60 -0
  208. lightly_studio/plugins/operator_registry.py +47 -0
  209. lightly_studio/plugins/parameter.py +70 -0
  210. lightly_studio/py.typed +0 -0
  211. lightly_studio/resolvers/__init__.py +0 -0
  212. lightly_studio/resolvers/annotation_label_resolver/__init__.py +22 -0
  213. lightly_studio/resolvers/annotation_label_resolver/create.py +27 -0
  214. lightly_studio/resolvers/annotation_label_resolver/delete.py +28 -0
  215. lightly_studio/resolvers/annotation_label_resolver/get_all.py +37 -0
  216. lightly_studio/resolvers/annotation_label_resolver/get_by_id.py +24 -0
  217. lightly_studio/resolvers/annotation_label_resolver/get_by_ids.py +25 -0
  218. lightly_studio/resolvers/annotation_label_resolver/get_by_label_name.py +24 -0
  219. lightly_studio/resolvers/annotation_label_resolver/names_by_ids.py +25 -0
  220. lightly_studio/resolvers/annotation_label_resolver/update.py +38 -0
  221. lightly_studio/resolvers/annotation_resolver/__init__.py +40 -0
  222. lightly_studio/resolvers/annotation_resolver/count_annotations_by_dataset.py +129 -0
  223. lightly_studio/resolvers/annotation_resolver/create_many.py +124 -0
  224. lightly_studio/resolvers/annotation_resolver/delete_annotation.py +87 -0
  225. lightly_studio/resolvers/annotation_resolver/delete_annotations.py +60 -0
  226. lightly_studio/resolvers/annotation_resolver/get_all.py +85 -0
  227. lightly_studio/resolvers/annotation_resolver/get_all_with_payload.py +179 -0
  228. lightly_studio/resolvers/annotation_resolver/get_by_id.py +34 -0
  229. lightly_studio/resolvers/annotation_resolver/get_by_id_with_payload.py +130 -0
  230. lightly_studio/resolvers/annotation_resolver/update_annotation_label.py +142 -0
  231. lightly_studio/resolvers/annotation_resolver/update_bounding_box.py +68 -0
  232. lightly_studio/resolvers/annotations/__init__.py +1 -0
  233. lightly_studio/resolvers/annotations/annotations_filter.py +88 -0
  234. lightly_studio/resolvers/caption_resolver.py +129 -0
  235. lightly_studio/resolvers/dataset_resolver/__init__.py +55 -0
  236. lightly_studio/resolvers/dataset_resolver/check_dataset_type.py +29 -0
  237. lightly_studio/resolvers/dataset_resolver/create.py +20 -0
  238. lightly_studio/resolvers/dataset_resolver/delete.py +20 -0
  239. lightly_studio/resolvers/dataset_resolver/export.py +267 -0
  240. lightly_studio/resolvers/dataset_resolver/get_all.py +19 -0
  241. lightly_studio/resolvers/dataset_resolver/get_by_id.py +16 -0
  242. lightly_studio/resolvers/dataset_resolver/get_by_name.py +12 -0
  243. lightly_studio/resolvers/dataset_resolver/get_dataset_details.py +27 -0
  244. lightly_studio/resolvers/dataset_resolver/get_hierarchy.py +31 -0
  245. lightly_studio/resolvers/dataset_resolver/get_or_create_child_dataset.py +58 -0
  246. lightly_studio/resolvers/dataset_resolver/get_parent_dataset_by_sample_id.py +27 -0
  247. lightly_studio/resolvers/dataset_resolver/get_parent_dataset_id.py +22 -0
  248. lightly_studio/resolvers/dataset_resolver/get_root_dataset.py +61 -0
  249. lightly_studio/resolvers/dataset_resolver/get_root_datasets_overview.py +41 -0
  250. lightly_studio/resolvers/dataset_resolver/update.py +25 -0
  251. lightly_studio/resolvers/embedding_model_resolver.py +120 -0
  252. lightly_studio/resolvers/image_filter.py +50 -0
  253. lightly_studio/resolvers/image_resolver/__init__.py +21 -0
  254. lightly_studio/resolvers/image_resolver/create_many.py +52 -0
  255. lightly_studio/resolvers/image_resolver/delete.py +20 -0
  256. lightly_studio/resolvers/image_resolver/filter_new_paths.py +23 -0
  257. lightly_studio/resolvers/image_resolver/get_all_by_dataset_id.py +117 -0
  258. lightly_studio/resolvers/image_resolver/get_by_id.py +14 -0
  259. lightly_studio/resolvers/image_resolver/get_dimension_bounds.py +75 -0
  260. lightly_studio/resolvers/image_resolver/get_many_by_id.py +22 -0
  261. lightly_studio/resolvers/image_resolver/get_samples_excluding.py +43 -0
  262. lightly_studio/resolvers/metadata_resolver/__init__.py +15 -0
  263. lightly_studio/resolvers/metadata_resolver/metadata_filter.py +163 -0
  264. lightly_studio/resolvers/metadata_resolver/sample/__init__.py +21 -0
  265. lightly_studio/resolvers/metadata_resolver/sample/bulk_update_metadata.py +46 -0
  266. lightly_studio/resolvers/metadata_resolver/sample/get_by_sample_id.py +24 -0
  267. lightly_studio/resolvers/metadata_resolver/sample/get_metadata_info.py +104 -0
  268. lightly_studio/resolvers/metadata_resolver/sample/get_value_for_sample.py +27 -0
  269. lightly_studio/resolvers/metadata_resolver/sample/set_value_for_sample.py +53 -0
  270. lightly_studio/resolvers/sample_embedding_resolver.py +132 -0
  271. lightly_studio/resolvers/sample_resolver/__init__.py +17 -0
  272. lightly_studio/resolvers/sample_resolver/count_by_dataset_id.py +16 -0
  273. lightly_studio/resolvers/sample_resolver/create.py +16 -0
  274. lightly_studio/resolvers/sample_resolver/create_many.py +25 -0
  275. lightly_studio/resolvers/sample_resolver/get_by_id.py +14 -0
  276. lightly_studio/resolvers/sample_resolver/get_filtered_samples.py +56 -0
  277. lightly_studio/resolvers/sample_resolver/get_many_by_id.py +22 -0
  278. lightly_studio/resolvers/sample_resolver/sample_filter.py +74 -0
  279. lightly_studio/resolvers/settings_resolver.py +62 -0
  280. lightly_studio/resolvers/tag_resolver.py +299 -0
  281. lightly_studio/resolvers/twodim_embedding_resolver.py +119 -0
  282. lightly_studio/resolvers/video_frame_resolver/__init__.py +23 -0
  283. lightly_studio/resolvers/video_frame_resolver/count_video_frames_annotations.py +83 -0
  284. lightly_studio/resolvers/video_frame_resolver/create_many.py +57 -0
  285. lightly_studio/resolvers/video_frame_resolver/get_all_by_dataset_id.py +63 -0
  286. lightly_studio/resolvers/video_frame_resolver/get_by_id.py +13 -0
  287. lightly_studio/resolvers/video_frame_resolver/get_table_fields_bounds.py +44 -0
  288. lightly_studio/resolvers/video_frame_resolver/video_frame_annotations_counter_filter.py +47 -0
  289. lightly_studio/resolvers/video_frame_resolver/video_frame_filter.py +57 -0
  290. lightly_studio/resolvers/video_resolver/__init__.py +27 -0
  291. lightly_studio/resolvers/video_resolver/count_video_frame_annotations_by_video_dataset.py +86 -0
  292. lightly_studio/resolvers/video_resolver/create_many.py +58 -0
  293. lightly_studio/resolvers/video_resolver/filter_new_paths.py +33 -0
  294. lightly_studio/resolvers/video_resolver/get_all_by_dataset_id.py +181 -0
  295. lightly_studio/resolvers/video_resolver/get_by_id.py +22 -0
  296. lightly_studio/resolvers/video_resolver/get_table_fields_bounds.py +72 -0
  297. lightly_studio/resolvers/video_resolver/get_view_by_id.py +52 -0
  298. lightly_studio/resolvers/video_resolver/video_count_annotations_filter.py +50 -0
  299. lightly_studio/resolvers/video_resolver/video_filter.py +98 -0
  300. lightly_studio/selection/__init__.py +1 -0
  301. lightly_studio/selection/mundig.py +143 -0
  302. lightly_studio/selection/select.py +203 -0
  303. lightly_studio/selection/select_via_db.py +273 -0
  304. lightly_studio/selection/selection_config.py +49 -0
  305. lightly_studio/services/annotations_service/__init__.py +33 -0
  306. lightly_studio/services/annotations_service/create_annotation.py +64 -0
  307. lightly_studio/services/annotations_service/delete_annotation.py +22 -0
  308. lightly_studio/services/annotations_service/get_annotation_by_id.py +31 -0
  309. lightly_studio/services/annotations_service/update_annotation.py +54 -0
  310. lightly_studio/services/annotations_service/update_annotation_bounding_box.py +36 -0
  311. lightly_studio/services/annotations_service/update_annotation_label.py +48 -0
  312. lightly_studio/services/annotations_service/update_annotations.py +29 -0
  313. lightly_studio/setup_logging.py +59 -0
  314. lightly_studio/type_definitions.py +31 -0
  315. lightly_studio/utils/__init__.py +3 -0
  316. lightly_studio/utils/download.py +94 -0
  317. lightly_studio/vendor/__init__.py +1 -0
  318. lightly_studio/vendor/mobileclip/ACKNOWLEDGEMENTS +422 -0
  319. lightly_studio/vendor/mobileclip/LICENSE +31 -0
  320. lightly_studio/vendor/mobileclip/LICENSE_weights_data +50 -0
  321. lightly_studio/vendor/mobileclip/README.md +5 -0
  322. lightly_studio/vendor/mobileclip/__init__.py +96 -0
  323. lightly_studio/vendor/mobileclip/clip.py +77 -0
  324. lightly_studio/vendor/mobileclip/configs/mobileclip_b.json +18 -0
  325. lightly_studio/vendor/mobileclip/configs/mobileclip_s0.json +18 -0
  326. lightly_studio/vendor/mobileclip/configs/mobileclip_s1.json +18 -0
  327. lightly_studio/vendor/mobileclip/configs/mobileclip_s2.json +18 -0
  328. lightly_studio/vendor/mobileclip/image_encoder.py +67 -0
  329. lightly_studio/vendor/mobileclip/logger.py +154 -0
  330. lightly_studio/vendor/mobileclip/models/__init__.py +10 -0
  331. lightly_studio/vendor/mobileclip/models/mci.py +933 -0
  332. lightly_studio/vendor/mobileclip/models/vit.py +433 -0
  333. lightly_studio/vendor/mobileclip/modules/__init__.py +4 -0
  334. lightly_studio/vendor/mobileclip/modules/common/__init__.py +4 -0
  335. lightly_studio/vendor/mobileclip/modules/common/mobileone.py +341 -0
  336. lightly_studio/vendor/mobileclip/modules/common/transformer.py +451 -0
  337. lightly_studio/vendor/mobileclip/modules/image/__init__.py +4 -0
  338. lightly_studio/vendor/mobileclip/modules/image/image_projection.py +113 -0
  339. lightly_studio/vendor/mobileclip/modules/image/replknet.py +188 -0
  340. lightly_studio/vendor/mobileclip/modules/text/__init__.py +4 -0
  341. lightly_studio/vendor/mobileclip/modules/text/repmixer.py +281 -0
  342. lightly_studio/vendor/mobileclip/modules/text/tokenizer.py +38 -0
  343. lightly_studio/vendor/mobileclip/text_encoder.py +245 -0
  344. lightly_studio/vendor/perception_encoder/LICENSE.PE +201 -0
  345. lightly_studio/vendor/perception_encoder/README.md +11 -0
  346. lightly_studio/vendor/perception_encoder/vision_encoder/__init__.py +0 -0
  347. lightly_studio/vendor/perception_encoder/vision_encoder/bpe_simple_vocab_16e6.txt.gz +0 -0
  348. lightly_studio/vendor/perception_encoder/vision_encoder/config.py +205 -0
  349. lightly_studio/vendor/perception_encoder/vision_encoder/config_src.py +264 -0
  350. lightly_studio/vendor/perception_encoder/vision_encoder/pe.py +766 -0
  351. lightly_studio/vendor/perception_encoder/vision_encoder/rope.py +352 -0
  352. lightly_studio/vendor/perception_encoder/vision_encoder/tokenizer.py +347 -0
  353. lightly_studio/vendor/perception_encoder/vision_encoder/transforms.py +36 -0
  354. lightly_studio-0.4.6.dist-info/METADATA +88 -0
  355. lightly_studio-0.4.6.dist-info/RECORD +356 -0
  356. lightly_studio-0.4.6.dist-info/WHEEL +4 -0
@@ -0,0 +1,111 @@
1
+ """Example of how to register operators."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Any
7
+ from uuid import UUID
8
+
9
+ from environs import Env
10
+ from sqlmodel import Session
11
+
12
+ import lightly_studio as ls
13
+ from lightly_studio import db_manager
14
+ from lightly_studio.plugins.base_operator import BaseOperator, OperatorResult
15
+ from lightly_studio.plugins.operator_registry import operator_registry
16
+ from lightly_studio.plugins.parameter import (
17
+ BaseParameter,
18
+ BoolParameter,
19
+ FloatParameter,
20
+ IntParameter,
21
+ StringParameter,
22
+ )
23
+
24
+
25
+ @dataclass
26
+ class TestOperator(BaseOperator):
27
+ """Dummy Operator for demo purpose."""
28
+
29
+ name: str = "test operator"
30
+ description: str = "used to test the operator and registry system"
31
+
32
+ @property
33
+ def parameters(self) -> list[BaseParameter]:
34
+ """Return the list of parameters this operator expects."""
35
+ return [
36
+ BoolParameter(name="test flag", required=True),
37
+ StringParameter(name="test str", required=True, default="Good Morning"),
38
+ StringParameter(
39
+ name="test str 2", required=True, default="Another", description="Test Description"
40
+ ),
41
+ BoolParameter(
42
+ name="test flag 2", required=True, description="Test Description", default=True
43
+ ),
44
+ FloatParameter(name="test float", required=False, default=2.0, description="abc"),
45
+ IntParameter(name="test int", required=False, default=2),
46
+ IntParameter(name="test int 2", required=True, description="Yet another int"),
47
+ IntParameter(
48
+ name="test int 3",
49
+ required=True,
50
+ description=(
51
+ "Yet another int with a very long description. this will show how we will "
52
+ "overflow or what soever is happening to this text in the GUI. maybe it "
53
+ "exceeds maybe not. only time will tell"
54
+ ),
55
+ ),
56
+ ]
57
+
58
+ def execute(
59
+ self,
60
+ *,
61
+ session: Session,
62
+ dataset_id: UUID,
63
+ parameters: dict[str, Any],
64
+ ) -> OperatorResult:
65
+ """Execute the operator with the given parameters.
66
+
67
+ Args:
68
+ session: Database session.
69
+ dataset_id: ID of the dataset to operate on.
70
+ parameters: Parameters passed to the operator.
71
+
72
+ Returns:
73
+ Dictionary with 'success' (bool) and 'message' (str) keys.
74
+ """
75
+ return OperatorResult(
76
+ success=bool(parameters.get("test flag")),
77
+ message=str(parameters.get("test str"))
78
+ + " "
79
+ + str(parameters.get("test str 2"))
80
+ + " "
81
+ + str(parameters.get("test flag 2"))
82
+ + " "
83
+ + str(parameters.get("test float"))
84
+ + " "
85
+ + str(parameters.get("test int"))
86
+ + " "
87
+ + str(dataset_id)
88
+ + str(session),
89
+ )
90
+
91
+
92
+ # Read environment variables
93
+ env = Env()
94
+ env.read_env()
95
+
96
+ # Cleanup an existing database
97
+ db_manager.connect(cleanup_existing=True)
98
+
99
+ # Setup dummy operators
100
+ test = TestOperator()
101
+ for i in range(20):
102
+ operator_registry.register(operator=TestOperator(name=f"test_{i}"))
103
+
104
+ # Define data path
105
+ dataset_path = env.path("EXAMPLES_DATASET_PATH", "/path/to/your/dataset")
106
+
107
+ # Create a DatasetLoader from a path
108
+ dataset = ls.Dataset.create()
109
+ dataset.add_images_from_path(path=dataset_path)
110
+
111
+ ls.start_gui()
@@ -0,0 +1,28 @@
1
+ """Example of how to run selection class."""
2
+
3
+ from environs import Env
4
+
5
+ import lightly_studio as ls
6
+ from lightly_studio import db_manager
7
+
8
+ # Read environment variables
9
+ env = Env()
10
+ env.read_env()
11
+
12
+ # Cleanup an existing database
13
+ db_manager.connect(cleanup_existing=True)
14
+
15
+ # Define the path to the dataset directory
16
+ dataset_path = env.path("EXAMPLES_DATASET_PATH", "/path/to/your/dataset")
17
+
18
+ # Create a Dataset from a path
19
+ dataset = ls.Dataset.create()
20
+ dataset.add_images_from_path(path=str(dataset_path))
21
+
22
+ # Run selection via the dataset query
23
+ dataset.query().selection().diverse(
24
+ n_samples_to_select=10,
25
+ selection_result_tag_name="diverse_selection",
26
+ )
27
+
28
+ ls.start_gui()
@@ -0,0 +1,48 @@
1
+ """Example of how to add tags to samples to set up a split review workflow."""
2
+
3
+ import math
4
+
5
+ from environs import Env
6
+
7
+ import lightly_studio as ls
8
+ from lightly_studio import db_manager
9
+
10
+ # Read environment variables
11
+ env = Env()
12
+ env.read_env()
13
+
14
+ # Cleanup an existing database
15
+ db_manager.connect(cleanup_existing=True)
16
+
17
+ # Create a Dataset instance
18
+ dataset = ls.Dataset.create()
19
+
20
+ # Define the path to the dataset (folder containing data.yaml)
21
+ dataset_path = env.path("EXAMPLES_YOLO_YAML_PATH", "/path/to/your/yolo/dataset/data.yaml")
22
+ input_split = env.str("EXAMPLES_YOLO_SPLIT", "test")
23
+
24
+ # Load YOLO dataset using data.yaml path
25
+ dataset.add_samples_from_yolo(
26
+ data_yaml=dataset_path,
27
+ input_split=input_split,
28
+ )
29
+
30
+ # Define the reviewers
31
+ # This should be a comma-separated list of reviewers
32
+ # we will then create a tag for each reviewer and assign them samples
33
+ # to work on.
34
+ reviewers = env.str("DATASET_REVIEWERS", "Alice, Bob, Charlie, David")
35
+
36
+ # Create a tag for each reviewer to work on
37
+ tags = [reviewer.strip() for reviewer in reviewers.split(",")]
38
+
39
+ # Get all samples from the db
40
+ samples = dataset.query().to_list()
41
+
42
+ # Chunk the samples into portions equally divided among the reviewers.
43
+ chunk_size = math.ceil(len(samples) / len(tags))
44
+ for i, sample in enumerate(samples):
45
+ sample.add_tag(tags[i // chunk_size])
46
+
47
+ # Launch the server to load data
48
+ ls.start_gui()
@@ -0,0 +1,22 @@
1
+ """Example of how to load videos from path with the dataset class."""
2
+
3
+ from environs import Env
4
+
5
+ import lightly_studio as ls
6
+ from lightly_studio import db_manager
7
+
8
+ # Read environment variables
9
+ env = Env()
10
+ env.read_env()
11
+
12
+ # Cleanup an existing database
13
+ db_manager.connect(cleanup_existing=True)
14
+
15
+ # Define the path to the dataset directory
16
+ dataset_path = env.path("EXAMPLES_VIDEO_DATASET_PATH", "/path/to/your/dataset")
17
+
18
+ # Create a Dataset from a path
19
+ dataset = ls.Dataset.create(sample_type=ls.SampleType.VIDEO)
20
+ dataset.add_videos_from_path(path=dataset_path)
21
+
22
+ ls.start_gui()
@@ -0,0 +1,157 @@
1
+ """Example of how to load videos with annotations in YouTube-VIS format."""
2
+ # ruff: noqa: D102, D107
3
+
4
+ from __future__ import annotations
5
+
6
+ import json
7
+ from argparse import ArgumentParser
8
+ from pathlib import Path
9
+ from typing import Iterable
10
+ from uuid import UUID
11
+
12
+ import tqdm
13
+ from environs import Env
14
+ from labelformat.model.bounding_box import BoundingBox, BoundingBoxFormat
15
+ from labelformat.model.category import Category
16
+ from labelformat.model.image import Image
17
+ from labelformat.model.object_detection import (
18
+ ImageObjectDetection,
19
+ ObjectDetectionInput,
20
+ SingleObjectDetection,
21
+ )
22
+ from sqlmodel import Session
23
+
24
+ import lightly_studio as ls
25
+ from lightly_studio import db_manager
26
+ from lightly_studio.core import add_samples
27
+ from lightly_studio.resolvers import video_resolver
28
+
29
+
30
+ class YouTubeVISObjectDetectionInput(ObjectDetectionInput):
31
+ """Loads object detections from a modified YouTube-VIS format.
32
+
33
+ The annotation json format is without modification, but the images are loaded as videos.
34
+
35
+ This is a temporary hack until YouTubeVIS is supported natively in labelformat. The code
36
+ is adapted from labelformat's COCOObjectDetectionInput.
37
+ """
38
+
39
+ @staticmethod
40
+ def add_cli_arguments(parser: ArgumentParser) -> None:
41
+ raise NotImplementedError()
42
+
43
+ def __init__(self, input_file: Path) -> None:
44
+ with input_file.open() as file:
45
+ self._data = json.load(file)
46
+
47
+ def get_categories(self) -> Iterable[Category]:
48
+ for category in self._data["categories"]:
49
+ yield Category(
50
+ id=category["id"],
51
+ name=category["name"],
52
+ )
53
+
54
+ def get_images(self) -> Iterable[Image]:
55
+ for video in self._data["videos"]:
56
+ yield Image(
57
+ id=video["id"],
58
+ # The video name is <video_folder>.mp4
59
+ filename=Path(video["file_names"][0]).parent.name + ".mp4",
60
+ width=int(video["width"]),
61
+ height=int(video["height"]),
62
+ )
63
+
64
+ def get_labels(self) -> Iterable[ImageObjectDetection]:
65
+ video_id_to_video = {video.id: video for video in self.get_images()}
66
+ category_id_to_category = {category.id: category for category in self.get_categories()}
67
+
68
+ for annotation_json in self._data["annotations"]:
69
+ # Only extract bounding boxes, not segmentations. Every element in "bboxes"
70
+ # corresponds to one frame in the video.
71
+ frame_detections: list[SingleObjectDetection] = [
72
+ SingleObjectDetection(
73
+ category=category_id_to_category[annotation_json["category_id"]],
74
+ box=BoundingBox.from_format(bbox=bbox, format=BoundingBoxFormat.XYWH),
75
+ )
76
+ if bbox is not None
77
+ else SingleObjectDetection(
78
+ category=Category(-1, "no segmentation"),
79
+ box=BoundingBox.from_format(bbox=[0, 0, 0, 0], format=BoundingBoxFormat.XYWH),
80
+ )
81
+ for bbox in annotation_json["bboxes"]
82
+ ]
83
+ yield ImageObjectDetection(
84
+ image=video_id_to_video[annotation_json["video_id"]],
85
+ objects=frame_detections,
86
+ )
87
+
88
+
89
+ def load_annotations(session: Session, dataset_id: UUID, annotations_path: Path) -> None:
90
+ """Loads video annotations from a YouTube-VIS format.
91
+
92
+ Temporarily use internal add_samples API until labelformat supports videos natively.
93
+ """
94
+ print("Loading video annotations...")
95
+ videos = video_resolver.get_all_by_dataset_id_with_frames(
96
+ session=session, dataset_id=dataset_id
97
+ )
98
+ video_name_to_video = {video.file_name: video for video in videos}
99
+ yvis_input = YouTubeVISObjectDetectionInput(input_file=annotations_path)
100
+ label_map = add_samples._create_label_map( # noqa: SLF001
101
+ session=session,
102
+ input_labels=yvis_input,
103
+ )
104
+ for label in tqdm.tqdm(yvis_input.get_labels(), desc="Adding annotations", unit=" objects"):
105
+ video = video_name_to_video[label.image.filename]
106
+ assert len(label.objects) == len(video.frames), (
107
+ f"Number of frames in annotation ({len(label.objects)}) does not match "
108
+ f"number of frames in video ({len(video.frames)}) for video {label.image.filename}"
109
+ )
110
+ # Use frame index as path to match frames with annotations
111
+ path_to_id = {str(idx): frame.sample_id for idx, frame in enumerate(video.frames)}
112
+ path_to_anno_data = {
113
+ str(idx): ImageObjectDetection(
114
+ image=label.image,
115
+ objects=[obj],
116
+ )
117
+ if obj.category.id != -1
118
+ else ImageObjectDetection(
119
+ image=label.image,
120
+ objects=[],
121
+ )
122
+ for idx, obj in enumerate(label.objects)
123
+ }
124
+ add_samples._process_batch_annotations( # noqa: SLF001
125
+ session=session,
126
+ created_path_to_id=path_to_id,
127
+ path_to_anno_data=path_to_anno_data,
128
+ dataset_id=dataset_id,
129
+ label_map=label_map,
130
+ )
131
+
132
+
133
+ if __name__ == "__main__":
134
+ # Read environment variables
135
+ env = Env()
136
+ env.read_env()
137
+
138
+ # Cleanup an existing database
139
+ db_manager.connect(cleanup_existing=True)
140
+
141
+ # Define the path to the dataset directory
142
+ dataset_path = env.path("EXAMPLES_VIDEO_DATASET_PATH", "/path/to/your/dataset")
143
+ annotations_path = env.path(
144
+ "EXAMPLES_VIDEO_YVIS_JSON_PATH", "/path/to/your/dataset/instances.json"
145
+ )
146
+
147
+ # Create a Dataset from a path
148
+ dataset = ls.Dataset.create(sample_type=ls.SampleType.VIDEO)
149
+ dataset.add_videos_from_path(path=dataset_path)
150
+
151
+ # Load annotations
152
+ load_annotations(
153
+ session=dataset.session, dataset_id=dataset.dataset_id, annotations_path=annotations_path
154
+ )
155
+
156
+ # Start the GUI
157
+ ls.start_gui()
@@ -0,0 +1,22 @@
1
+ """Example of how to add samples in yolo format to a dataset."""
2
+
3
+ from environs import Env
4
+
5
+ import lightly_studio as ls
6
+ from lightly_studio import db_manager
7
+
8
+ # Read environment variables
9
+ env = Env()
10
+ env.read_env()
11
+
12
+ # Cleanup an existing database
13
+ db_manager.connect(cleanup_existing=True)
14
+
15
+ # Define the path to the dataset directory
16
+ dataset_path = env.path("EXAMPLES_YOLO_YAML_PATH", "/path/to/your/dataset/data.yaml")
17
+ input_split = env.str("EXAMPLES_YOLO_SPLIT", "train")
18
+
19
+ # Create a DatasetLoader from a path
20
+ dataset = ls.Dataset.create()
21
+ dataset.add_samples_from_yolo(data_yaml=dataset_path, input_split=input_split)
22
+ ls.start_gui()
@@ -0,0 +1,69 @@
1
+ """Helper module for exporting datasets in COCO captions format."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Iterable, TypedDict
6
+
7
+ from lightly_studio.core.image_sample import ImageSample
8
+
9
+
10
+ class CocoCaptionImage(TypedDict):
11
+ """Image schema for COCO captions format."""
12
+
13
+ id: int
14
+ file_name: str
15
+ width: int
16
+ height: int
17
+
18
+
19
+ class CocoCaptionAnnotation(TypedDict):
20
+ """Annotation schema for COCO captions format."""
21
+
22
+ id: int
23
+ image_id: int
24
+ caption: str
25
+
26
+
27
+ class CocoCaptionsJson(TypedDict):
28
+ """COCO captions JSON schema."""
29
+
30
+ images: list[CocoCaptionImage]
31
+ annotations: list[CocoCaptionAnnotation]
32
+
33
+
34
+ def to_coco_captions_dict(samples: Iterable[ImageSample]) -> CocoCaptionsJson:
35
+ """Convert samples with captions to a COCO captions dictionary.
36
+
37
+ Args:
38
+ samples: The samples to export.
39
+
40
+ Returns:
41
+ A dictionary in COCO captions format.
42
+ """
43
+ coco_images: list[CocoCaptionImage] = []
44
+ coco_annotations: list[CocoCaptionAnnotation] = []
45
+ annotation_id = 0
46
+
47
+ for image_id, image in enumerate(samples):
48
+ coco_images.append(
49
+ {
50
+ "id": image_id,
51
+ "file_name": image.file_path_abs,
52
+ "width": image.width,
53
+ "height": image.height,
54
+ }
55
+ )
56
+ for caption in image.captions:
57
+ coco_annotations.append(
58
+ {
59
+ "id": annotation_id,
60
+ "image_id": image_id,
61
+ "caption": caption,
62
+ }
63
+ )
64
+ annotation_id += 1
65
+
66
+ return {
67
+ "images": coco_images,
68
+ "annotations": coco_annotations,
69
+ }
@@ -0,0 +1,104 @@
1
+ """Exports datasets from Lightly Studio into various formats."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+ from typing import Iterable
8
+
9
+ from labelformat.formats import COCOObjectDetectionOutput
10
+ from sqlmodel import Session
11
+
12
+ from lightly_studio.core.image_sample import ImageSample
13
+ from lightly_studio.export import coco_captions
14
+ from lightly_studio.export.lightly_studio_label_input import LightlyStudioObjectDetectionInput
15
+ from lightly_studio.type_definitions import PathLike
16
+
17
+ DEFAULT_EXPORT_FILENAME = "coco_export.json"
18
+
19
+
20
+ class DatasetExport:
21
+ """Provides methods to export a dataset or a subset of it.
22
+
23
+ This class is typically not instantiated directly but returned by `Dataset.export()`.
24
+ It allows exporting data in various formats.
25
+ """
26
+
27
+ def __init__(self, session: Session, samples: Iterable[ImageSample]):
28
+ """Initializes the DatasetExport object.
29
+
30
+ Args:
31
+ session: The database session.
32
+ samples: Samples to export.
33
+ """
34
+ self.session = session
35
+ self.samples = samples
36
+
37
+ def to_coco_object_detections(self, output_json: PathLike | None = None) -> None:
38
+ """Exports object detection annotations to a COCO format JSON file.
39
+
40
+ Args:
41
+ output_json: The path to the output COCO JSON file. If not provided,
42
+ defaults to "coco_export.json" in the current working directory.
43
+
44
+ Raises:
45
+ ValueError: If the annotation task with the given name does not exist.
46
+ """
47
+ if output_json is None:
48
+ output_json = DEFAULT_EXPORT_FILENAME
49
+ to_coco_object_detections(
50
+ session=self.session,
51
+ samples=self.samples,
52
+ output_json=Path(output_json),
53
+ )
54
+
55
+ def to_coco_captions(self, output_json: PathLike | None = None) -> None:
56
+ """Exports captions to a COCO format JSON file.
57
+
58
+ Args:
59
+ output_json: The path to the output COCO JSON file. If not provided,
60
+ defaults to "coco_export.json" in the current working directory.
61
+ """
62
+ if output_json is None:
63
+ output_json = DEFAULT_EXPORT_FILENAME
64
+ to_coco_captions(samples=self.samples, output_json=Path(output_json))
65
+
66
+
67
+ def to_coco_object_detections(
68
+ session: Session,
69
+ samples: Iterable[ImageSample],
70
+ output_json: Path,
71
+ ) -> None:
72
+ """Exports object detection annotations to a COCO format JSON file.
73
+
74
+ This function is for internal use. Use `Dataset.query().export().to_coco_object_detections()`
75
+ instead.
76
+
77
+ Args:
78
+ session: The database session.
79
+ samples: The samples to export.
80
+ output_json: The path to save the output JSON file.
81
+ """
82
+ export_input = LightlyStudioObjectDetectionInput(
83
+ session=session,
84
+ samples=samples,
85
+ )
86
+ COCOObjectDetectionOutput(output_file=output_json).save(label_input=export_input)
87
+
88
+
89
+ def to_coco_captions(
90
+ samples: Iterable[ImageSample],
91
+ output_json: Path,
92
+ ) -> None:
93
+ """Exports captions to a COCO format JSON file.
94
+
95
+ This function is for internal use. Use `Dataset.query().export().to_coco_captions()`
96
+ instead.
97
+
98
+ Args:
99
+ samples: The samples to export.
100
+ output_json: The path to save the output JSON file.
101
+ """
102
+ coco_captions_dict = coco_captions.to_coco_captions_dict(samples=samples)
103
+ with output_json.open("w") as f:
104
+ json.dump(coco_captions_dict, f, indent=2)
@@ -0,0 +1,120 @@
1
+ """Converts annotations from Lightly Studio to Labelformat format."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from argparse import ArgumentParser
6
+ from typing import Iterable
7
+ from uuid import UUID
8
+
9
+ from labelformat.model.bounding_box import BoundingBox
10
+ from labelformat.model.category import Category
11
+ from labelformat.model.image import Image
12
+ from labelformat.model.object_detection import (
13
+ ImageObjectDetection,
14
+ ObjectDetectionInput,
15
+ SingleObjectDetection,
16
+ )
17
+ from sqlmodel import Session
18
+
19
+ from lightly_studio.core.image_sample import ImageSample
20
+ from lightly_studio.models.annotation.annotation_base import AnnotationBaseTable, AnnotationType
21
+ from lightly_studio.resolvers import annotation_label_resolver
22
+
23
+
24
+ class LightlyStudioObjectDetectionInput(ObjectDetectionInput):
25
+ """Labelformat adapter backed by dataset samples and annotations."""
26
+
27
+ def __init__(self, session: Session, samples: Iterable[ImageSample]) -> None:
28
+ """Initializes the LightlyStudioObjectDetectionInput.
29
+
30
+ Args:
31
+ session: The SQLModel session to use for database access. Used only in the
32
+ constructor to fetch the labels for the given annotation task.
33
+ samples: Dataset samples.
34
+ """
35
+ self._samples = list(samples)
36
+ self._label_id_to_category = _build_label_id_to_category(session=session)
37
+
38
+ @staticmethod
39
+ def add_cli_arguments(parser: ArgumentParser) -> None:
40
+ """Adds CLI arguments."""
41
+ # Add CLI arguments implementation is not needed for this class. We need it only
42
+ # to satisfy the interface.
43
+ raise NotImplementedError()
44
+
45
+ def get_categories(self) -> Iterable[Category]:
46
+ """Returns the categories for export."""
47
+ return self._label_id_to_category.values()
48
+
49
+ def get_images(self) -> Iterable[Image]:
50
+ """Returns the images for export."""
51
+ for idx, sample in enumerate(self._samples):
52
+ yield _sample_to_image(sample=sample, image_id=idx)
53
+
54
+ def get_labels(self) -> Iterable[ImageObjectDetection]:
55
+ """Returns the labels for export."""
56
+ for idx, sample in enumerate(self._samples):
57
+ yield _sample_to_image_obj_det(
58
+ sample=sample,
59
+ image_id=idx,
60
+ label_id_to_category=self._label_id_to_category,
61
+ )
62
+
63
+
64
+ def _build_label_id_to_category(session: Session) -> dict[UUID, Category]:
65
+ labels = annotation_label_resolver.get_all_sorted_alphabetically(
66
+ session=session,
67
+ )
68
+ # TODO(Horatiu, 09/2025): We should get only labels that are attached to Object Detection
69
+ # annotations.
70
+ return {
71
+ label.annotation_label_id: Category(id=idx, name=label.annotation_label_name)
72
+ for idx, label in enumerate(labels)
73
+ }
74
+
75
+
76
+ def _sample_to_image(sample: ImageSample, image_id: int) -> Image:
77
+ return Image(
78
+ id=image_id,
79
+ filename=sample.file_path_abs,
80
+ width=sample.width,
81
+ height=sample.height,
82
+ )
83
+
84
+
85
+ def _sample_to_image_obj_det(
86
+ sample: ImageSample,
87
+ image_id: int,
88
+ label_id_to_category: dict[UUID, Category],
89
+ ) -> ImageObjectDetection:
90
+ # TODO(Michal, 09/2025): We can optimise in the future to filter annotations in a DB query.
91
+ objects = [
92
+ _annotation_to_single_obj_det(
93
+ annotation=annotation,
94
+ label_id_to_category=label_id_to_category,
95
+ )
96
+ for annotation in sample.sample_table.annotations
97
+ if annotation.annotation_type == AnnotationType.OBJECT_DETECTION
98
+ ]
99
+ return ImageObjectDetection(
100
+ image=_sample_to_image(sample=sample, image_id=image_id),
101
+ objects=objects,
102
+ )
103
+
104
+
105
+ def _annotation_to_single_obj_det(
106
+ annotation: AnnotationBaseTable, label_id_to_category: dict[UUID, Category]
107
+ ) -> SingleObjectDetection:
108
+ assert annotation.object_detection_details is not None
109
+ box = BoundingBox(
110
+ xmin=annotation.object_detection_details.x,
111
+ ymin=annotation.object_detection_details.y,
112
+ xmax=annotation.object_detection_details.x + annotation.object_detection_details.width,
113
+ ymax=annotation.object_detection_details.y + annotation.object_detection_details.height,
114
+ )
115
+ category = label_id_to_category[annotation.annotation_label.annotation_label_id]
116
+ return SingleObjectDetection(
117
+ category=category,
118
+ box=box,
119
+ confidence=annotation.confidence,
120
+ )