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,179 @@
|
|
|
1
|
+
"""Get all annotations with payload resolver."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
from uuid import UUID
|
|
7
|
+
|
|
8
|
+
from sqlalchemy.orm import aliased, joinedload, load_only
|
|
9
|
+
from sqlmodel import Session, col, func, select
|
|
10
|
+
from sqlmodel.sql.expression import Select
|
|
11
|
+
|
|
12
|
+
from lightly_studio.api.routes.api.validators import Paginated
|
|
13
|
+
from lightly_studio.models.annotation.annotation_base import (
|
|
14
|
+
AnnotationBaseTable,
|
|
15
|
+
AnnotationWithPayloadAndCountView,
|
|
16
|
+
AnnotationWithPayloadView,
|
|
17
|
+
ImageAnnotationView,
|
|
18
|
+
SampleAnnotationView,
|
|
19
|
+
VideoAnnotationView,
|
|
20
|
+
VideoFrameAnnotationView,
|
|
21
|
+
)
|
|
22
|
+
from lightly_studio.models.dataset import SampleType
|
|
23
|
+
from lightly_studio.models.image import ImageTable
|
|
24
|
+
from lightly_studio.models.sample import SampleTable
|
|
25
|
+
from lightly_studio.models.video import VideoFrameTable, VideoTable
|
|
26
|
+
from lightly_studio.resolvers import dataset_resolver
|
|
27
|
+
from lightly_studio.resolvers.annotations.annotations_filter import (
|
|
28
|
+
AnnotationsFilter,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_all_with_payload(
|
|
33
|
+
session: Session,
|
|
34
|
+
dataset_id: UUID,
|
|
35
|
+
pagination: Paginated | None = None,
|
|
36
|
+
filters: AnnotationsFilter | None = None,
|
|
37
|
+
) -> AnnotationWithPayloadAndCountView:
|
|
38
|
+
"""Get all annotations with payload from the database.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
session: Database session
|
|
42
|
+
pagination: Optional pagination parameters
|
|
43
|
+
filters: Optional filters to apply to the query
|
|
44
|
+
dataset_id: ID of the dataset to get annotations for
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
List of annotations matching the filters with payload
|
|
48
|
+
"""
|
|
49
|
+
parent_dataset = dataset_resolver.get_parent_dataset_id(session=session, dataset_id=dataset_id)
|
|
50
|
+
|
|
51
|
+
if parent_dataset is None:
|
|
52
|
+
raise ValueError(f"Dataset with id {dataset_id} does not have a parent dataset.")
|
|
53
|
+
|
|
54
|
+
sample_type = parent_dataset.sample_type
|
|
55
|
+
|
|
56
|
+
base_query = _build_base_query(sample_type=sample_type)
|
|
57
|
+
|
|
58
|
+
if filters:
|
|
59
|
+
base_query = filters.apply(base_query)
|
|
60
|
+
|
|
61
|
+
annotations_query = base_query.order_by(
|
|
62
|
+
*_extra_order_by(sample_type=sample_type),
|
|
63
|
+
col(AnnotationBaseTable.created_at).asc(),
|
|
64
|
+
col(AnnotationBaseTable.sample_id).asc(),
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
total_count_query = select(func.count()).select_from(base_query.subquery())
|
|
68
|
+
total_count = session.exec(total_count_query).one()
|
|
69
|
+
|
|
70
|
+
if pagination is not None:
|
|
71
|
+
annotations_query = annotations_query.offset(pagination.offset).limit(pagination.limit)
|
|
72
|
+
|
|
73
|
+
next_cursor = None
|
|
74
|
+
if pagination and pagination.offset + pagination.limit < total_count:
|
|
75
|
+
next_cursor = pagination.offset + pagination.limit
|
|
76
|
+
|
|
77
|
+
rows = session.exec(annotations_query).all()
|
|
78
|
+
|
|
79
|
+
return AnnotationWithPayloadAndCountView(
|
|
80
|
+
total_count=total_count,
|
|
81
|
+
next_cursor=next_cursor,
|
|
82
|
+
annotations=[
|
|
83
|
+
AnnotationWithPayloadView(
|
|
84
|
+
parent_sample_type=sample_type,
|
|
85
|
+
annotation=annotation,
|
|
86
|
+
parent_sample_data=_serialize_annotation_payload(payload),
|
|
87
|
+
)
|
|
88
|
+
for annotation, payload in rows
|
|
89
|
+
],
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _build_base_query(
|
|
94
|
+
sample_type: SampleType,
|
|
95
|
+
) -> Select[tuple[AnnotationBaseTable, Any]]:
|
|
96
|
+
if sample_type == SampleType.IMAGE:
|
|
97
|
+
# this alias is needed to avoid name clashes in joins
|
|
98
|
+
SampleFromImage = aliased(SampleTable) # noqa: N806
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
select(AnnotationBaseTable, ImageTable)
|
|
102
|
+
.join(
|
|
103
|
+
ImageTable,
|
|
104
|
+
col(ImageTable.sample_id) == col(AnnotationBaseTable.parent_sample_id),
|
|
105
|
+
)
|
|
106
|
+
.join(SampleFromImage, col(SampleFromImage.sample_id) == col(ImageTable.sample_id))
|
|
107
|
+
.options(
|
|
108
|
+
load_only(
|
|
109
|
+
ImageTable.file_path_abs, # type: ignore[arg-type]
|
|
110
|
+
ImageTable.sample_id, # type: ignore[arg-type]
|
|
111
|
+
ImageTable.height, # type: ignore[arg-type]
|
|
112
|
+
ImageTable.width, # type: ignore[arg-type]
|
|
113
|
+
),
|
|
114
|
+
joinedload(ImageTable.sample).load_only(
|
|
115
|
+
SampleTable.dataset_id, # type: ignore[arg-type]
|
|
116
|
+
),
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
if sample_type in (SampleType.VIDEO_FRAME, SampleType.VIDEO):
|
|
121
|
+
return (
|
|
122
|
+
select(AnnotationBaseTable, VideoFrameTable)
|
|
123
|
+
.join(
|
|
124
|
+
VideoFrameTable,
|
|
125
|
+
col(VideoFrameTable.sample_id) == col(AnnotationBaseTable.parent_sample_id),
|
|
126
|
+
)
|
|
127
|
+
.join(VideoFrameTable.video)
|
|
128
|
+
.options(
|
|
129
|
+
load_only(VideoFrameTable.sample_id), # type: ignore[arg-type]
|
|
130
|
+
joinedload(VideoFrameTable.video).load_only(
|
|
131
|
+
VideoTable.height, # type: ignore[arg-type]
|
|
132
|
+
VideoTable.width, # type: ignore[arg-type]
|
|
133
|
+
VideoTable.file_path_abs, # type: ignore[arg-type]
|
|
134
|
+
),
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
raise NotImplementedError(f"Unsupported sample type: {sample_type}")
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _extra_order_by(sample_type: SampleType) -> list[Any]:
|
|
142
|
+
"""Return extra order by clauses for the query."""
|
|
143
|
+
if sample_type == SampleType.IMAGE:
|
|
144
|
+
return [
|
|
145
|
+
col(ImageTable.file_path_abs).asc(),
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
if sample_type in (SampleType.VIDEO_FRAME, SampleType.VIDEO):
|
|
149
|
+
return [
|
|
150
|
+
col(VideoTable.file_path_abs).asc(),
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
return []
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _serialize_annotation_payload(
|
|
157
|
+
payload: ImageTable | VideoFrameTable,
|
|
158
|
+
) -> ImageAnnotationView | VideoFrameAnnotationView:
|
|
159
|
+
"""Serialize annotation based on sample type."""
|
|
160
|
+
if isinstance(payload, ImageTable):
|
|
161
|
+
return ImageAnnotationView(
|
|
162
|
+
height=payload.height,
|
|
163
|
+
width=payload.width,
|
|
164
|
+
file_path_abs=payload.file_path_abs,
|
|
165
|
+
sample_id=payload.sample_id,
|
|
166
|
+
sample=SampleAnnotationView(dataset_id=payload.sample.dataset_id),
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
if isinstance(payload, VideoFrameTable):
|
|
170
|
+
return VideoFrameAnnotationView(
|
|
171
|
+
sample_id=payload.sample_id,
|
|
172
|
+
video=VideoAnnotationView(
|
|
173
|
+
width=payload.video.width,
|
|
174
|
+
height=payload.video.height,
|
|
175
|
+
file_path_abs=payload.video.file_path_abs,
|
|
176
|
+
),
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
raise NotImplementedError("Unsupported sample type")
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Handler for database operations related to annotations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Sequence
|
|
6
|
+
from uuid import UUID
|
|
7
|
+
|
|
8
|
+
from sqlmodel import Session, col, select
|
|
9
|
+
|
|
10
|
+
from lightly_studio.models.annotation.annotation_base import (
|
|
11
|
+
AnnotationBaseTable,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_by_id(session: Session, annotation_id: UUID) -> AnnotationBaseTable | None:
|
|
16
|
+
"""Retrieve a single annotation by ID."""
|
|
17
|
+
return session.exec(
|
|
18
|
+
select(AnnotationBaseTable).where(AnnotationBaseTable.sample_id == annotation_id)
|
|
19
|
+
).one_or_none()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_by_ids(session: Session, annotation_ids: Sequence[UUID]) -> Sequence[AnnotationBaseTable]:
|
|
23
|
+
"""Retrieve multiple annotations by their IDs.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
session: The database session to use for the query.
|
|
27
|
+
annotation_ids: A list of annotation IDs to retrieve.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
A list of annotations matching the provided IDs.
|
|
31
|
+
"""
|
|
32
|
+
return session.exec(
|
|
33
|
+
select(AnnotationBaseTable).where(col(AnnotationBaseTable.sample_id).in_(annotation_ids))
|
|
34
|
+
).all()
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""Get annotation by id with payload resolver."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from sqlalchemy.orm import aliased, joinedload, load_only
|
|
8
|
+
from sqlmodel import Session, col, select
|
|
9
|
+
|
|
10
|
+
from lightly_studio.models.annotation.annotation_base import (
|
|
11
|
+
AnnotationBaseTable,
|
|
12
|
+
AnnotationDetailsWithPayloadView,
|
|
13
|
+
ImageAnnotationDetailsView,
|
|
14
|
+
VideoFrameAnnotationDetailsView,
|
|
15
|
+
)
|
|
16
|
+
from lightly_studio.models.dataset import SampleType
|
|
17
|
+
from lightly_studio.models.image import ImageTable
|
|
18
|
+
from lightly_studio.models.sample import SampleTable
|
|
19
|
+
from lightly_studio.models.video import VideoFrameTable, VideoTable
|
|
20
|
+
from lightly_studio.resolvers import dataset_resolver
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_by_id_with_payload(
|
|
24
|
+
session: Session,
|
|
25
|
+
sample_id: UUID,
|
|
26
|
+
) -> AnnotationDetailsWithPayloadView | None:
|
|
27
|
+
"""Get annotation by its id with payload from the database.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
session: Database session
|
|
31
|
+
sample_id: ID of the sample to get annotations for
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Returns annotations with payload
|
|
35
|
+
"""
|
|
36
|
+
parent_dataset = dataset_resolver.get_parent_dataset_by_sample_id(
|
|
37
|
+
session=session, sample_id=sample_id
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
if parent_dataset is None:
|
|
41
|
+
raise ValueError(f"Sample with id {sample_id} does not have a parent dataset.")
|
|
42
|
+
|
|
43
|
+
parent_sample_type = parent_dataset.sample_type
|
|
44
|
+
|
|
45
|
+
if parent_sample_type in SampleType.VIDEO_FRAME:
|
|
46
|
+
return _get_video_frame_annotation_by_id(
|
|
47
|
+
session=session, sample_id=sample_id, parent_sample_type=parent_sample_type
|
|
48
|
+
)
|
|
49
|
+
if parent_sample_type == SampleType.IMAGE:
|
|
50
|
+
return _get_image_annotation_by_id(session=session, sample_id=sample_id)
|
|
51
|
+
|
|
52
|
+
raise NotImplementedError("Unsupported sample type")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
SampleFromImage = aliased(SampleTable)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _get_image_annotation_by_id(
|
|
59
|
+
session: Session, sample_id: UUID
|
|
60
|
+
) -> AnnotationDetailsWithPayloadView | None:
|
|
61
|
+
base_query = (
|
|
62
|
+
select(AnnotationBaseTable, ImageTable)
|
|
63
|
+
.join(
|
|
64
|
+
ImageTable,
|
|
65
|
+
col(ImageTable.sample_id) == col(AnnotationBaseTable.parent_sample_id),
|
|
66
|
+
)
|
|
67
|
+
.join(SampleFromImage, col(SampleFromImage.sample_id) == col(ImageTable.sample_id))
|
|
68
|
+
.options(
|
|
69
|
+
load_only(
|
|
70
|
+
ImageTable.file_path_abs, # type: ignore[arg-type]
|
|
71
|
+
ImageTable.file_name, # type: ignore[arg-type]
|
|
72
|
+
ImageTable.sample_id, # type: ignore[arg-type]
|
|
73
|
+
ImageTable.height, # type: ignore[arg-type]
|
|
74
|
+
ImageTable.width, # type: ignore[arg-type]
|
|
75
|
+
),
|
|
76
|
+
)
|
|
77
|
+
.where(col(AnnotationBaseTable.sample_id) == sample_id)
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
row = session.exec(base_query).one_or_none()
|
|
81
|
+
|
|
82
|
+
if row is None:
|
|
83
|
+
return None
|
|
84
|
+
|
|
85
|
+
(annotation, payload) = row
|
|
86
|
+
|
|
87
|
+
return AnnotationDetailsWithPayloadView(
|
|
88
|
+
parent_sample_type=SampleType.IMAGE,
|
|
89
|
+
annotation=annotation,
|
|
90
|
+
parent_sample_data=ImageAnnotationDetailsView.from_image_table(payload),
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _get_video_frame_annotation_by_id(
|
|
95
|
+
session: Session, sample_id: UUID, parent_sample_type: SampleType
|
|
96
|
+
) -> AnnotationDetailsWithPayloadView | None:
|
|
97
|
+
base_query = (
|
|
98
|
+
select(AnnotationBaseTable, VideoFrameTable)
|
|
99
|
+
.join(
|
|
100
|
+
VideoFrameTable,
|
|
101
|
+
col(VideoFrameTable.sample_id) == col(AnnotationBaseTable.parent_sample_id),
|
|
102
|
+
)
|
|
103
|
+
.join(VideoFrameTable.video)
|
|
104
|
+
.options(
|
|
105
|
+
load_only(
|
|
106
|
+
VideoFrameTable.sample_id, # type: ignore[arg-type]
|
|
107
|
+
VideoFrameTable.frame_number, # type: ignore[arg-type]
|
|
108
|
+
VideoFrameTable.frame_timestamp_s, # type: ignore[arg-type]
|
|
109
|
+
),
|
|
110
|
+
joinedload(VideoFrameTable.video).load_only(
|
|
111
|
+
VideoTable.height, # type: ignore[arg-type]
|
|
112
|
+
VideoTable.width, # type: ignore[arg-type]
|
|
113
|
+
VideoTable.file_path_abs, # type: ignore[arg-type]
|
|
114
|
+
),
|
|
115
|
+
)
|
|
116
|
+
.where(col(AnnotationBaseTable.sample_id) == sample_id)
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
row = session.exec(base_query).one_or_none()
|
|
120
|
+
|
|
121
|
+
if row is None:
|
|
122
|
+
return None
|
|
123
|
+
|
|
124
|
+
(annotation, payload) = row
|
|
125
|
+
|
|
126
|
+
return AnnotationDetailsWithPayloadView(
|
|
127
|
+
parent_sample_type=parent_sample_type,
|
|
128
|
+
annotation=annotation,
|
|
129
|
+
parent_sample_data=VideoFrameAnnotationDetailsView.from_video_frame_table(payload),
|
|
130
|
+
)
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"""Module for handling the update of annotation labels in the database."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TypeVar
|
|
6
|
+
from uuid import UUID
|
|
7
|
+
|
|
8
|
+
from sqlmodel import Session, SQLModel
|
|
9
|
+
|
|
10
|
+
from lightly_studio.models.annotation.annotation_base import (
|
|
11
|
+
AnnotationBaseTable,
|
|
12
|
+
)
|
|
13
|
+
from lightly_studio.models.annotation.instance_segmentation import (
|
|
14
|
+
InstanceSegmentationAnnotationTable,
|
|
15
|
+
)
|
|
16
|
+
from lightly_studio.models.annotation.links import AnnotationTagLinkTable
|
|
17
|
+
from lightly_studio.models.annotation.object_detection import ObjectDetectionAnnotationTable
|
|
18
|
+
from lightly_studio.models.annotation.semantic_segmentation import (
|
|
19
|
+
SemanticSegmentationAnnotationTable,
|
|
20
|
+
)
|
|
21
|
+
from lightly_studio.resolvers import (
|
|
22
|
+
annotation_resolver,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
T = TypeVar("T", bound=SQLModel)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def update_annotation_label(
|
|
29
|
+
session: Session, annotation_id: UUID, annotation_label_id: UUID
|
|
30
|
+
) -> AnnotationBaseTable:
|
|
31
|
+
"""Update the label of an annotation.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
session: Database session for executing the operation.
|
|
35
|
+
annotation_id: UUID of the annotation to update.
|
|
36
|
+
annotation_label_id: UUID of the new label to assign to the annotation.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
The updated annotation with the new label assigned.
|
|
40
|
+
|
|
41
|
+
Raises:
|
|
42
|
+
ValueError: If the annotation is not found.
|
|
43
|
+
"""
|
|
44
|
+
annotation = annotation_resolver.get_by_id(session, annotation_id)
|
|
45
|
+
if not annotation:
|
|
46
|
+
raise ValueError(f"Annotation with ID {annotation_id} not found.")
|
|
47
|
+
|
|
48
|
+
# DuckDB has no "looking ahead" functionality for referenced tables.
|
|
49
|
+
# We need to work around this by deleting the existing and re-inserting
|
|
50
|
+
# Check https://duckdb.org/docs/stable/sql/indexes.html#over-eager-constraint-checking-in-foreign-keys
|
|
51
|
+
|
|
52
|
+
# DuckDB has no "looking ahead" functionality for referenced tables and neither does it support cascading updates. # noqa: E501
|
|
53
|
+
# Herefore we need to delete and re-insert the affected rows.
|
|
54
|
+
# more information can be found in the DuckDB documentation https://duckdb.org/docs/stable/sql/statements/create_table.html.
|
|
55
|
+
try:
|
|
56
|
+
# copy content
|
|
57
|
+
annotation_copy = annotation.model_copy(update={"annotation_label_id": annotation_label_id})
|
|
58
|
+
|
|
59
|
+
annotation_type = annotation_copy.annotation_type
|
|
60
|
+
|
|
61
|
+
annotation_tags = [
|
|
62
|
+
AnnotationTagLinkTable(
|
|
63
|
+
annotation_sample_id=annotation_copy.sample_id,
|
|
64
|
+
tag_id=tag.tag_id,
|
|
65
|
+
)
|
|
66
|
+
for tag in annotation.tags
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
# we need to create a new annotation details before committing
|
|
70
|
+
# because copy will be gone with the commit
|
|
71
|
+
instance_segmentation = (
|
|
72
|
+
InstanceSegmentationAnnotationTable(
|
|
73
|
+
sample_id=annotation_copy.sample_id,
|
|
74
|
+
segmentation_mask=annotation_copy.instance_segmentation_details.segmentation_mask,
|
|
75
|
+
x=annotation_copy.instance_segmentation_details.x,
|
|
76
|
+
y=annotation_copy.instance_segmentation_details.y,
|
|
77
|
+
width=annotation_copy.instance_segmentation_details.width,
|
|
78
|
+
height=annotation_copy.instance_segmentation_details.height,
|
|
79
|
+
)
|
|
80
|
+
if annotation_type == "instance_segmentation"
|
|
81
|
+
and annotation_copy.instance_segmentation_details
|
|
82
|
+
else None
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
object_detection = (
|
|
86
|
+
ObjectDetectionAnnotationTable(
|
|
87
|
+
sample_id=annotation_copy.sample_id,
|
|
88
|
+
x=annotation_copy.object_detection_details.x,
|
|
89
|
+
y=annotation_copy.object_detection_details.y,
|
|
90
|
+
width=annotation_copy.object_detection_details.width,
|
|
91
|
+
height=annotation_copy.object_detection_details.height,
|
|
92
|
+
)
|
|
93
|
+
if annotation_type == "object_detection" and annotation_copy.object_detection_details
|
|
94
|
+
else None
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
semantic_segmentation = (
|
|
98
|
+
SemanticSegmentationAnnotationTable(
|
|
99
|
+
sample_id=annotation_copy.sample_id,
|
|
100
|
+
segmentation_mask=annotation_copy.semantic_segmentation_details.segmentation_mask,
|
|
101
|
+
)
|
|
102
|
+
if annotation_type == "semantic_segmentation"
|
|
103
|
+
and annotation_copy.semantic_segmentation_details
|
|
104
|
+
else None
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# delete
|
|
108
|
+
annotation_resolver.delete_annotation(session, annotation.sample_id, delete_sample=False)
|
|
109
|
+
|
|
110
|
+
new_annotation = AnnotationBaseTable(
|
|
111
|
+
sample_id=annotation_copy.sample_id,
|
|
112
|
+
annotation_label_id=annotation_copy.annotation_label_id,
|
|
113
|
+
annotation_type=annotation_copy.annotation_type,
|
|
114
|
+
confidence=annotation_copy.confidence,
|
|
115
|
+
created_at=annotation_copy.created_at,
|
|
116
|
+
parent_sample_id=annotation_copy.parent_sample_id,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
session.add(new_annotation)
|
|
120
|
+
|
|
121
|
+
if instance_segmentation:
|
|
122
|
+
session.add(instance_segmentation)
|
|
123
|
+
|
|
124
|
+
if object_detection:
|
|
125
|
+
session.add(object_detection)
|
|
126
|
+
|
|
127
|
+
if semantic_segmentation:
|
|
128
|
+
session.add(semantic_segmentation)
|
|
129
|
+
|
|
130
|
+
if annotation_tags:
|
|
131
|
+
session.add_all(annotation_tags)
|
|
132
|
+
|
|
133
|
+
session.commit()
|
|
134
|
+
session.flush()
|
|
135
|
+
|
|
136
|
+
return annotation_copy
|
|
137
|
+
except Exception:
|
|
138
|
+
# Explicit rollback to be safe, then re-raise the original error.
|
|
139
|
+
session.rollback()
|
|
140
|
+
raise
|
|
141
|
+
|
|
142
|
+
return annotation
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Module for handling the update of annotation bounding box coordinates in the database."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from uuid import UUID
|
|
7
|
+
|
|
8
|
+
from sqlmodel import Session
|
|
9
|
+
|
|
10
|
+
from lightly_studio.models.annotation.annotation_base import AnnotationBaseTable
|
|
11
|
+
from lightly_studio.resolvers import annotation_resolver
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class BoundingBoxCoordinates:
|
|
16
|
+
"""Represents bounding box coordinates."""
|
|
17
|
+
|
|
18
|
+
x: int
|
|
19
|
+
y: int
|
|
20
|
+
width: int
|
|
21
|
+
height: int
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def update_bounding_box(
|
|
25
|
+
session: Session,
|
|
26
|
+
annotation_id: UUID,
|
|
27
|
+
coordinates: BoundingBoxCoordinates,
|
|
28
|
+
) -> AnnotationBaseTable:
|
|
29
|
+
"""Update the bounding box coordinates of an annotation.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
session: Database session for executing the operation.
|
|
33
|
+
annotation_id: UUID of the annotation to update.
|
|
34
|
+
coordinates: New bounding box coordinates.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
The updated annotation with the new bounding box coordinates.
|
|
38
|
+
|
|
39
|
+
Raises:
|
|
40
|
+
ValueError: If the annotation is not found.
|
|
41
|
+
"""
|
|
42
|
+
annotation = annotation_resolver.get_by_id(session, annotation_id)
|
|
43
|
+
if not annotation:
|
|
44
|
+
raise ValueError(f"Annotation with ID {annotation_id} not found.")
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
if annotation.object_detection_details:
|
|
48
|
+
annotation.object_detection_details.x = coordinates.x
|
|
49
|
+
annotation.object_detection_details.y = coordinates.y
|
|
50
|
+
annotation.object_detection_details.width = coordinates.width
|
|
51
|
+
annotation.object_detection_details.height = coordinates.height
|
|
52
|
+
session.add(annotation.object_detection_details)
|
|
53
|
+
|
|
54
|
+
elif annotation.instance_segmentation_details:
|
|
55
|
+
annotation.instance_segmentation_details.x = coordinates.x
|
|
56
|
+
annotation.instance_segmentation_details.y = coordinates.y
|
|
57
|
+
annotation.instance_segmentation_details.width = coordinates.width
|
|
58
|
+
annotation.instance_segmentation_details.height = coordinates.height
|
|
59
|
+
session.add(annotation.instance_segmentation_details)
|
|
60
|
+
else:
|
|
61
|
+
raise ValueError("Annotation type does not support bounding boxes.")
|
|
62
|
+
|
|
63
|
+
session.commit()
|
|
64
|
+
session.refresh(annotation)
|
|
65
|
+
return annotation
|
|
66
|
+
except Exception:
|
|
67
|
+
session.rollback()
|
|
68
|
+
raise
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""Filtering functionality for annotations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
from sqlmodel import col
|
|
9
|
+
|
|
10
|
+
from lightly_studio.models.annotation.annotation_base import AnnotationBaseTable, AnnotationType
|
|
11
|
+
from lightly_studio.models.sample import SampleTable
|
|
12
|
+
from lightly_studio.models.tag import TagTable
|
|
13
|
+
from lightly_studio.type_definitions import QueryType
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AnnotationsFilter(BaseModel):
|
|
17
|
+
"""Handles filtering for annotation queries."""
|
|
18
|
+
|
|
19
|
+
annotation_types: list[AnnotationType] | None = Field(
|
|
20
|
+
default=None,
|
|
21
|
+
description="Types of annotation to filter (e.g., 'object_detection')",
|
|
22
|
+
)
|
|
23
|
+
dataset_ids: list[UUID] | None = Field(default=None, description="List of dataset UUIDs")
|
|
24
|
+
annotation_label_ids: list[UUID] | None = Field(
|
|
25
|
+
default=None, description="List of annotation label UUIDs"
|
|
26
|
+
)
|
|
27
|
+
annotation_tag_ids: list[UUID] | None = Field(default=None, description="List of tag UUIDs")
|
|
28
|
+
sample_tag_ids: list[UUID] | None = Field(
|
|
29
|
+
default=None,
|
|
30
|
+
description="List of sample tag UUIDs to filter annotations by",
|
|
31
|
+
)
|
|
32
|
+
sample_ids: list[UUID] | None = Field(
|
|
33
|
+
default=None, description="List of sample UUIDs to filter annotations by"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def apply(
|
|
37
|
+
self,
|
|
38
|
+
query: QueryType,
|
|
39
|
+
) -> QueryType:
|
|
40
|
+
"""Apply filters to an annotation query.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
query: The base query to apply filters to
|
|
44
|
+
annotation_table: The SQLModel table class for the annotation type
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
The query with filters applied
|
|
48
|
+
"""
|
|
49
|
+
# Filter by dataset
|
|
50
|
+
if self.dataset_ids:
|
|
51
|
+
query = query.join(AnnotationBaseTable.sample).where(
|
|
52
|
+
col(SampleTable.dataset_id).in_(self.dataset_ids)
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Filter by annotation label
|
|
56
|
+
if self.annotation_label_ids:
|
|
57
|
+
query = query.where(
|
|
58
|
+
col(AnnotationBaseTable.annotation_label_id).in_(self.annotation_label_ids)
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Filter by annotation tags
|
|
62
|
+
if self.annotation_tag_ids:
|
|
63
|
+
query = (
|
|
64
|
+
query.join(AnnotationBaseTable.tags)
|
|
65
|
+
.where(
|
|
66
|
+
AnnotationBaseTable.tags.any(col(TagTable.tag_id).in_(self.annotation_tag_ids))
|
|
67
|
+
)
|
|
68
|
+
.distinct()
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# Filter by sample tags
|
|
72
|
+
if self.sample_tag_ids:
|
|
73
|
+
query = (
|
|
74
|
+
query.join(AnnotationBaseTable.parent_sample)
|
|
75
|
+
.join(SampleTable.tags)
|
|
76
|
+
.where(SampleTable.tags.any(col(TagTable.tag_id).in_(self.sample_tag_ids)))
|
|
77
|
+
.distinct()
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Filter by sample ids
|
|
81
|
+
if self.sample_ids:
|
|
82
|
+
query = query.where(col(AnnotationBaseTable.parent_sample_id).in_(self.sample_ids))
|
|
83
|
+
|
|
84
|
+
# Filter by annotation type
|
|
85
|
+
if self.annotation_types:
|
|
86
|
+
query = query.where(col(AnnotationBaseTable.annotation_type).in_(self.annotation_types))
|
|
87
|
+
|
|
88
|
+
return query
|