-
Notifications
You must be signed in to change notification settings - Fork 79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
✨ Add Support for QuPath
Annotation Imports
#721
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## develop #721 +/- ##
========================================
Coverage 99.85% 99.85%
========================================
Files 65 65
Lines 7517 7520 +3
Branches 1460 1461 +1
========================================
+ Hits 7506 7509 +3
Misses 4 4
Partials 7 7 ☔ View full report in Codecov by Sentry. |
QuPath
Annotation Imports
QuPath
Annotation ImportsQuPath
Annotation Imports
An alternative approach would be to use dependency injection to achieve the same result. In this approach, you could provide a "transform" parameter (similar to PyTorch datasets) that accepts any callable and applies it to the annotation or properties during loading. The main advantage of this method is that it allows for different types of transformations to be applied during import, without the need to specify a separate set of keyword arguments for each transformation. also having many kwargs that could conflict may be annoying. You could even chain or compose transforms (much like image transforms). This can be particularly useful when importing from another application, where different types of transformations may be required. You could then show a 'recipe' (see itertools recipes) for QuPath in the examples docstring or even provide some named transform functiosn for common imports. e.g. def qupath_transform(properties: dict) -> dict:
"""An example QuPath transform."""
measurements = properties.pop("measurements", {})
properties.update(measurements)
return properties
def another_app_transform(properties: dict) -> dict:
"""An example transform for annotation from another application."""
...
store.from_geojson("qupath_annotation.json", transform=qupath_transform) This could alternatively be a transform that takes an annotation instead of just the properties dict e.g. if you wanted to apply a geometric transform based on the properties etc. Not required of course, but I think it would make things easier to test and add greater flexibility. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please can you make the changes as suggested by @John-P and discussed during the meeting on Friday?
…toolbox into easier-qupath-imports
…eAnalytics/tiatoolbox into easier-qupath-imports
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @measty
…toolbox into easier-qupath-imports
…path Signed-off-by: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com>
## 1.5.0 (2023-12-15) ### Major Updates and Feature Improvements - Adds the bokeh visualization tool. #684 - The tool allows a user to launch a server on their machine to visualise whole slide images, overlay the results of deep learning algorithms or to select a patch from whole slide image and run TIAToolbox deep learning engines. - This tool powers the TIA demos server. For details please see https://tiademos.dcs.warwick.ac.uk/. - Extends Annotation to Support Init from WKB #639 - Adds `IOConfig` for NuClick in `pretrained_model.yaml` #709 - Adds functions to save the TIAToolbox Engine outputs to Zarr and AnnotationStore files. #724 - Adds Support for QuPath Annotation Imports #721 ### Changes to API - Adds `model.to(device)` and `model.load_model_from_file()` functionality to make it compatible with PyTorch API. #733 - Replaces `pretrained` with `weights` to make the engines compatible with the new PyTorch API. #621 - Adds support for high-level imports for various utility functions and classes such as `WSIReader`, `PatchPredictor` and `imread` #606, #607, - Adds `tiatoolbox.typing` for type hints. #619 - Fixes incorrect file size saved by `save_tiles`, issue with certain WSIs raised by @TomastpPereira - TissueMasker transform now returns mask instead of a list. #748 - Fixes #732 ### Bug Fixes and Other Changes - Fixes `pixman` incompability error on Colab #601 - Removes `shapely.speedups`. The module no longer has any affect in Shapely >=2.0. #622 - Fixes errors in the slidegraph example notebook #608 - Fixes bugs in WSI Registration #645, #670, #693 - Fixes the situation where PatchExtractor.get_coords() can return patch coords which lie fully outside the bounds of a slide. #712 - Fixes #710 - Fixes #738 raised by @xiachenrui ### Development related changes - Replaces `flake8` and `isort` with `ruff` #625, #666 - Adds `mypy` checks to `root` and `utils` package. This will be rolled out in phases to other modules. #723 - Adds a module to detect file types using magic number/signatures #616 - Uses `poetry` for version updates instead of `bump2version`. #638 - Removes `setup.cfg` and uses `pyproject.toml` for project configurations. - Reduces runtime for some unit tests e.g., #627, #630, #631, #629 - Reuses models and datasets in tests on GitHub actions by utilising cache #641, #644 - Set up parallel tests locally #671 **Full Changelog:** v1.4.0...v1.5.0 --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: mostafajahanifar <74412979+mostafajahanifar@users.noreply.github.com> Co-authored-by: John Pocock <John-P@users.noreply.github.com> Co-authored-by: DavidBAEpstein <David.Epstein@warwick.ac.uk> Co-authored-by: David Epstein <22086916+DavidBAEpstein@users.noreply.github.com> Co-authored-by: Ruqayya Awan <18444369+ruqayya@users.noreply.github.com> Co-authored-by: Mark Eastwood <20169086+measty@users.noreply.github.com> Co-authored-by: adamshephard <39619155+adamshephard@users.noreply.github.com> Co-authored-by: adamshephard <adam.shephard@warwick.ac.uk> Co-authored-by: Abdol <a@fkrtech.com> Co-authored-by: Jiaqi-Lv <60471431+Jiaqi-Lv@users.noreply.github.com> Co-authored-by: Abishek <abishekraj6797@gmail.com> Co-authored-by: Dmitrii Blaginin <blaginin@mbp.lan>
## 1.5.0 (2023-12-15) ### Major Updates and Feature Improvements - Adds the bokeh visualization tool. #684 - The tool allows a user to launch a server on their machine to visualise whole slide images, overlay the results of deep learning algorithms or to select a patch from whole slide image and run TIAToolbox deep learning engines. - This tool powers the TIA demos server. For details please see https://tiademos.dcs.warwick.ac.uk/. - Extends Annotation to Support Init from WKB #639 - Adds `IOConfig` for NuClick in `pretrained_model.yaml` #709 - Adds functions to save the TIAToolbox Engine outputs to Zarr and AnnotationStore files. #724 - Adds Support for QuPath Annotation Imports #721 ### Changes to API - Adds `model.to(device)` and `model.load_model_from_file()` functionality to make it compatible with PyTorch API. #733 - Replaces `pretrained` with `weights` to make the engines compatible with the new PyTorch API. #621 - Adds support for high-level imports for various utility functions and classes such as `WSIReader`, `PatchPredictor` and `imread` #606, #607, - Adds `tiatoolbox.typing` for type hints. #619 - Fixes incorrect file size saved by `save_tiles`, issue with certain WSIs raised by @TomastpPereira - TissueMasker transform now returns mask instead of a list. #748 - Fixes #732 ### Bug Fixes and Other Changes - Fixes `pixman` incompability error on Colab #601 - Removes `shapely.speedups`. The module no longer has any affect in Shapely >=2.0. #622 - Fixes errors in the slidegraph example notebook #608 - Fixes bugs in WSI Registration #645, #670, #693 - Fixes the situation where PatchExtractor.get_coords() can return patch coords which lie fully outside the bounds of a slide. #712 - Fixes #710 - Fixes #738 raised by @xiachenrui ### Development related changes - Replaces `flake8` and `isort` with `ruff` #625, #666 - Adds `mypy` checks to `root` and `utils` package. This will be rolled out in phases to other modules. #723 - Adds a module to detect file types using magic number/signatures #616 - Uses `poetry` for version updates instead of `bump2version`. #638 - Removes `setup.cfg` and uses `pyproject.toml` for project configurations. - Reduces runtime for some unit tests e.g., #627, #630, #631, #629 - Reuses models and datasets in tests on GitHub actions by utilising cache #641, #644 - Set up parallel tests locally #671 **Full Changelog:** v1.4.0...v1.5.0
This PR is intended to make importing objects from QuPath (and other applications) easier. I have updated it to follow the suggestion of John to do it via dependency injection.
If you export some objects in .geojson from some versions of QuPath, and they have measurements, all the measurements are in a 'measurements' property in the geojson. This means, when you import into annotation store, it will import fine but the properties dict will look something like:
properties = {a couple other props, "measurements": [{'name': 'propA', 'value': valA}, {'name': 'propB', 'value': valB}, etc]}
Which is awkward for many downstream things with the nested data structure, and doesn't really mesh with how annotations are intended to be represented in the store (usually a flat dict of properties unless there's a very good reason for nesting).
This PR adds an option to provide a transform to deal with any application-specific formatting, which for example can be used to unpack measurements when importing from QuPath to give instead in a properties dict with the measurement properties unpacked:
properties = {a couple other props, 'propA': valA, 'propB': valB, etc}
Importing from QuPath is probably one of the main use-cases for this, and an example is provided in the docstring for this case, but the additional flexibility means it can be used for other use-cases too.