-
Notifications
You must be signed in to change notification settings - Fork 102
🆕 Simplified SAM segmentation in TIAViz
#968
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
base: develop
Are you sure you want to change the base?
Conversation
Merge develop
commit d315a5f415542890f351ddb07c771d62c278c2f2 Merge: dab2693 1a27178 Author: Musraf Basheer <Musraf.Basheer@warwick.ac.uk> Date: Fri Jan 24 15:07:28 2025 +0000 Merge branch 'sam-architecture' into develop commit dab2693 Merge: ca37400 8ff4f5e Author: mbasheer04 <78800844+mbasheer04@users.noreply.github.com> Date: Fri Jan 24 15:04:28 2025 +0000 Merge branch 'TissueImageAnalytics:develop' into develop commit 1a27178 Merge: 3b51acb 8ff4f5e Author: mbasheer04 <78800844+mbasheer04@users.noreply.github.com> Date: Fri Jan 24 14:57:22 2025 +0000 Merge branch 'TissueImageAnalytics:develop' into sam-architecture commit 3b51acb Author: Musraf Basheer <Musraf.Basheer@warwick.ac.uk> Date: Fri Jan 24 14:53:06 2025 +0000 Improved Engine commit 8ff4f5e Author: Mark Eastwood <20169086+measty@users.noreply.github.com> Date: Thu Jan 23 10:03:43 2025 +0000 📌 Pin `zarr<3.0.0` (#905) - `zarr>3.0.0` is not compatible yet commit 46d30f2 Merge: 1e136c5 ca37400 Author: Musraf Basheer <Musraf.Basheer@warwick.ac.uk> Date: Fri Jan 17 14:22:18 2025 +0000 Merge branch 'develop' into sam-architecture commit ca37400 Merge: 32cae0b f385ced Author: mbasheer04 <78800844+mbasheer04@users.noreply.github.com> Date: Fri Jan 17 14:18:47 2025 +0000 Merge pull request #1 from TissueImageAnalytics/develop Merge develop commit 1e136c5 Merge: 47a2190 bb9399d Author: Musraf Basheer <Musraf.Basheer@warwick.ac.uk> Date: Fri Jan 17 14:12:52 2025 +0000 Merge branch 'sam-architecture' of https://github.com/mbasheer04/tiatoolbox into sam-architecture commit 47a2190 Author: Musraf Basheer <Musraf.Basheer@warwick.ac.uk> Date: Fri Jan 17 14:08:11 2025 +0000 Improved engine & added unit tests commit f385ced Author: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri Jan 10 12:04:52 2025 +0000 :technologist: pre-commit autoupdate (#902) * 🧑💻 pre-commit autoupdate updates: - [github.com/executablebooks/mdformat: 0.7.19 → 0.7.21](hukkin/mdformat@0.7.19...0.7.21) - [github.com/astral-sh/ruff-pre-commit: v0.8.2 → v0.8.6](astral-sh/ruff-pre-commit@v0.8.2...v0.8.6) * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> commit 0ddd2b1 Author: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Thu Dec 12 14:45:39 2024 +0000 🔖 Release 1.6.0 (#898) ## TIAToolbox v1.6.0 (2024-12-12) ### Major Updates and Feature Improvements - **Foundation Models Support via `timm` API** (#856, contributed by @GeorgeBatch) - Introduced `TimmBackbone` for running additional PyTorch Image Models. - Tested models include `UNI`, `Prov-GigaPath`, and `H-optimus-0`. - Added an example notebook demonstrating feature extraction with foundation models. - `timm` added as a dependency. - **Performance Enhancements with `torch.compile`** (#716) - Improved performance on newer GPUs using `torch.compile`. - **Multichannel Input Support in `WSIReader`** (#742) - **AnnotationStore Filtering for Patch Extraction** (#822) - **Python 3.12 Support** - **Deprecation of Python 3.8 Support** - **CLI Response Time Improvements** (#795) ### API Changes - **Device Specification Update** (#882) - Replaced `has_gpu` with `device` for specifying GPU or CPU usage, aligning with PyTorch's `Model.to()` functionality. - **Windows Compatibility Enhancement** (#769) - Replaced `POWER` with explicit multiplication. ### Bug Fixes and Other Changes - **TIFFWSIReader Bound Reading Adjustment** (#777) - Fixed `read_bound` to use adjusted bounds. - Reduced code complexity in `WSIReader` (#814). - **Annotation Rendering Fixes** (#813) - Corrected rendering of annotations with holes. - **Non-Tiled TIFF Support in `WSIReader`** (#807, contributed by @GeorgeBatch) - **HoVer-Net Documentation Update** (#751) - Corrected class output information. - **Citation File Fix for `cffconvert`** (#869, contributed by @Alon-Alexander) - **Bokeh Compatibility Updates** - Updated `bokeh_app` for compatibility with `bokeh>=3.5.0`. - Switched from `size` to `radius` for `bokeh>3.4.0` compatibility (#796). - **JSON Extraction Fixes** (#772) - Restructured SQL expression construction for JSON properties with dots in keys. - **VahadaneExtractor Warning** (#871) - Added warning due to changes in `scikit-learn>0.23.0` dictionary learning (#382). - **PatchExtractor Error Message Refinement** (#883) - **Immutable Output Fix in `WSIReader`** (#850) ### Development-Related Changes - **Mypy Checks Added** - Applied to `utils`, `tools`, `data`, `annotation`, and `cli/common`. - **ReadTheDocs PDF Build Deprecation** - **Formatter Update** - Replaced `black` with `ruff-format`. - **Dependency Removal** - Removed `jinja2`. - **Test Environment Update** - Updated to `Ubuntu 24.04`. - **Conda Environment Workflow Update** - Implemented `micromamba` setup. - **Codecov Reporting Fix** (#811) **Full Changelog:** v1.5.1...v1.6.0 commit a38d95f Author: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Thu Dec 5 17:14:20 2024 +0000 [skip ci] 🐛 Fix `benchmarks/annotation_store.ipynb` (#894) - Fix `benchmarks/annotation_store.ipynb` errors commit 6b214fe Author: adamshephard <39619155+adamshephard@users.noreply.github.com> Date: Tue Dec 3 14:09:33 2024 +0000 📝 Add Example Notebook for Foundation Models (#887) - Add Example Notebook to explain how to use Foundation Models from `timm` module in TIAToolbox. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> commit 442bd3f Author: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue Dec 3 09:40:40 2024 +0000 :technologist: pre-commit autoupdate (#891) <!--pre-commit.ci start--> updates: - [github.com/executablebooks/mdformat: 0.7.18 → 0.7.19](hukkin/mdformat@0.7.18...0.7.19) --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> commit 741463c Author: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Mon Dec 2 22:45:05 2024 +0000 :pushpin: Update `ruff` Version to `v0.8.1` (#890) - Update `ruff` Version to `v0.8.1` --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> commit 9a62c10 Author: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Mon Dec 2 17:11:39 2024 +0000 [skip ci] :memo: Update Jupyter Notebooks for Release `v1.6.0` (#885) - Update Jupyter Notebooks for the New Release - Fix issues with API changes e.g., device instead of ON_GPU flag. commit 4a1940d Author: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Fri Nov 29 16:13:37 2024 +0000 :technologist: `torch.compile` is not compatible with Windows. (#888) - `torch.compile` is not currently compatible with Windows. See pytorch/pytorch#122094 commit 5f1cecb Author: Jiaqi-Lv <60471431+Jiaqi-Lv@users.noreply.github.com> Date: Fri Nov 29 14:37:39 2024 +0000 🧑💻 Refine `PatchExtractor` Error Message (#883) - Fix Misleading error message #881 commit 5beb119 Author: Musraf Basheer <Musraf.Basheer@warwick.ac.uk> Date: Tue Nov 26 18:47:14 2024 +0000 Initialised SAM Engine commit bb9399d Author: mbasheer04 <78800844+mbasheer04@users.noreply.github.com> Date: Fri Nov 22 19:26:45 2024 +0000 Created using Colab commit ca13e7f Author: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Thu Nov 21 22:28:44 2024 +0000 ♻️ Update Changes from New Engine Design (#882) - Add changes from New engine design #578. This will not only simplify the PR but also keep the main repo up to date. - Refactor `model_to` to `model_abc` - Instead of `on_gpu` use `device` as an input in line with `PyTorch`. - `infer_batch` uses `device` as an input instead of `on_gpu` commit 91ca877 Merge: 1e27436 32cae0b Author: mbasheer04 <bmusraf1@gmail.com> Date: Thu Nov 21 21:03:41 2024 +0000 Merge branch 'develop' of https://github.com/TissueImageAnalytics/tiatoolbox into sam-architecture commit 1e27436 Author: mbasheer04 <bmusraf1@gmail.com> Date: Thu Nov 21 21:00:34 2024 +0000 Implementing architecture for full-image segmentation commit 32cae0b Author: Abdol <a@fkrtech.com> Date: Fri Nov 15 20:29:34 2024 +0000 ⚡️Add `torch.compile` Functionality (#716) - Integrates PyTorch 2.0's [torch.compile](https://pytorch.org/docs/stable/generated/torch.compile.html) functionality to demonstrate performance improvements in torch code. This PR focuses on adding `torch.compile` to `PatchPredictor`. **Notes:** - According to the [documentation](https://pytorch.org/tutorials/intermediate/torch_compile_tutorial.html), noticeable performance can be achieved when using modern NVIDIA GPUs (H100, A100, or V100) **TODO:** - [x] Resolve compilation errors related to using `torch.compile` in running models - [x] Initial config - [x] Add to patch predictor - [x] Add to registration - [x] Add to segmentation - [x] Test on custom models - [x] Test on `torch.compile` compatible GPUs --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Co-authored-by: Jiaqi-Lv <60471431+Jiaqi-Lv@users.noreply.github.com> commit e1a57c6 Author: mbasheer04 <bmusraf1@gmail.com> Date: Fri Nov 15 17:29:44 2024 +0000 Created Jupyter Notebook for SAM architecture commit 9113996 Author: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri Nov 15 17:18:16 2024 +0000 :technologist: pre-commit autoupdate (#880) * 🧑💻 pre-commit autoupdate updates: - [github.com/astral-sh/ruff-pre-commit: v0.7.0 → v0.7.2](astral-sh/ruff-pre-commit@v0.7.0...v0.7.2) * 📌 Update `ruff` version. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> commit c980eec Author: George Batchkala <46561186+GeorgeBatch@users.noreply.github.com> Date: Fri Nov 15 16:31:42 2024 +0000 🆕 Integrate Foundation Models Available VIA `timm`: `UNI`, `Prov-GigaPath`, `H-optimus-0` (#856) - Integrates pre-trained foundation models from other labs into tiatoolbox.models.architecture.vanilla.py. Currently, the `_get_architecture()` function allows the use of models from `torchvision.models`. A new function `_get_timm_architecture()` has been incorporated to support foundation models which are available from `timm` with weights on HuggingFace Hub. - All the models from `timm` that used require users to sign the licence agreement with the authors. - The users can add new models by modifying `_get_timm_architecture()` --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> commit 7fb9926 Author: Mostafa Jahanifar <74412979+mostafajahanifar@users.noreply.github.com> Date: Fri Nov 8 17:25:02 2024 +0000 🐛 Add Warning for `VahadaneExtractor` Algorithm Instability (#871) - Adds a warning to the `VahadaneExtractor` to inform users about the algorithm's instability due to changes in the dictionary learning algorithm in `scikit-learn versions > 0.23.0 (see issue #382)`. - The docstrings are updated accordingly to reflect this warning. - No other functionality is altered. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> commit f4f2fa6 Author: mbasheer04 <bmusraf1@gmail.com> Date: Sun Nov 3 23:41:50 2024 +0000 Initial setup of SAM architecture commit 12d435e Author: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Thu Oct 24 16:40:56 2024 +0100 :pushpin: Pin `numpy<2.0.0` (#876) - `numpy>=2.0` breaks the tests. commit 76f02f8 Author: Mark Eastwood <20169086+measty@users.noreply.github.com> Date: Fri Oct 18 14:53:49 2024 +0100 🆕 Use Annotations as a Filter for Patch Extraction (#822) - Adds the ability to get patches filtered by class or label using AnnotationStore. - Allows the user to provide a path to an annotation store as the mask. - By default the mask will then be built out of all the annotations, but the user can also provide any filter that works in the annotation store, and have only those annotations make the mask. For example, if the user have some pathologist annotations with some regions, and they would only want to extract patches which have some overlap with regions labelled 'tumor' or any other class, they would just need to provide the appropriate string ("props['label'] == 'tumor'" for example). --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> commit 0b857c7 Author: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri Oct 18 12:00:04 2024 +0100 :technologist: `pre-commit` autoupdate (#868) * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/pre-commit/pre-commit-hooks: v4.6.0 → v5.0.0](pre-commit/pre-commit-hooks@v4.6.0...v5.0.0) - [github.com/astral-sh/ruff-pre-commit: v0.6.5 → v0.6.9](astral-sh/ruff-pre-commit@v0.6.5...v0.6.9) * 🐛 Fix pre-commit yaml * 🧑💻 Change to monthly schedule. * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/executablebooks/mdformat: 0.7.17 → 0.7.18](hukkin/mdformat@0.7.17...0.7.18) - [github.com/pre-commit/pre-commit-hooks: v4.6.0 → v5.0.0](pre-commit/pre-commit-hooks@v4.6.0...v5.0.0) - [github.com/astral-sh/ruff-pre-commit: v0.6.5 → v0.6.9](astral-sh/ruff-pre-commit@v0.6.5...v0.6.9) * 🔀 Merge online and local copies * 📌 Pin dependencies * 📌 Pin `ruff` version --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> commit 52792bc Author: Alon Alexander <alon008@gmail.com> Date: Wed Oct 2 12:51:52 2024 +0300 🐛 Fix `CITATION.cff` to Make it Compatible with `cffconvert` - To cite this repository using `cffconvert`, the conversion fails as the citation file was invalid. - This PR fixes the citation file to a valid ORCID. commit 3714ef7 Author: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Date: Wed Oct 2 10:22:26 2024 +0100 :pushpin: Pin `bokeh` version to less than 3.6.0 (#870) - Pin `bokeh` version to less than `3.6.0` - `bokeh` 3.6.0 has breaking changes
for more information, see https://pre-commit.ci
Removing large files Removing unneccessary files Fixing pre-commit [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Fixing PR issues :technologist: pre-commit autoupdate (#910) * 🧑💻 pre-commit autoupdate updates: - [github.com/executablebooks/mdformat: 0.7.21 → 0.7.22](hukkin/mdformat@0.7.21...0.7.22) - [github.com/astral-sh/ruff-pre-commit: v0.8.6 → v0.9.4](astral-sh/ruff-pre-commit@v0.8.6...v0.9.4) * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * 📌 Update `ruff` dependency * 🔥 TIAToolbox does not support Python > 3.12 yet - There is no need for this check as this will be tested while upgrading to Python 3.13 * ♻️ Refactor `typing` to `type_hints`. * 🐛 Fix `mypy` workflow --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> 📝 Update Documentation Structure (#909) - Use `Python 3.12` for docs build - Update `copyright` year to `2025` - Landing page now shows text from README - Update documentation structure - Update `readthedocs` Build - Remove `usage.rst` - Rename Jupyter Notebooks to Usage Examples - Show README for Usage Examples instead of TOC - Reduce TOC depth for basic functionalities and pipelines - Improve `README` quality. 🐛 Fix in `test_arch_mapde` and `test_arch_sccnn` (#911) - If cuda is available model should be moved to cuda otherwise tests will fail as test data is moved to cuda. [skip ci] 📝 Improve Documentation (#913) - Update CONTRIBUTING.rst - Bug fix in conf.py to fix notebook links - Update `examples/README.md` - Update `docs/installation.rst` - Update `docs/visualization.rst` --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: adamshephard <39619155+adamshephard@users.noreply.github.com> :bug: Fix `MapDe` `dist_filter` Shape (#914) - Fix `dist_filter` in `MapDe` model for multi-class output. Explanation: Previously, if we set `num_class` to more than 1, the model would still output 1 channel. This was because the `dist_filter` always had size of 1 in its first dimension, however the first dimension determines the number of output channels in the tensor produced by `torch.functional.F.conv2d`. This PR changes this by repeating the filters the match the number of output classes. :technologist: pre-commit autoupdate (#916) * 🧑💻 pre-commit autoupdate updates: - [github.com/astral-sh/ruff-pre-commit: v0.9.4 → v0.9.9](astral-sh/ruff-pre-commit@v0.9.4...v0.9.9) * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * 🔨 Update `ruff` version * 🔨 Update noqa for Unused static method argument --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Add FsspecJsonWSIReader class. (#897) The `FsspecJsonWSIReader` reads fsspec json file which represents SVS or TIFF whole slide image. The images are accessible by HTTP range requests, eg: `https://api.gdc.cancer.gov/data/73c69d24-6f9e-44e2-bfe5-a608d4cf5c27` The whole image can be downloaded like: `curl -C - -o TCGA-22-1017-01Z-00-DX1.9562FE79-A261-42D3-B394-F3E0E2FF7DDA.svs https://api.gdc.cancer.gov/data/73c69d24-6f9e-44e2-bfe5-a608d4cf5c27` The `FsspecJsonWSIReader` class has a `_zarr_store` field which is created by reading json file using `fsspec`: ``` mapper = fsspec.get_mapper( "reference://", fo=str(input_img), target_protocol="file" ) self._zarr_array = zarr.open(mapper, mode="r") self._zarr_store = self._zarr_array.store self._zarr_lru_cache = zarr.LRUStoreCache(self._zarr_store, max_size=cache_size) self._zarr_group = zarr.open(self._zarr_lru_cache) ``` This is equivalent to `TIFFWSIReader` code: ``` self._zarr_store = tifffile.imread( self.input_path, series=self.series_n, aszarr=True, ) self._zarr_lru_cache = zarr.LRUStoreCache(self._zarr_store, max_size=cache_size) self._zarr_group = zarr.open(self._zarr_lru_cache) ``` Both FsspecJsonWSIReader and TIFFWSIReader forward calls to `read_bounds` and `read_rect` methods of the`TIFFWSIReaderDelegate` delegate instance. The method `_info` of the`TIFFWSIReaderDelegate` reads SVS metadata which is stored in the root group metadata like: ``` { ".zattrs": { "multiscales": [ { "metadata": { "objective_power": 40, "vendor": "Aperio", "mpp": [0.2525, 0.2525] } } ] } } ``` To test, execute from the root dir: ``` pip install -r requirements/requirements_dev.txt mkdir -p samples/slides mkdir -p samples/fsspec cd samples/slides curl -C - -o TCGA-22-1017-01Z-00-DX1.9562FE79-A261-42D3-B394-F3E0E2FF7DDA.svs https://api.gdc.cancer.gov/data/73c69d24-6f9e-44e2-bfe5-a608d4cf5c27 cd ../../ cp tiatoolbox/utils/tiff_to_fsspec.py . python tiff_to_fsspec.py "samples/slides/TCGA-22-1017-01Z-00-DX1.9562FE79-A261-42D3-B394-F3E0E2FF7DDA.svs" "samples/fsspec/73c69d24-6f9e-44e2-bfe5-a608d4cf5c27_fsspec.json" "https://api.gdc.cancer.gov/data/73c69d24-6f9e-44e2-bfe5-a608d4cf5c27" ``` Create `tileserver.py` inside of the project root: ``` from flask_cors import CORS from tiatoolbox.visualization import TileServer from tiatoolbox.wsicore.wsireader import FsspecJsonWSIReader wsi = FsspecJsonWSIReader.open( "./samples/fsspec/73c69d24-6f9e-44e2-bfe5-a608d4cf5c27_fsspec.json" ) tile_server = TileServer( title="Tiatoolbox TileServer", layers={"layer": wsi}, ) CORS(tile_server, send_wildcard=True) tile_server.run(host="127.0.0.1", port=5000) ``` Open `http://127.0.0.1:5000/` and verify that it works. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> ✨ Support for Additional Foundation Models (#906) - Add support for additional foundation models as feature extractors using the TimmBackbone. - Added models include: UNI2, Virchow, Virchow2, kaiko and H-optimus-1. - Add more information to docstrings. - Allow foundation models with additional parameters. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com> Fixing PR issues
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #968 +/- ##
=========================================
Coverage 99.37% 99.38%
=========================================
Files 71 73 +2
Lines 9175 9312 +137
Branches 1197 1206 +9
=========================================
+ Hits 9118 9255 +137
Misses 31 31
Partials 26 26 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
PR is now ready for review |
SAM segmentation in TIAViz
| autoupdate_commit_msg: ':technologist: pre-commit autoupdate' | ||
| autoupdate_schedule: 'monthly' | ||
| default_language_version: | ||
| python: python3.12 |
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.
| python: python3.12 | |
| python: python3.10 |
Can we set this to the base supported version i.e., 3.10.
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.
Pull request overview
This PR adds simplified SAM (Segment Anything Model) integration to TIAViz, enabling interactive segmentation using point and bounding box prompts within a specific view window. The implementation includes a new SAM architecture wrapper, a PromptSegmentor engine, and UI integration for interactive use.
Changes:
- Adds SAM model architecture and PromptSegmentor engine for interactive segmentation with point/box prompts
- Integrates SAM into TIAViz UI with callback for running segmentation on selected regions
- Extends utility functions to support offset parameter for annotation coordinate transformations
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| tiatoolbox/models/architecture/sam.py | New SAM model architecture using transformers library for zero-shot segmentation |
| tiatoolbox/models/engine/prompt_segmentor.py | New PromptSegmentor engine that handles SAM inference and output conversion |
| tiatoolbox/visualization/bokeh_app/main.py | Adds sam_segment callback and SAM model option to UI |
| tiatoolbox/utils/misc.py | Extends process_contours and dict_to_store_semantic_segmentor to support offset parameter |
| tiatoolbox/visualization/tileserver.py | Filters out temporary bokeh databases from commit operations |
| tiatoolbox/models/init.py | Exports SAM and PromptSegmentor classes |
| requirements/requirements.txt | Adds transformers>=4.51.1 dependency |
| .pre-commit-config.yaml | Sets default Python version to 3.12 |
| tests/models/test_prompt_segmentor.py | Unit tests for PromptSegmentor functionality |
| tests/models/test_arch_sam.py | Unit tests for SAM architecture |
| tests/test_app_bokeh.py | Integration test for SAM in TIAViz UI |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if box_coords is not None: | ||
| boxes = box_coords[i] | ||
| # Convert box coordinates to list | ||
| boxes = [boxes[:, None, :].tolist()] | ||
| image_masks, image_scores = self._process_prompts( | ||
| image, | ||
| embeddings, | ||
| orig_sizes, | ||
| reshaped_sizes, | ||
| None, | ||
| boxes, | ||
| point_labels, | ||
| ) | ||
| masks.append(np.array([image_masks])) | ||
| scores.append(np.array([image_scores])) | ||
|
|
||
| if point_coords is not None: | ||
| points = point_coords[i] | ||
| # Convert point coordinates to list | ||
| point_labels = np.ones((1, len(points), 1), dtype=int).tolist() | ||
| points = [points[:, None, :].tolist()] | ||
| image_masks, image_scores = self._process_prompts( | ||
| image, | ||
| embeddings, | ||
| orig_sizes, | ||
| reshaped_sizes, | ||
| points, | ||
| None, | ||
| point_labels, | ||
| ) | ||
| masks.append(np.array([image_masks])) | ||
| scores.append(np.array([image_scores])) | ||
|
|
||
| torch.cuda.empty_cache() | ||
|
|
||
| return np.concatenate(masks, axis=2), np.concatenate(scores, axis=2) |
Copilot
AI
Feb 3, 2026
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.
When both point_coords and box_coords are provided for the same image, this code will call _process_prompts twice and append results to masks and scores lists separately. This means if a user provides both points and boxes, the concatenation at line 164 will have double the expected number of masks (one set from boxes, one set from points), rather than combining them as joint prompts. Consider either: 1) combining prompts in a single _process_prompts call, or 2) documenting that only one prompt type should be provided at a time, or 3) adding logic to handle this case appropriately.
| save_dir = Path(save_dir) | ||
| for i, _mask in enumerate(masks): | ||
| save_path = save_dir / f"{i}" | ||
| mask = np.any(_mask[0], axis=0, keepdims=False) | ||
| dict_to_store_semantic_segmentor( | ||
| patch_output={"predictions": mask[0]}, | ||
| scale_factor=self.scale, | ||
| offset=self.offset, | ||
| save_path=Path(f"{save_path}.{i}.db"), | ||
| ) | ||
| paths.append(Path(f"{save_path}.{i}.db")) |
Copilot
AI
Feb 3, 2026
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.
The save_dir directory is not created before use. If the directory doesn't exist, dict_to_store_semantic_segmentor will fail when trying to save the database file. Add save_dir.mkdir(parents=True, exist_ok=True) after line 82 to ensure the directory exists before attempting to save files to it.
| model = SAM() | ||
| self.model = model | ||
| self.scale = 1.0 | ||
| self.offset = (0, 0) |
Copilot
AI
Feb 3, 2026
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.
The offset attribute is initialized as a tuple (0, 0) but is later assigned as a numpy array in main.py line 1294 (offset = np.array([x_start, y_start])). This type inconsistency could cause issues. The offset is expected to be used in arithmetic operations with numpy arrays in process_contours. Consider initializing offset as np.array([0, 0]) for type consistency, or document that it can be either a tuple or numpy array.
| self.offset = (0, 0) | |
| self.offset = np.array([0, 0]) |
| scores.append(np.array([image_scores])) | ||
|
|
||
| torch.cuda.empty_cache() | ||
|
|
Copilot
AI
Feb 3, 2026
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.
If neither point_coords nor box_coords is provided for an image (both are None), the masks and scores lists will remain empty for that image, leading to an empty concatenation at line 164 which will likely fail. While infer_batch has validation to check that at least one is provided globally, this doesn't ensure that each individual image in the batch has at least one prompt. Consider adding validation within the loop to ensure each image has at least one prompt type, or handle the case where both are None for a specific image.
| if not masks or not scores: | |
| raise ValueError( | |
| "No segmentation masks were generated. Ensure that each image in " | |
| "`imgs` has at least one corresponding prompt in `point_coords` " | |
| "or `box_coords`." | |
| ) |
| def calc_mpp( | ||
| self, area_dims: IntPair, base_mpp: float, fixed_size: int = 1500 | ||
| ) -> float: |
Copilot
AI
Feb 3, 2026
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.
The return type annotation indicates this method returns a float, but it actually returns a tuple of (float, float) containing both the calculated mpp and the scale factor. Update the return type annotation to tuple[float, float] to match the actual return value.
| for i in range(len(y)) | ||
| ] | ||
| width = [round(UI["box_source"].data["width"][i]) for i in range(len(x))] | ||
| height = [round(UI["box_source"].data["height"][0]) for i in range(len(x))] |
Copilot
AI
Feb 3, 2026
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.
The variable name 'height' is reused at line 1330, shadowing the height variable defined at line 1319. This causes the box height calculation to always use the height from index 0 (UI["box_source"].data["height"][0]) instead of the correct index i. This will produce incorrect box coordinates when multiple boxes are present. Change line 1330 to use index i instead of 0: height = [round(UI["box_source"].data["height"][i]) for i in range(len(x))]
| height = [round(UI["box_source"].data["height"][0]) for i in range(len(x))] | |
| height = [round(UI["box_source"].data["height"][i]) for i in range(len(x))] |
| mask = np.any(_mask[0], axis=0, keepdims=False) | ||
| dict_to_store_semantic_segmentor( | ||
| patch_output={"predictions": mask[0]}, | ||
| scale_factor=self.scale, |
Copilot
AI
Feb 3, 2026
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.
The scale_factor parameter should be a tuple of floats (tuple[float, float]) as expected by dict_to_store_semantic_segmentor and process_contours functions, but self.scale is a single float value. This will cause the multiplication in process_contours at line 1236 (scaled_coords = np.array([np.array(scale_factor) * coords])) to fail with a shape mismatch error. Consider changing this to scale_factor=(self.scale, self.scale) to provide the expected 2D scale factor.
| scale_factor=self.scale, | |
| scale_factor=(self.scale, self.scale), |
| float: | ||
| Microns per pixel required to scale the area to a fixed size. |
Copilot
AI
Feb 3, 2026
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.
The docstring incorrectly states the return type as "float" when the method actually returns a tuple. Update the Returns section to document both return values: the calculated mpp (float) and the scale factor (float), or change it to "tuple[float, float]".
| float: | |
| Microns per pixel required to scale the area to a fixed size. | |
| tuple[float, float]: | |
| A tuple containing: | |
| - Microns per pixel required to scale the area to a fixed size. | |
| - The scale factor used for scaling. |
| data={"overlay_path": fname}, | ||
| ) | ||
| ann_types = json.loads(resp.text) | ||
| update_ui_on_new_annotations(ann_types) |
Copilot
AI
Feb 3, 2026
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.
The temporary directory created with tempfile.mkdtemp is never cleaned up after use. Unlike the segment_on_box function which calls rmtree to clean up temporary directories, this function leaves the temporary directory and its contents on disk. Add rmtree(tmp_save_dir) after the annotations have been processed to prevent accumulation of temporary files.
| update_ui_on_new_annotations(ann_types) | |
| update_ui_on_new_annotations(ann_types) | |
| rmtree(tmp_save_dir) |
| model = SAM(device=select_device(on_gpu=ON_GPU)) | ||
|
|
||
| # create image patch and prompts | ||
| patch = img[63:191, 750:878, :] |
Copilot
AI
Feb 3, 2026
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.
This assignment to 'patch' is unnecessary as it is redefined before this value is used.
| patch = img[63:191, 750:878, :] |
| NucleusInstanceSegmentor, | ||
| from tiatoolbox.models.engine.nucleus_instance_segmentor import NucleusInstanceSegmentor | ||
| from tiatoolbox.models.engine.prompt_segmentor import ( | ||
| PromptSegmentor, # skipcq: FLK-E402 |
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.
It's strange that you are getting FLK-E402 error on this.
| # Get box coordinates | ||
| x = np.round(UI["box_source"].data["x"]) | ||
| y = np.round(UI["box_source"].data["y"]) | ||
| height = np.round(UI["box_source"].data["height"]) |
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.
height and width is being overwritten on 1329 and 1330
| @@ -0,0 +1,53 @@ | |||
| """Unit test package for prompt segmentor.""" | |||
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 move this file to tests/engines
| point_coords: list | None = None, | ||
| box_coords: list | None = None, | ||
| ) -> tuple[np.ndarray, np.ndarray]: | ||
| """Torch method. Defines forward pass on each image in the batch. |
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.
| """Torch method. Defines forward pass on each image in the batch. | |
| """PyTorch method. Defines forward pass on each image in the batch. |
|
|
||
| """ | ||
|
|
||
| def __init__( |
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.
Do we need any of these inputs to match with the new EngineABC signature?
def __init__(
self: EngineABC,
model: str | ModelABC,
batch_size: int = 8,
num_workers: int = 0,
weights: str | Path | None = None,
*,
device: str = "cpu",
verbose: bool = False,
| point_coords: np.ndarray | None = None, | ||
| box_coords: np.ndarray | None = None, | ||
| save_dir: str | Path | None = None, | ||
| device: str = "cpu", |
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.
Is there an output type option if a user wants to save the results?
| Returns: | ||
| list[Path]: | ||
| Paths to the saved output databases. | ||
| """ |
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.
| """ | |
| """ |
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
This looks good. A few minor comments if you could address before we merge.
- I was not able to test it though on my workstation using
--base-pathargument. - Also it would be good to show any progress bar or message on the visualization rather than only in the terminal if possible.
- Can we reset the model weights after the first run if possible?
This PR takes the sam-viz PR and fixes and substantially simplifies it.
I think the original PR was going for a more general prompt segmentor engine that would in theory cope with prompts dispersed over a whole WSI, but I think that approach has issues in practice (and it would also need some significant work to fix from its current state, I think). This PR focusses on segmenting prompts made within a specific view window, which I think is more practical and allows for a much simplified approach.
To use, draw a few points (and/or a box) on some object(s) in the field of view in TIAViz using this widget:

Then select SAM in the model select box and click run. The segmetations should be displayed after a short time.
Examples:


