Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
2bee250
Merge pull request #17 from EIDOSLAB/development
carloalbertobarbano Aug 8, 2022
ece6e7c
update backend comparison
carloalbertobarbano Aug 8, 2022
5e2fdf5
bump version to 1.2.0
carloalbertobarbano Aug 8, 2022
a8b57f2
update README
carloalbertobarbano Aug 8, 2022
838a806
update README
carloalbertobarbano Aug 8, 2022
bbdf449
rename cov_tf and percentile_tf to cov and percentile
carloalbertobarbano Aug 8, 2022
a34fc47
update tests
carloalbertobarbano Aug 8, 2022
c2c39b4
Use CPU flavor of torch and fix tf and protobuf version
carloalbertobarbano Aug 8, 2022
ecacfb8
fixed tf percentile test - off by one
andreped Aug 8, 2022
89a8407
removed redundant tensor conversion
andreped Aug 8, 2022
96c6be4
Merge pull request #22 from andreped/v1.2.0
carloalbertobarbano Aug 8, 2022
5d1b729
move solveLS to torchstain.tf.utils
carloalbertobarbano Aug 8, 2022
fd5c8af
Merge branch 'v1.2.0' of github.com:EIDOSlab/torchstain into v1.2.0
carloalbertobarbano Aug 8, 2022
32f6f67
fix type hint
carloalbertobarbano Aug 9, 2022
163d10b
print version
carloalbertobarbano Aug 9, 2022
45b98da
disable stdout capture
carloalbertobarbano Aug 9, 2022
0616dea
fix tests
carloalbertobarbano Aug 9, 2022
ea125bc
Merge branch 'v1.2.0' of github.com:EIDOSlab/torchstain into v1.2.0
carloalbertobarbano Aug 9, 2022
3bcbd72
update README
carloalbertobarbano Aug 9, 2022
cb99e5e
fix docstring
carloalbertobarbano Aug 9, 2022
a4246c2
update description
carloalbertobarbano Aug 9, 2022
7298fc4
add python 3.6
carloalbertobarbano Aug 9, 2022
899e41f
fix test configurations
carloalbertobarbano Aug 9, 2022
036d1ee
fix test configurations
carloalbertobarbano Aug 9, 2022
78e42aa
remove python 3.6 from tensorflow tests
carloalbertobarbano Aug 9, 2022
803c014
enable all systems
carloalbertobarbano Aug 9, 2022
8560513
perform all tests for main branch only
carloalbertobarbano Aug 9, 2022
1282a02
update description
carloalbertobarbano Aug 9, 2022
365a494
remove leading space
carloalbertobarbano Aug 9, 2022
42561ce
Merge pull request #18 from EIDOSLAB/v1.2.0
carloalbertobarbano Aug 10, 2022
ecf0ade
add build action
carloalbertobarbano Aug 10, 2022
bc7c6a5
add build&deploy action on release created
carloalbertobarbano Aug 10, 2022
0248a93
add build&deploy action on release created
carloalbertobarbano Aug 10, 2022
e588a63
fix typo in action yaml
carloalbertobarbano Aug 10, 2022
93fd522
deploy on tagged version commit
carloalbertobarbano Aug 10, 2022
978c84c
deploy on tagged version commit
carloalbertobarbano Aug 10, 2022
3fbf493
deploy on tagged version commit
carloalbertobarbano Aug 10, 2022
a104b34
do not specify main branch for push
carloalbertobarbano Aug 10, 2022
b257184
update README [skip ci]
carloalbertobarbano Aug 10, 2022
97ea765
added experimental numpy support for Reinhard
andreped Nov 23, 2022
ba22905
reinhard works, but required opencv for rgb/lab conversion
andreped Nov 23, 2022
657d136
replaced opencv with scikit-image -> towards numpy only
andreped Nov 23, 2022
c2c4625
numpy rgb2lab working
andreped Nov 23, 2022
39bb65a
refactored rgb2lab
andreped Nov 23, 2022
a597208
removed sklearn + opencv from rgb2lab
andreped Nov 23, 2022
e8907d5
lab2rgb working, refactored to pure numpy
andreped Nov 23, 2022
b3f7209
removed redundant cv2 import
andreped Nov 23, 2022
74c22e3
refactored to keep consistent structure
andreped Nov 23, 2022
25f1602
refactored
andreped Nov 23, 2022
5970a45
fixed spacing
andreped Nov 23, 2022
5cac2a5
started to add unit test for rgb/lab conversion
andreped Nov 23, 2022
5738b1f
added comment of Reinhard to README
andreped Nov 23, 2022
ee360c6
added Reinhard to alg table
andreped Nov 24, 2022
1ea3bad
added convenience functions for TF reinhard
andreped Nov 24, 2022
fbf0627
added RGB/LAB converters for TF
andreped Nov 24, 2022
c379f43
forgot lab2rgb
andreped Nov 24, 2022
87dc635
added TF Reinhard
andreped Nov 24, 2022
f30f02a
Reinhard TF works - added it to API
andreped Nov 24, 2022
193041d
updated README
andreped Nov 24, 2022
d029fe4
moved result.png to data/
andreped Nov 25, 2022
946db08
minor refactoring in README
andreped Nov 25, 2022
8b02b9f
Merge pull request #25 from andreped/reinhard
carloalbertobarbano Dec 2, 2022
bde067e
added torch reinhard base support
andreped Dec 3, 2022
03d499a
removed redundant import and added newline in tf
andreped Dec 3, 2022
ce443d8
added all utils for torch
andreped Dec 3, 2022
18b539e
torch reinhard almost working
andreped Dec 3, 2022
ede14d7
fixed bug - torch reinhard works
andreped Dec 3, 2022
51f9448
updated README as all backends are supported with Reinhard
andreped Dec 3, 2022
3af7477
added reinhard test for all backends
andreped Dec 3, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Build and upload to PyPI

