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.
- lightly_studio/__init__.py +12 -0
- lightly_studio/api/__init__.py +0 -0
- lightly_studio/api/app.py +131 -0
- lightly_studio/api/cache.py +77 -0
- lightly_studio/api/db_tables.py +35 -0
- lightly_studio/api/features.py +5 -0
- lightly_studio/api/routes/api/annotation.py +305 -0
- lightly_studio/api/routes/api/annotation_label.py +87 -0
- lightly_studio/api/routes/api/annotations/__init__.py +7 -0
- lightly_studio/api/routes/api/annotations/create_annotation.py +52 -0
- lightly_studio/api/routes/api/caption.py +100 -0
- lightly_studio/api/routes/api/classifier.py +384 -0
- lightly_studio/api/routes/api/dataset.py +191 -0
- lightly_studio/api/routes/api/dataset_tag.py +266 -0
- lightly_studio/api/routes/api/embeddings2d.py +90 -0
- lightly_studio/api/routes/api/exceptions.py +114 -0
- lightly_studio/api/routes/api/export.py +114 -0
- lightly_studio/api/routes/api/features.py +17 -0
- lightly_studio/api/routes/api/frame.py +241 -0
- lightly_studio/api/routes/api/image.py +155 -0
- lightly_studio/api/routes/api/metadata.py +161 -0
- lightly_studio/api/routes/api/operator.py +75 -0
- lightly_studio/api/routes/api/sample.py +103 -0
- lightly_studio/api/routes/api/selection.py +87 -0
- lightly_studio/api/routes/api/settings.py +41 -0
- lightly_studio/api/routes/api/status.py +19 -0
- lightly_studio/api/routes/api/text_embedding.py +50 -0
- lightly_studio/api/routes/api/validators.py +17 -0
- lightly_studio/api/routes/api/video.py +133 -0
- lightly_studio/api/routes/healthz.py +13 -0
- lightly_studio/api/routes/images.py +104 -0
- lightly_studio/api/routes/video_frames_media.py +116 -0
- lightly_studio/api/routes/video_media.py +223 -0
- lightly_studio/api/routes/webapp.py +51 -0
- lightly_studio/api/server.py +94 -0
- lightly_studio/core/__init__.py +0 -0
- lightly_studio/core/add_samples.py +533 -0
- lightly_studio/core/add_videos.py +294 -0
- lightly_studio/core/dataset.py +780 -0
- lightly_studio/core/dataset_query/__init__.py +14 -0
- lightly_studio/core/dataset_query/boolean_expression.py +67 -0
- lightly_studio/core/dataset_query/dataset_query.py +317 -0
- lightly_studio/core/dataset_query/field.py +113 -0
- lightly_studio/core/dataset_query/field_expression.py +79 -0
- lightly_studio/core/dataset_query/match_expression.py +23 -0
- lightly_studio/core/dataset_query/order_by.py +79 -0
- lightly_studio/core/dataset_query/sample_field.py +37 -0
- lightly_studio/core/dataset_query/tags_expression.py +46 -0
- lightly_studio/core/image_sample.py +36 -0
- lightly_studio/core/loading_log.py +56 -0
- lightly_studio/core/sample.py +291 -0
- lightly_studio/core/start_gui.py +54 -0
- lightly_studio/core/video_sample.py +38 -0
- lightly_studio/dataset/__init__.py +0 -0
- lightly_studio/dataset/edge_embedding_generator.py +155 -0
- lightly_studio/dataset/embedding_generator.py +129 -0
- lightly_studio/dataset/embedding_manager.py +349 -0
- lightly_studio/dataset/env.py +20 -0
- lightly_studio/dataset/file_utils.py +49 -0
- lightly_studio/dataset/fsspec_lister.py +275 -0
- lightly_studio/dataset/mobileclip_embedding_generator.py +158 -0
- lightly_studio/dataset/perception_encoder_embedding_generator.py +260 -0
- lightly_studio/db_manager.py +166 -0
- lightly_studio/dist_lightly_studio_view_app/_app/env.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/0.GcXvs2l7.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/12.Dx6SXgAb.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/17.9X9_k6TP.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/18.BxiimdIO.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/2.CkOblLn7.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/ClassifierSamplesGrid.BJbCDlvs.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/LightlyLogo.BNjCIww-.png +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Bold.DGvYQtcs.ttf +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Italic-VariableFont_wdth_wght.B4AZ-wl6.ttf +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Medium.DVUZMR_6.ttf +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Regular.DxJTClRG.ttf +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-SemiBold.D3TTYgdB.ttf +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-VariableFont_wdth_wght.BZBpG5Iz.ttf +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_layout.CefECEWA.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_layout.D5tDcjY-.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_page.9X9_k6TP.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_page.BxiimdIO.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_page.Dx6SXgAb.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/transform._-1mPSEI.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/0dDyq72A.js +20 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/69_IOA4Y.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BK4An2kI.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BRmB-kJ9.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/B_1cpokE.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BiqpDEr0.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BpLiSKgx.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BscxbINH.js +39 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C1FmrZbK.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C80h3dJx.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C8mfFM-u.js +2 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CGY1p9L4.js +517 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/COfLknXM.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CWj6FrbW.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CYgJF_JY.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CmLg0ys7.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CvGjimpO.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D3RDXHoj.js +39 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D4y7iiT3.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D9SC3jBb.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DCuAdx1Q.js +20 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DDBy-_jD.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DIeogL5L.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DL9a7v5o.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DSKECuqX.js +39 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D_FFv0Oe.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DiZ5o5vz.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DkbXUtyG.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DmK2hulV.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DqnHaLTj.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DtWZc_tl.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DuUalyFS.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DwIonDAZ.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Il-mSPmK.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/KNLP4aJU.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/KjYeVjkE.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/MErlcOXj.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/VRI4prUD.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/VYb2dkNs.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/VqWvU2yF.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/dHC3otuL.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/da7Oy_lO.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/eAy8rZzC.js +2 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/erjNR5MX.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/f1oG3eFE.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/rsLi1iKv.js +20 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/rwuuBP9f.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/xGHZQ1pe.js +3 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/app.DrTRUgT3.js +2 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/start.BK5EOJl2.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/0.CIvTuljF.js +4 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/1.UBvSzxdA.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/10.CQ_tiLJa.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/11.KqkAcaxW.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/12.DoYsmxQc.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/13.571n2LZA.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/14.DGs689M-.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/15.CWG1ehzT.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/16.Dpq6jbSh.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/17.B5AZbHUU.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/18.CBga8cnq.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/2.D2HXgz-8.js +1090 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/3.f4HAg-y3.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/4.BKF4xuKQ.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/5.BAE0Pm_f.js +39 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/6.CouWWpzA.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/7.UBHT0ktp.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/8.FiYNElcc.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/9.B3-UaT23.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/workers/clustering.worker-DKqeLtG0.js +2 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/workers/search.worker-vNSty3B0.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/version.json +1 -0
- lightly_studio/dist_lightly_studio_view_app/apple-touch-icon-precomposed.png +0 -0
- lightly_studio/dist_lightly_studio_view_app/apple-touch-icon.png +0 -0
- lightly_studio/dist_lightly_studio_view_app/favicon.png +0 -0
- lightly_studio/dist_lightly_studio_view_app/index.html +45 -0
- lightly_studio/errors.py +5 -0
- lightly_studio/examples/example.py +25 -0
- lightly_studio/examples/example_coco.py +27 -0
- lightly_studio/examples/example_coco_caption.py +29 -0
- lightly_studio/examples/example_metadata.py +369 -0
- lightly_studio/examples/example_operators.py +111 -0
- lightly_studio/examples/example_selection.py +28 -0
- lightly_studio/examples/example_split_work.py +48 -0
- lightly_studio/examples/example_video.py +22 -0
- lightly_studio/examples/example_video_annotations.py +157 -0
- lightly_studio/examples/example_yolo.py +22 -0
- lightly_studio/export/coco_captions.py +69 -0
- lightly_studio/export/export_dataset.py +104 -0
- lightly_studio/export/lightly_studio_label_input.py +120 -0
- lightly_studio/export_schema.py +18 -0
- lightly_studio/export_version.py +57 -0
- lightly_studio/few_shot_classifier/__init__.py +0 -0
- lightly_studio/few_shot_classifier/classifier.py +80 -0
- lightly_studio/few_shot_classifier/classifier_manager.py +644 -0
- lightly_studio/few_shot_classifier/random_forest_classifier.py +495 -0
- lightly_studio/metadata/complex_metadata.py +47 -0
- lightly_studio/metadata/compute_similarity.py +84 -0
- lightly_studio/metadata/compute_typicality.py +67 -0
- lightly_studio/metadata/gps_coordinate.py +41 -0
- lightly_studio/metadata/metadata_protocol.py +17 -0
- lightly_studio/models/__init__.py +1 -0
- lightly_studio/models/annotation/__init__.py +0 -0
- lightly_studio/models/annotation/annotation_base.py +303 -0
- lightly_studio/models/annotation/instance_segmentation.py +56 -0
- lightly_studio/models/annotation/links.py +17 -0
- lightly_studio/models/annotation/object_detection.py +47 -0
- lightly_studio/models/annotation/semantic_segmentation.py +44 -0
- lightly_studio/models/annotation_label.py +47 -0
- lightly_studio/models/caption.py +49 -0
- lightly_studio/models/classifier.py +20 -0
- lightly_studio/models/dataset.py +70 -0
- lightly_studio/models/embedding_model.py +30 -0
- lightly_studio/models/image.py +96 -0
- lightly_studio/models/metadata.py +208 -0
- lightly_studio/models/range.py +17 -0
- lightly_studio/models/sample.py +154 -0
- lightly_studio/models/sample_embedding.py +36 -0
- lightly_studio/models/settings.py +69 -0
- lightly_studio/models/tag.py +96 -0
- lightly_studio/models/two_dim_embedding.py +16 -0
- lightly_studio/models/video.py +161 -0
- lightly_studio/plugins/__init__.py +0 -0
- lightly_studio/plugins/base_operator.py +60 -0
- lightly_studio/plugins/operator_registry.py +47 -0
- lightly_studio/plugins/parameter.py +70 -0
- lightly_studio/py.typed +0 -0
- lightly_studio/resolvers/__init__.py +0 -0
- lightly_studio/resolvers/annotation_label_resolver/__init__.py +22 -0
- lightly_studio/resolvers/annotation_label_resolver/create.py +27 -0
- lightly_studio/resolvers/annotation_label_resolver/delete.py +28 -0
- lightly_studio/resolvers/annotation_label_resolver/get_all.py +37 -0
- lightly_studio/resolvers/annotation_label_resolver/get_by_id.py +24 -0
- lightly_studio/resolvers/annotation_label_resolver/get_by_ids.py +25 -0
- lightly_studio/resolvers/annotation_label_resolver/get_by_label_name.py +24 -0
- lightly_studio/resolvers/annotation_label_resolver/names_by_ids.py +25 -0
- lightly_studio/resolvers/annotation_label_resolver/update.py +38 -0
- lightly_studio/resolvers/annotation_resolver/__init__.py +40 -0
- lightly_studio/resolvers/annotation_resolver/count_annotations_by_dataset.py +129 -0
- lightly_studio/resolvers/annotation_resolver/create_many.py +124 -0
- lightly_studio/resolvers/annotation_resolver/delete_annotation.py +87 -0
- lightly_studio/resolvers/annotation_resolver/delete_annotations.py +60 -0
- lightly_studio/resolvers/annotation_resolver/get_all.py +85 -0
- lightly_studio/resolvers/annotation_resolver/get_all_with_payload.py +179 -0
- lightly_studio/resolvers/annotation_resolver/get_by_id.py +34 -0
- lightly_studio/resolvers/annotation_resolver/get_by_id_with_payload.py +130 -0
- lightly_studio/resolvers/annotation_resolver/update_annotation_label.py +142 -0
- lightly_studio/resolvers/annotation_resolver/update_bounding_box.py +68 -0
- lightly_studio/resolvers/annotations/__init__.py +1 -0
- lightly_studio/resolvers/annotations/annotations_filter.py +88 -0
- lightly_studio/resolvers/caption_resolver.py +129 -0
- lightly_studio/resolvers/dataset_resolver/__init__.py +55 -0
- lightly_studio/resolvers/dataset_resolver/check_dataset_type.py +29 -0
- lightly_studio/resolvers/dataset_resolver/create.py +20 -0
- lightly_studio/resolvers/dataset_resolver/delete.py +20 -0
- lightly_studio/resolvers/dataset_resolver/export.py +267 -0
- lightly_studio/resolvers/dataset_resolver/get_all.py +19 -0
- lightly_studio/resolvers/dataset_resolver/get_by_id.py +16 -0
- lightly_studio/resolvers/dataset_resolver/get_by_name.py +12 -0
- lightly_studio/resolvers/dataset_resolver/get_dataset_details.py +27 -0
- lightly_studio/resolvers/dataset_resolver/get_hierarchy.py +31 -0
- lightly_studio/resolvers/dataset_resolver/get_or_create_child_dataset.py +58 -0
- lightly_studio/resolvers/dataset_resolver/get_parent_dataset_by_sample_id.py +27 -0
- lightly_studio/resolvers/dataset_resolver/get_parent_dataset_id.py +22 -0
- lightly_studio/resolvers/dataset_resolver/get_root_dataset.py +61 -0
- lightly_studio/resolvers/dataset_resolver/get_root_datasets_overview.py +41 -0
- lightly_studio/resolvers/dataset_resolver/update.py +25 -0
- lightly_studio/resolvers/embedding_model_resolver.py +120 -0
- lightly_studio/resolvers/image_filter.py +50 -0
- lightly_studio/resolvers/image_resolver/__init__.py +21 -0
- lightly_studio/resolvers/image_resolver/create_many.py +52 -0
- lightly_studio/resolvers/image_resolver/delete.py +20 -0
- lightly_studio/resolvers/image_resolver/filter_new_paths.py +23 -0
- lightly_studio/resolvers/image_resolver/get_all_by_dataset_id.py +117 -0
- lightly_studio/resolvers/image_resolver/get_by_id.py +14 -0
- lightly_studio/resolvers/image_resolver/get_dimension_bounds.py +75 -0
- lightly_studio/resolvers/image_resolver/get_many_by_id.py +22 -0
- lightly_studio/resolvers/image_resolver/get_samples_excluding.py +43 -0
- lightly_studio/resolvers/metadata_resolver/__init__.py +15 -0
- lightly_studio/resolvers/metadata_resolver/metadata_filter.py +163 -0
- lightly_studio/resolvers/metadata_resolver/sample/__init__.py +21 -0
- lightly_studio/resolvers/metadata_resolver/sample/bulk_update_metadata.py +46 -0
- lightly_studio/resolvers/metadata_resolver/sample/get_by_sample_id.py +24 -0
- lightly_studio/resolvers/metadata_resolver/sample/get_metadata_info.py +104 -0
- lightly_studio/resolvers/metadata_resolver/sample/get_value_for_sample.py +27 -0
- lightly_studio/resolvers/metadata_resolver/sample/set_value_for_sample.py +53 -0
- lightly_studio/resolvers/sample_embedding_resolver.py +132 -0
- lightly_studio/resolvers/sample_resolver/__init__.py +17 -0
- lightly_studio/resolvers/sample_resolver/count_by_dataset_id.py +16 -0
- lightly_studio/resolvers/sample_resolver/create.py +16 -0
- lightly_studio/resolvers/sample_resolver/create_many.py +25 -0
- lightly_studio/resolvers/sample_resolver/get_by_id.py +14 -0
- lightly_studio/resolvers/sample_resolver/get_filtered_samples.py +56 -0
- lightly_studio/resolvers/sample_resolver/get_many_by_id.py +22 -0
- lightly_studio/resolvers/sample_resolver/sample_filter.py +74 -0
- lightly_studio/resolvers/settings_resolver.py +62 -0
- lightly_studio/resolvers/tag_resolver.py +299 -0
- lightly_studio/resolvers/twodim_embedding_resolver.py +119 -0
- lightly_studio/resolvers/video_frame_resolver/__init__.py +23 -0
- lightly_studio/resolvers/video_frame_resolver/count_video_frames_annotations.py +83 -0
- lightly_studio/resolvers/video_frame_resolver/create_many.py +57 -0
- lightly_studio/resolvers/video_frame_resolver/get_all_by_dataset_id.py +63 -0
- lightly_studio/resolvers/video_frame_resolver/get_by_id.py +13 -0
- lightly_studio/resolvers/video_frame_resolver/get_table_fields_bounds.py +44 -0
- lightly_studio/resolvers/video_frame_resolver/video_frame_annotations_counter_filter.py +47 -0
- lightly_studio/resolvers/video_frame_resolver/video_frame_filter.py +57 -0
- lightly_studio/resolvers/video_resolver/__init__.py +27 -0
- lightly_studio/resolvers/video_resolver/count_video_frame_annotations_by_video_dataset.py +86 -0
- lightly_studio/resolvers/video_resolver/create_many.py +58 -0
- lightly_studio/resolvers/video_resolver/filter_new_paths.py +33 -0
- lightly_studio/resolvers/video_resolver/get_all_by_dataset_id.py +181 -0
- lightly_studio/resolvers/video_resolver/get_by_id.py +22 -0
- lightly_studio/resolvers/video_resolver/get_table_fields_bounds.py +72 -0
- lightly_studio/resolvers/video_resolver/get_view_by_id.py +52 -0
- lightly_studio/resolvers/video_resolver/video_count_annotations_filter.py +50 -0
- lightly_studio/resolvers/video_resolver/video_filter.py +98 -0
- lightly_studio/selection/__init__.py +1 -0
- lightly_studio/selection/mundig.py +143 -0
- lightly_studio/selection/select.py +203 -0
- lightly_studio/selection/select_via_db.py +273 -0
- lightly_studio/selection/selection_config.py +49 -0
- lightly_studio/services/annotations_service/__init__.py +33 -0
- lightly_studio/services/annotations_service/create_annotation.py +64 -0
- lightly_studio/services/annotations_service/delete_annotation.py +22 -0
- lightly_studio/services/annotations_service/get_annotation_by_id.py +31 -0
- lightly_studio/services/annotations_service/update_annotation.py +54 -0
- lightly_studio/services/annotations_service/update_annotation_bounding_box.py +36 -0
- lightly_studio/services/annotations_service/update_annotation_label.py +48 -0
- lightly_studio/services/annotations_service/update_annotations.py +29 -0
- lightly_studio/setup_logging.py +59 -0
- lightly_studio/type_definitions.py +31 -0
- lightly_studio/utils/__init__.py +3 -0
- lightly_studio/utils/download.py +94 -0
- lightly_studio/vendor/__init__.py +1 -0
- lightly_studio/vendor/mobileclip/ACKNOWLEDGEMENTS +422 -0
- lightly_studio/vendor/mobileclip/LICENSE +31 -0
- lightly_studio/vendor/mobileclip/LICENSE_weights_data +50 -0
- lightly_studio/vendor/mobileclip/README.md +5 -0
- lightly_studio/vendor/mobileclip/__init__.py +96 -0
- lightly_studio/vendor/mobileclip/clip.py +77 -0
- lightly_studio/vendor/mobileclip/configs/mobileclip_b.json +18 -0
- lightly_studio/vendor/mobileclip/configs/mobileclip_s0.json +18 -0
- lightly_studio/vendor/mobileclip/configs/mobileclip_s1.json +18 -0
- lightly_studio/vendor/mobileclip/configs/mobileclip_s2.json +18 -0
- lightly_studio/vendor/mobileclip/image_encoder.py +67 -0
- lightly_studio/vendor/mobileclip/logger.py +154 -0
- lightly_studio/vendor/mobileclip/models/__init__.py +10 -0
- lightly_studio/vendor/mobileclip/models/mci.py +933 -0
- lightly_studio/vendor/mobileclip/models/vit.py +433 -0
- lightly_studio/vendor/mobileclip/modules/__init__.py +4 -0
- lightly_studio/vendor/mobileclip/modules/common/__init__.py +4 -0
- lightly_studio/vendor/mobileclip/modules/common/mobileone.py +341 -0
- lightly_studio/vendor/mobileclip/modules/common/transformer.py +451 -0
- lightly_studio/vendor/mobileclip/modules/image/__init__.py +4 -0
- lightly_studio/vendor/mobileclip/modules/image/image_projection.py +113 -0
- lightly_studio/vendor/mobileclip/modules/image/replknet.py +188 -0
- lightly_studio/vendor/mobileclip/modules/text/__init__.py +4 -0
- lightly_studio/vendor/mobileclip/modules/text/repmixer.py +281 -0
- lightly_studio/vendor/mobileclip/modules/text/tokenizer.py +38 -0
- lightly_studio/vendor/mobileclip/text_encoder.py +245 -0
- lightly_studio/vendor/perception_encoder/LICENSE.PE +201 -0
- lightly_studio/vendor/perception_encoder/README.md +11 -0
- lightly_studio/vendor/perception_encoder/vision_encoder/__init__.py +0 -0
- lightly_studio/vendor/perception_encoder/vision_encoder/bpe_simple_vocab_16e6.txt.gz +0 -0
- lightly_studio/vendor/perception_encoder/vision_encoder/config.py +205 -0
- lightly_studio/vendor/perception_encoder/vision_encoder/config_src.py +264 -0
- lightly_studio/vendor/perception_encoder/vision_encoder/pe.py +766 -0
- lightly_studio/vendor/perception_encoder/vision_encoder/rope.py +352 -0
- lightly_studio/vendor/perception_encoder/vision_encoder/tokenizer.py +347 -0
- lightly_studio/vendor/perception_encoder/vision_encoder/transforms.py +36 -0
- lightly_studio-0.4.6.dist-info/METADATA +88 -0
- lightly_studio-0.4.6.dist-info/RECORD +356 -0
- lightly_studio-0.4.6.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Update annotation label functionality."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from sqlmodel import Session
|
|
8
|
+
|
|
9
|
+
from lightly_studio.models.annotation_label import (
|
|
10
|
+
AnnotationLabelCreate,
|
|
11
|
+
AnnotationLabelTable,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from .get_by_id import get_by_id
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def update(
|
|
18
|
+
session: Session, label_id: UUID, label_data: AnnotationLabelCreate
|
|
19
|
+
) -> AnnotationLabelTable | None:
|
|
20
|
+
"""Update an existing annotation label.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
session (Session): The database session.
|
|
24
|
+
label_id (UUID): The identifier of the annotation label to update.
|
|
25
|
+
label_data (AnnotationLabelCreate): The new data.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
AnnotationLabelTable | None: The updated annotation label if it exists,
|
|
29
|
+
otherwise None.
|
|
30
|
+
"""
|
|
31
|
+
label = get_by_id(session=session, label_id=label_id)
|
|
32
|
+
if not label:
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
label.annotation_label_name = label_data.annotation_label_name
|
|
36
|
+
session.commit()
|
|
37
|
+
session.refresh(label)
|
|
38
|
+
return label
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Resolvers for database operations."""
|
|
2
|
+
|
|
3
|
+
from lightly_studio.resolvers.annotation_resolver.count_annotations_by_dataset import (
|
|
4
|
+
count_annotations_by_dataset,
|
|
5
|
+
)
|
|
6
|
+
from lightly_studio.resolvers.annotation_resolver.create_many import create_many
|
|
7
|
+
from lightly_studio.resolvers.annotation_resolver.delete_annotation import (
|
|
8
|
+
delete_annotation,
|
|
9
|
+
)
|
|
10
|
+
from lightly_studio.resolvers.annotation_resolver.delete_annotations import (
|
|
11
|
+
delete_annotations,
|
|
12
|
+
)
|
|
13
|
+
from lightly_studio.resolvers.annotation_resolver.get_all import get_all
|
|
14
|
+
from lightly_studio.resolvers.annotation_resolver.get_all_with_payload import (
|
|
15
|
+
get_all_with_payload,
|
|
16
|
+
)
|
|
17
|
+
from lightly_studio.resolvers.annotation_resolver.get_by_id import get_by_id, get_by_ids
|
|
18
|
+
from lightly_studio.resolvers.annotation_resolver.get_by_id_with_payload import (
|
|
19
|
+
get_by_id_with_payload,
|
|
20
|
+
)
|
|
21
|
+
from lightly_studio.resolvers.annotation_resolver.update_annotation_label import (
|
|
22
|
+
update_annotation_label,
|
|
23
|
+
)
|
|
24
|
+
from lightly_studio.resolvers.annotation_resolver.update_bounding_box import (
|
|
25
|
+
update_bounding_box,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"count_annotations_by_dataset",
|
|
30
|
+
"create_many",
|
|
31
|
+
"delete_annotation",
|
|
32
|
+
"delete_annotations",
|
|
33
|
+
"get_all",
|
|
34
|
+
"get_all_with_payload",
|
|
35
|
+
"get_by_id",
|
|
36
|
+
"get_by_id_with_payload",
|
|
37
|
+
"get_by_ids",
|
|
38
|
+
"update_annotation_label",
|
|
39
|
+
"update_bounding_box",
|
|
40
|
+
]
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""Handler for database operations related to annotations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from sqlmodel import Session, col, func, select
|
|
8
|
+
|
|
9
|
+
from lightly_studio.models.annotation.annotation_base import (
|
|
10
|
+
AnnotationBaseTable,
|
|
11
|
+
)
|
|
12
|
+
from lightly_studio.models.annotation_label import AnnotationLabelTable
|
|
13
|
+
from lightly_studio.models.image import ImageTable
|
|
14
|
+
from lightly_studio.models.sample import SampleTable
|
|
15
|
+
from lightly_studio.models.tag import TagTable
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def count_annotations_by_dataset( # noqa: PLR0913 // FIXME: refactor to use proper pydantic
|
|
19
|
+
session: Session,
|
|
20
|
+
dataset_id: UUID,
|
|
21
|
+
filtered_labels: list[str] | None = None,
|
|
22
|
+
min_width: int | None = None,
|
|
23
|
+
max_width: int | None = None,
|
|
24
|
+
min_height: int | None = None,
|
|
25
|
+
max_height: int | None = None,
|
|
26
|
+
tag_ids: list[UUID] | None = None,
|
|
27
|
+
) -> list[tuple[str, int, int]]:
|
|
28
|
+
"""Count annotations for a specific dataset.
|
|
29
|
+
|
|
30
|
+
Annotations for a specific dataset are grouped by annotation
|
|
31
|
+
label name and counted for total and filtered.
|
|
32
|
+
"""
|
|
33
|
+
# Query for total counts (unfiltered)
|
|
34
|
+
total_counts_query = (
|
|
35
|
+
select(
|
|
36
|
+
AnnotationLabelTable.annotation_label_name,
|
|
37
|
+
func.count(col(AnnotationBaseTable.sample_id)).label("total_count"),
|
|
38
|
+
)
|
|
39
|
+
.join(
|
|
40
|
+
AnnotationBaseTable,
|
|
41
|
+
col(AnnotationBaseTable.annotation_label_id)
|
|
42
|
+
== col(AnnotationLabelTable.annotation_label_id),
|
|
43
|
+
)
|
|
44
|
+
.join(
|
|
45
|
+
ImageTable,
|
|
46
|
+
col(ImageTable.sample_id) == col(AnnotationBaseTable.parent_sample_id),
|
|
47
|
+
)
|
|
48
|
+
.join(
|
|
49
|
+
SampleTable,
|
|
50
|
+
col(SampleTable.sample_id) == col(ImageTable.sample_id),
|
|
51
|
+
)
|
|
52
|
+
.where(SampleTable.dataset_id == dataset_id)
|
|
53
|
+
.group_by(AnnotationLabelTable.annotation_label_name)
|
|
54
|
+
.order_by(col(AnnotationLabelTable.annotation_label_name).asc())
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
total_counts = {row[0]: row[1] for row in session.exec(total_counts_query).all()}
|
|
58
|
+
|
|
59
|
+
# Build filtered query for current counts
|
|
60
|
+
filtered_query = (
|
|
61
|
+
select(
|
|
62
|
+
AnnotationLabelTable.annotation_label_name,
|
|
63
|
+
func.count(col(AnnotationBaseTable.sample_id)).label("current_count"),
|
|
64
|
+
)
|
|
65
|
+
.join(
|
|
66
|
+
AnnotationBaseTable,
|
|
67
|
+
col(AnnotationBaseTable.annotation_label_id)
|
|
68
|
+
== col(AnnotationLabelTable.annotation_label_id),
|
|
69
|
+
)
|
|
70
|
+
.join(
|
|
71
|
+
ImageTable,
|
|
72
|
+
col(ImageTable.sample_id) == col(AnnotationBaseTable.parent_sample_id),
|
|
73
|
+
)
|
|
74
|
+
.join(
|
|
75
|
+
SampleTable,
|
|
76
|
+
col(SampleTable.sample_id) == col(ImageTable.sample_id),
|
|
77
|
+
)
|
|
78
|
+
.where(SampleTable.dataset_id == dataset_id)
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# Add dimension filters
|
|
82
|
+
if min_width is not None:
|
|
83
|
+
filtered_query = filtered_query.where(ImageTable.width >= min_width)
|
|
84
|
+
if max_width is not None:
|
|
85
|
+
filtered_query = filtered_query.where(ImageTable.width <= max_width)
|
|
86
|
+
if min_height is not None:
|
|
87
|
+
filtered_query = filtered_query.where(ImageTable.height >= min_height)
|
|
88
|
+
if max_height is not None:
|
|
89
|
+
filtered_query = filtered_query.where(ImageTable.height <= max_height)
|
|
90
|
+
|
|
91
|
+
# Add label filter if specified
|
|
92
|
+
if filtered_labels:
|
|
93
|
+
filtered_query = filtered_query.where(
|
|
94
|
+
col(ImageTable.sample_id).in_(
|
|
95
|
+
select(ImageTable.sample_id)
|
|
96
|
+
.join(
|
|
97
|
+
AnnotationBaseTable,
|
|
98
|
+
col(ImageTable.sample_id) == col(AnnotationBaseTable.parent_sample_id),
|
|
99
|
+
)
|
|
100
|
+
.join(
|
|
101
|
+
AnnotationLabelTable,
|
|
102
|
+
col(AnnotationBaseTable.annotation_label_id)
|
|
103
|
+
== col(AnnotationLabelTable.annotation_label_id),
|
|
104
|
+
)
|
|
105
|
+
.where(col(AnnotationLabelTable.annotation_label_name).in_(filtered_labels))
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# filter by tag_ids
|
|
110
|
+
if tag_ids:
|
|
111
|
+
filtered_query = (
|
|
112
|
+
filtered_query.join(AnnotationBaseTable.tags)
|
|
113
|
+
.where(AnnotationBaseTable.tags.any(col(TagTable.tag_id).in_(tag_ids)))
|
|
114
|
+
.distinct()
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Group by label name and sort
|
|
118
|
+
filtered_query = filtered_query.group_by(AnnotationLabelTable.annotation_label_name).order_by(
|
|
119
|
+
col(AnnotationLabelTable.annotation_label_name).asc()
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
_rows = session.exec(filtered_query).all()
|
|
123
|
+
|
|
124
|
+
current_counts = {row[0]: row[1] for row in _rows}
|
|
125
|
+
|
|
126
|
+
return [
|
|
127
|
+
(label, current_counts.get(label, 0), total_count)
|
|
128
|
+
for label, total_count in total_counts.items()
|
|
129
|
+
]
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""Handler for database operations related to annotations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from sqlmodel import Session
|
|
8
|
+
|
|
9
|
+
from lightly_studio.models.annotation.annotation_base import (
|
|
10
|
+
AnnotationBaseTable,
|
|
11
|
+
AnnotationCreate,
|
|
12
|
+
)
|
|
13
|
+
from lightly_studio.models.annotation.instance_segmentation import (
|
|
14
|
+
InstanceSegmentationAnnotationTable,
|
|
15
|
+
)
|
|
16
|
+
from lightly_studio.models.annotation.object_detection import (
|
|
17
|
+
ObjectDetectionAnnotationTable,
|
|
18
|
+
)
|
|
19
|
+
from lightly_studio.models.annotation.semantic_segmentation import (
|
|
20
|
+
SemanticSegmentationAnnotationTable,
|
|
21
|
+
)
|
|
22
|
+
from lightly_studio.models.dataset import SampleType
|
|
23
|
+
from lightly_studio.models.sample import SampleCreate
|
|
24
|
+
from lightly_studio.resolvers import dataset_resolver, sample_resolver
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def create_many(
|
|
28
|
+
session: Session,
|
|
29
|
+
parent_dataset_id: UUID,
|
|
30
|
+
annotations: list[AnnotationCreate],
|
|
31
|
+
) -> list[UUID]:
|
|
32
|
+
"""Create multiple annotations in bulk with their respective type-specific details.
|
|
33
|
+
|
|
34
|
+
Creates base annotations and their associated type-specific details (object detection,
|
|
35
|
+
instance segmentation, or semantic segmentation) in the annotation dataset child of
|
|
36
|
+
the provided parent dataset.
|
|
37
|
+
|
|
38
|
+
It is responsibility of the caller to ensure that all parent samples belong to the same
|
|
39
|
+
dataset with ID `parent_dataset_id`. This function does not perform this check for performance
|
|
40
|
+
reasons.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
session: SQLAlchemy session for database operations.
|
|
44
|
+
parent_dataset_id: UUID of the parent dataset.
|
|
45
|
+
annotations: List of annotation objects to create.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
List of created annotation IDs.
|
|
49
|
+
"""
|
|
50
|
+
# Step 1: Create all base annotations
|
|
51
|
+
base_annotations = []
|
|
52
|
+
object_detection_annotations = []
|
|
53
|
+
instance_segmentation_annotations = []
|
|
54
|
+
semantic_segmentation_annotations = []
|
|
55
|
+
annotation_dataset_id = dataset_resolver.get_or_create_child_dataset(
|
|
56
|
+
session=session, dataset_id=parent_dataset_id, sample_type=SampleType.ANNOTATION
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
sample_ids = sample_resolver.create_many(
|
|
60
|
+
session=session,
|
|
61
|
+
samples=[SampleCreate(dataset_id=annotation_dataset_id) for _ in annotations],
|
|
62
|
+
)
|
|
63
|
+
for annotation_create, sample_id in zip(annotations, sample_ids):
|
|
64
|
+
# Create base annotation
|
|
65
|
+
db_base_annotation = AnnotationBaseTable(
|
|
66
|
+
sample_id=sample_id,
|
|
67
|
+
annotation_label_id=annotation_create.annotation_label_id,
|
|
68
|
+
annotation_type=annotation_create.annotation_type,
|
|
69
|
+
confidence=annotation_create.confidence,
|
|
70
|
+
dataset_id=annotation_dataset_id,
|
|
71
|
+
parent_sample_id=annotation_create.parent_sample_id,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Set other relationship details to None
|
|
75
|
+
db_base_annotation.instance_segmentation_details = None
|
|
76
|
+
db_base_annotation.semantic_segmentation_details = None
|
|
77
|
+
db_base_annotation.object_detection_details = None
|
|
78
|
+
|
|
79
|
+
base_annotations.append(db_base_annotation)
|
|
80
|
+
|
|
81
|
+
# Bulk save base annotations and flush to get IDs
|
|
82
|
+
session.bulk_save_objects(base_annotations)
|
|
83
|
+
session.flush()
|
|
84
|
+
|
|
85
|
+
# Step 2: Create specific annotation details
|
|
86
|
+
for i, annotation_create in enumerate(annotations):
|
|
87
|
+
# Create object detection details
|
|
88
|
+
if base_annotations[i].annotation_type == "object_detection":
|
|
89
|
+
db_object_detection = ObjectDetectionAnnotationTable(
|
|
90
|
+
sample_id=base_annotations[i].sample_id,
|
|
91
|
+
x=annotation_create.x,
|
|
92
|
+
y=annotation_create.y,
|
|
93
|
+
width=annotation_create.width,
|
|
94
|
+
height=annotation_create.height,
|
|
95
|
+
)
|
|
96
|
+
object_detection_annotations.append(db_object_detection)
|
|
97
|
+
|
|
98
|
+
# Create instance segmentation details
|
|
99
|
+
elif base_annotations[i].annotation_type == "instance_segmentation":
|
|
100
|
+
db_instance_segmentation = InstanceSegmentationAnnotationTable(
|
|
101
|
+
sample_id=base_annotations[i].sample_id,
|
|
102
|
+
segmentation_mask=annotation_create.segmentation_mask,
|
|
103
|
+
x=annotation_create.x,
|
|
104
|
+
y=annotation_create.y,
|
|
105
|
+
width=annotation_create.width,
|
|
106
|
+
height=annotation_create.height,
|
|
107
|
+
)
|
|
108
|
+
instance_segmentation_annotations.append(db_instance_segmentation)
|
|
109
|
+
elif base_annotations[i].annotation_type == "semantic_segmentation":
|
|
110
|
+
db_semantic_segmentation = SemanticSegmentationAnnotationTable(
|
|
111
|
+
sample_id=base_annotations[i].sample_id,
|
|
112
|
+
segmentation_mask=annotation_create.segmentation_mask,
|
|
113
|
+
)
|
|
114
|
+
semantic_segmentation_annotations.append(db_semantic_segmentation)
|
|
115
|
+
|
|
116
|
+
# Bulk save object detection annotations
|
|
117
|
+
session.bulk_save_objects(object_detection_annotations)
|
|
118
|
+
session.bulk_save_objects(instance_segmentation_annotations)
|
|
119
|
+
session.bulk_save_objects(semantic_segmentation_annotations)
|
|
120
|
+
|
|
121
|
+
# Commit everything
|
|
122
|
+
session.commit()
|
|
123
|
+
|
|
124
|
+
return [annotation.sample_id for annotation in base_annotations]
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""Handler for database operations related to annotations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from sqlmodel import Session, col, delete
|
|
8
|
+
|
|
9
|
+
from lightly_studio.models.annotation.annotation_base import AnnotationBaseTable
|
|
10
|
+
from lightly_studio.models.annotation.instance_segmentation import (
|
|
11
|
+
InstanceSegmentationAnnotationTable,
|
|
12
|
+
)
|
|
13
|
+
from lightly_studio.models.annotation.links import AnnotationTagLinkTable
|
|
14
|
+
from lightly_studio.models.annotation.object_detection import (
|
|
15
|
+
ObjectDetectionAnnotationTable,
|
|
16
|
+
)
|
|
17
|
+
from lightly_studio.models.annotation.semantic_segmentation import (
|
|
18
|
+
SemanticSegmentationAnnotationTable,
|
|
19
|
+
)
|
|
20
|
+
from lightly_studio.models.sample import SampleTable
|
|
21
|
+
from lightly_studio.resolvers import annotation_resolver
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def delete_annotation(
|
|
25
|
+
session: Session,
|
|
26
|
+
annotation_id: UUID,
|
|
27
|
+
delete_sample: bool = True,
|
|
28
|
+
) -> None:
|
|
29
|
+
"""Delete all annotations and their tag links using filters.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
session: Database session.
|
|
33
|
+
annotation_id: Annotation ID to filter by.
|
|
34
|
+
delete_sample: Whether to also delete the annotation's sample. Defaults to True.
|
|
35
|
+
Set to False when updating an annotation (to reuse the sample).
|
|
36
|
+
"""
|
|
37
|
+
# Find annotation_ids to delete
|
|
38
|
+
annotation = annotation_resolver.get_by_id(
|
|
39
|
+
session,
|
|
40
|
+
annotation_id=annotation_id,
|
|
41
|
+
)
|
|
42
|
+
if not annotation:
|
|
43
|
+
raise ValueError(f"Annotation {annotation_id} not found")
|
|
44
|
+
|
|
45
|
+
# Store the annotation's sample_id before deletion
|
|
46
|
+
annotation_sample_id = annotation.sample_id
|
|
47
|
+
|
|
48
|
+
session.exec( # type: ignore
|
|
49
|
+
delete(ObjectDetectionAnnotationTable).where(
|
|
50
|
+
col(ObjectDetectionAnnotationTable.sample_id) == annotation.sample_id
|
|
51
|
+
)
|
|
52
|
+
)
|
|
53
|
+
session.exec( # type: ignore
|
|
54
|
+
delete(InstanceSegmentationAnnotationTable).where(
|
|
55
|
+
col(InstanceSegmentationAnnotationTable.sample_id) == annotation.sample_id
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
session.exec( # type: ignore
|
|
59
|
+
delete(SemanticSegmentationAnnotationTable).where(
|
|
60
|
+
col(SemanticSegmentationAnnotationTable.sample_id) == annotation.sample_id
|
|
61
|
+
)
|
|
62
|
+
)
|
|
63
|
+
session.commit()
|
|
64
|
+
|
|
65
|
+
# Delete tag links
|
|
66
|
+
session.exec( # type: ignore
|
|
67
|
+
delete(AnnotationTagLinkTable).where(
|
|
68
|
+
col(AnnotationTagLinkTable.annotation_sample_id).in_([annotation.sample_id])
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
session.commit()
|
|
72
|
+
|
|
73
|
+
# Delete the annotation using explicit DELETE to avoid relationship cascade issues
|
|
74
|
+
session.exec( # type: ignore
|
|
75
|
+
delete(AnnotationBaseTable).where(
|
|
76
|
+
col(AnnotationBaseTable.sample_id) == annotation.sample_id
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
session.commit()
|
|
80
|
+
|
|
81
|
+
# Then delete the annotation's sample (created specifically for this annotation)
|
|
82
|
+
# unless we're keeping it for reuse (e.g., when updating annotation label)
|
|
83
|
+
if delete_sample:
|
|
84
|
+
annotation_sample = session.get(SampleTable, annotation_sample_id)
|
|
85
|
+
if annotation_sample:
|
|
86
|
+
session.delete(annotation_sample)
|
|
87
|
+
session.commit()
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Handler for database operations related to annotations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from sqlmodel import Session, col, delete
|
|
8
|
+
|
|
9
|
+
from lightly_studio.models.annotation.annotation_base import (
|
|
10
|
+
AnnotationBaseTable,
|
|
11
|
+
)
|
|
12
|
+
from lightly_studio.models.annotation.links import AnnotationTagLinkTable
|
|
13
|
+
from lightly_studio.resolvers import annotation_resolver
|
|
14
|
+
from lightly_studio.resolvers.annotations.annotations_filter import (
|
|
15
|
+
AnnotationsFilter,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def delete_annotations(
|
|
20
|
+
session: Session,
|
|
21
|
+
annotation_label_ids: list[UUID] | None,
|
|
22
|
+
) -> None:
|
|
23
|
+
"""Delete all annotations and their tag links using filters.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
session: Database session.
|
|
27
|
+
annotation_label_ids: List of annotation label IDs to filter by.
|
|
28
|
+
"""
|
|
29
|
+
# Find annotation_ids to delete
|
|
30
|
+
annotations = annotation_resolver.get_all(
|
|
31
|
+
session,
|
|
32
|
+
filters=AnnotationsFilter(
|
|
33
|
+
annotation_label_ids=annotation_label_ids,
|
|
34
|
+
),
|
|
35
|
+
).annotations
|
|
36
|
+
for annotation in annotations:
|
|
37
|
+
if annotation.object_detection_details:
|
|
38
|
+
session.delete(annotation.object_detection_details)
|
|
39
|
+
if annotation.instance_segmentation_details:
|
|
40
|
+
session.delete(annotation.instance_segmentation_details)
|
|
41
|
+
if annotation.semantic_segmentation_details:
|
|
42
|
+
session.delete(annotation.semantic_segmentation_details)
|
|
43
|
+
annotation_ids = [annotation.sample_id for annotation in annotations]
|
|
44
|
+
# TODO(Horatiu, 06/2025): Check if there is a way to delete the links
|
|
45
|
+
# automatically using SQLModel/SQLAlchemy.
|
|
46
|
+
if annotation_ids:
|
|
47
|
+
# Delete tag links first
|
|
48
|
+
session.exec( # type: ignore
|
|
49
|
+
delete(AnnotationTagLinkTable).where(
|
|
50
|
+
col(AnnotationTagLinkTable.annotation_sample_id).in_(annotation_ids)
|
|
51
|
+
)
|
|
52
|
+
)
|
|
53
|
+
session.commit()
|
|
54
|
+
# Now delete the annotations themselves
|
|
55
|
+
session.exec( # type: ignore
|
|
56
|
+
delete(AnnotationBaseTable).where(
|
|
57
|
+
col(AnnotationBaseTable.sample_id).in_(annotation_ids)
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
session.commit()
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Handler for database operations related to annotations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Sequence
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
from sqlmodel import Session, col, func, select
|
|
9
|
+
|
|
10
|
+
from lightly_studio.api.routes.api.validators import Paginated
|
|
11
|
+
from lightly_studio.models.annotation.annotation_base import (
|
|
12
|
+
AnnotationBaseTable,
|
|
13
|
+
)
|
|
14
|
+
from lightly_studio.models.image import ImageTable
|
|
15
|
+
from lightly_studio.models.video import VideoFrameTable, VideoTable
|
|
16
|
+
from lightly_studio.resolvers.annotations.annotations_filter import (
|
|
17
|
+
AnnotationsFilter,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class GetAllAnnotationsResult(BaseModel):
|
|
22
|
+
"""Result of getting all annotations."""
|
|
23
|
+
|
|
24
|
+
annotations: Sequence[AnnotationBaseTable]
|
|
25
|
+
|
|
26
|
+
total_count: int
|
|
27
|
+
|
|
28
|
+
next_cursor: int | None = None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_all(
|
|
32
|
+
session: Session,
|
|
33
|
+
pagination: Paginated | None = None,
|
|
34
|
+
filters: AnnotationsFilter | None = None,
|
|
35
|
+
) -> GetAllAnnotationsResult:
|
|
36
|
+
"""Get all annotations from the database.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
session: Database session
|
|
40
|
+
pagination: Optional pagination parameters
|
|
41
|
+
filters: Optional filters to apply to the query
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
List of annotations matching the filters
|
|
45
|
+
"""
|
|
46
|
+
annotations_statement = select(AnnotationBaseTable)
|
|
47
|
+
annotations_statement = (
|
|
48
|
+
annotations_statement.outerjoin(
|
|
49
|
+
ImageTable, col(ImageTable.sample_id) == col(AnnotationBaseTable.parent_sample_id)
|
|
50
|
+
)
|
|
51
|
+
.outerjoin(
|
|
52
|
+
VideoFrameTable,
|
|
53
|
+
col(VideoFrameTable.sample_id) == col(AnnotationBaseTable.parent_sample_id),
|
|
54
|
+
)
|
|
55
|
+
.outerjoin(VideoTable, col(VideoTable.sample_id) == col(VideoFrameTable.parent_sample_id))
|
|
56
|
+
.order_by(
|
|
57
|
+
func.coalesce(ImageTable.file_path_abs, VideoTable.file_path_abs, "").asc(),
|
|
58
|
+
col(AnnotationBaseTable.created_at).asc(),
|
|
59
|
+
col(AnnotationBaseTable.sample_id).asc(),
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
total_count_statement = select(func.count()).select_from(AnnotationBaseTable)
|
|
63
|
+
|
|
64
|
+
# Apply filters if provided
|
|
65
|
+
if filters is not None:
|
|
66
|
+
annotations_statement = filters.apply(annotations_statement)
|
|
67
|
+
total_count_statement = filters.apply(total_count_statement)
|
|
68
|
+
|
|
69
|
+
# Apply pagination if provided
|
|
70
|
+
if pagination is not None:
|
|
71
|
+
annotations_statement = annotations_statement.offset(pagination.offset).limit(
|
|
72
|
+
pagination.limit
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
total_count = session.exec(total_count_statement).one()
|
|
76
|
+
|
|
77
|
+
next_cursor = None
|
|
78
|
+
if pagination and pagination.offset + pagination.limit < total_count:
|
|
79
|
+
next_cursor = pagination.offset + pagination.limit
|
|
80
|
+
|
|
81
|
+
return GetAllAnnotationsResult(
|
|
82
|
+
annotations=session.exec(annotations_statement).all(),
|
|
83
|
+
total_count=total_count,
|
|
84
|
+
next_cursor=next_cursor,
|
|
85
|
+
)
|