on:
push

jobs:
build_wheels:
name: Build release
runs-on: ubuntu-18.04

steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
with:
python-version: '3.x'

- name: Install deps
run: |
pip install setuptools wheel

- name: Build wheels
run: python setup.py sdist bdist_wheel

- uses: actions/upload-artifact@v3
with:
path: ./dist/*

upload_pypi:
needs: build_wheels
runs-on: ubuntu-18.04

if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')

steps:
- uses: actions/download-artifact@v3
with:
name: artifact
path: dist

- uses: pypa/gh-action-pypi-publish@v1.5.0
with:
user: __token__
password: ${{ secrets.torchstain_deploy_token }}

75 changes: 26 additions & 49 deletions .github/workflows/tests.yml → .github/workflows/tests_full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ name: tests
on:
push:
branches:
- '*'
- main
pull_request:
branches:
- '*'
- main

jobs:
build:
runs-on: ubuntu-18.04

if: startsWith(github.ref, 'refs/tags/v') != true

steps:
- uses: actions/checkout@v1
- name: Set up Python 3.6
Expand All @@ -31,46 +34,14 @@ jobs:
path: ${{github.workspace}}/dist/torchstain-*.whl
if-no-files-found: error

test:
needs: build
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-2019, ubuntu-18.04, macos-11]
python-version: [3.6, 3.7, 3.8, 3.9]

steps:
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}

- name: Download artifact
uses: actions/download-artifact@master
with:
name: "Python wheel"

- name: Install deps and wheel
run: |
pip install tensorflow torch
pip install --find-links=${{github.workspace}} torchstain

- name: Install test dependencies
run: pip install opencv-python torchvision scikit-image pytest

- name: Run tests
run: |
pytest -v tests/test_utils.py
pytest -v tests/test_normalizers.py

test-tf:
needs: build
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ windows-2019, ubuntu-18.04, macos-11 ]
python-version: [ 3.7 ]
python-version: [ 3.7, 3.8, 3.9 ]
tf-version: [2.7.0, 2.8.0, 2.9.0]

steps:
- uses: actions/checkout@v1
Expand All @@ -84,24 +55,30 @@ jobs:
with:
name: "Python wheel"

- name: Install deps and wheel
- name: Install dependencies
run: |
pip install tensorflow
pip install --find-links=${{github.workspace}} torchstain
pip install tensorflow==${{ matrix.tf-version }} protobuf==3.20.* opencv-python-headless scikit-image
pip install pytest

- name: Install test dependencies
run: pip install opencv-python scikit-image pytest
- name: Install wheel
run: pip install --find-links=${{github.workspace}} torchstain

- name: Run tests
run: pytest -v tests/test_tf_normalizer.py
run: pytest -vs tests/test_tf.py

test-torch:
needs: build
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ windows-2019, ubuntu-18.04, macos-11 ]
python-version: [ 3.7 ]
python-version: [ 3.6, 3.7, 3.8, 3.9 ]
pytorch-version: [1.8.0, 1.9.0, 1.10.0, 1.11.0, 1.12.0]
exclude:
- python-version: 3.6
pytorch-version: 1.11.0
- python-version: 3.6
pytorch-version: 1.12.0

steps:
- uses: actions/checkout@v1
Expand All @@ -115,13 +92,13 @@ jobs:
with:
name: "Python wheel"

- name: Install deps and wheel wheel
- name: Install dependencies
run: |
pip install torch
pip install --find-links=${{github.workspace}} torchstain
pip install torch==${{ matrix.pytorch-version }} torchvision opencv-python-headless scikit-image
pip install pytest

- name: Install test dependencies
run: pip install opencv-python torchvision scikit-image pytest
- name: Install wheel
run: pip install --find-links=${{github.workspace}} torchstain

- name: Run tests
run: pytest -v tests/test_torch_normalizer.py
run: pytest -vs tests/test_torch.py
86 changes: 86 additions & 0 deletions .github/workflows/tests_quick.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: tests

on:
push:
branches-ignore:
- main
pull_request:
branches-ignore:
- main

jobs:
build:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v1
- name: Set up Python 3.6
uses: actions/setup-python@v2
with:
python-version: 3.6

- name: Install dependencies
run: pip install wheel setuptools

- name: Build wheel
run: python setup.py bdist_wheel

- name: Upload Python wheel
uses: actions/upload-artifact@v2
with:
name: Python wheel
path: ${{github.workspace}}/dist/torchstain-*.whl
if-no-files-found: error

test-tf:
needs: build
runs-on: ubuntu-18.04

steps:
- uses: actions/checkout@v1
- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.8

- name: Download artifact
uses: actions/download-artifact@master
with:
name: "Python wheel"

- name: Install dependencies
run: |
pip install tensorflow protobuf==3.20.* opencv-python-headless scikit-image
pip install pytest

- name: Install wheel
run: pip install --find-links=${{github.workspace}} torchstain

- name: Run tests
run: pytest -vs tests/test_tf.py

test-torch:
needs: build
runs-on: ubuntu-18.04

steps:
- uses: actions/checkout@v1
- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.8

- name: Download artifact
uses: actions/download-artifact@master
with:
name: "Python wheel"

- name: Install dependencies
run: |
pip install torch torchvision opencv-python-headless scikit-image
pip install pytest

- name: Install wheel
run: pip install --find-links=${{github.workspace}} torchstain

- name: Run tests
run: pytest -vs tests/test_torch.py
66 changes: 53 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,22 @@
[![License](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
[![tests](https://github.com/EIDOSLAB/torchstain/workflows/tests/badge.svg)](https://github.com/EIDOSLAB/torchstain/actions)
[![Pip Downloads](https://img.shields.io/pypi/dm/torchstain?label=pip%20downloads&logo=python)](https://pypi.org/project/torchstain/)
[![DOI](https://zenodo.org/badge/323590093.svg)](https://zenodo.org/badge/latestdoi/323590093)

GPU-accelerated stain normalization tools for histopathological images. Compatible with PyTorch, TensorFlow, and Numpy.
Normalization algorithms currently implemented:

- Macenko et al. [\[1\]](#reference) (ported from [numpy implementation](https://github.com/schaugf/HEnorm_python))
- Reinhard et al. [\[2\]](#reference)

## Installation

```bash
pip install torchstain
```

To install a specific backend use either ```torchstain[torch]``` or ```torchstain[tf]```. The numpy backend is included by default in both.

## Example Usage

```python
Expand All @@ -38,26 +42,62 @@ t_to_transform = T(to_transform)
norm, H, E = normalizer.normalize(I=t_to_transform, stains=True)
```

![alt text](result.png)
![alt text](data/result.png)

## Implemented algorithms

| Algorithm | numpy | torch | tensorflow |
|-|-|-|-|
| Macenko | ✓ | ✓ | ✓ |
| Reinhard | ✓ | ✓ | ✓ |

## Backend comparison

Results with 10 runs per size on a Intel(R) Core(TM) i5-8365U CPU @ 1.60GHz


| size | numpy avg. time | numpy tot. time | torch avg. time | torch tot. time |
|--------|-------------------|-------------------|-------------------|-------------------|
| 224x224 | 0.0323s ± 0.0032 | 0.3231s | 0.0234s ± 0.0384 | 0.2340s |
| 448x448 | 0.1228s ± 0.0042 | 1.2280s | 0.0395s ± 0.0168 | 0.3954s |
| 672x672 | 0.2653s ± 0.0106 | 2.6534s | 0.0753s ± 0.0157 | 0.7527s |
| 896x896 | 0.4940s ± 0.0208 | 4.9397s | 0.1262s ± 0.0159 | 1.2622s |
| 1120x1120 | 0.6888s ± 0.0081 | 6.8883s | 0.2002s ± 0.0141 | 2.0021s |
| 1344x1344 | 1.0145s ± 0.0089 | 10.1448s | 0.2703s ± 0.0136 | 2.7026s |
| 1568x1568 | 1.2620s ± 0.0133 | 12.6200s | 0.3680s ± 0.0128 | 3.6795s |
| 1792x1792 | 1.4289s ± 0.0128 | 14.2886s | 0.5968s ± 0.0160 | 5.9676s |

| size | numpy avg. time | torch avg. time | tf avg. time |
|--------|-------------------|-------------------|------------------|
| 224 | 0.0182s ± 0.0016 | 0.0180s ± 0.0390 | 0.0048s ± 0.0002 |
| 448 | 0.0880s ± 0.0224 | 0.0283s ± 0.0172 | 0.0210s ± 0.0025 |
| 672 | 0.1810s ± 0.0139 | 0.0463s ± 0.0301 | 0.0354s ± 0.0018 |
| 896 | 0.3013s ± 0.0377 | 0.0820s ± 0.0329 | 0.0713s ± 0.0008 |
| 1120 | 0.4694s ± 0.0350 | 0.1321s ± 0.0237 | 0.1036s ± 0.0042 |
| 1344 | 0.6640s ± 0.0553 | 0.1665s ± 0.0026 | 0.1663s ± 0.0021 |
| 1568 | 1.1935s ± 0.0739 | 0.2590s ± 0.0088 | 0.2531s ± 0.0031 |
| 1792 | 1.4523s ± 0.0207 | 0.3402s ± 0.0114 | 0.3080s ± 0.0188 |

## Reference

- [1] Macenko, Marc, et al. "A method for normalizing histology slides for quantitative analysis." 2009 IEEE International Symposium on Biomedical Imaging: From Nano to Macro. IEEE, 2009.
- [2] Reinhard, Erik, et al. "Color transfer between images." IEEE Computer Graphics and Applications. IEEE, 2001.

## Citing

If you find this software useful for your research, please cite it as:

```bibtex
@software{barbano2022torchstain,
author = {Carlo Alberto Barbano and
André Pedersen},
title = {EIDOSLAB/torchstain: v1.2.0-stable},
month = aug,
year = 2022,
publisher = {Zenodo},
version = {v1.2.0-stable},
doi = {10.5281/zenodo.6979540},
url = {https://doi.org/10.5281/zenodo.6979540}
}
```

Torchstain was originally developed within the [UNITOPATHO](https://github.com/EIDOSLAB/UNITOPATHO) data collection, which you can cite as:

```bibtex
@inproceedings{barbano2021unitopatho,
title={UniToPatho, a labeled histopathological dataset for colorectal polyps classification and adenoma dysplasia grading},
author={Barbano, Carlo Alberto and Perlo, Daniele and Tartaglione, Enzo and Fiandrotti, Attilio and Bertero, Luca and Cassoni, Paola and Grangetto, Marco},
booktitle={2021 IEEE International Conference on Image Processing (ICIP)},
pages={76--80},
year={2021},
organization={IEEE}
}
```
Loading