Metadata-Version: 2.4
Name: fundus_image_toolbox
Version: 0.1.3
Summary: A toolbox for fundus image analysis
Author-email: Julius Gervelmeyer <Julius.Gervelmeyer@uni-tuebingen.de>
Project-URL: repository, https://github.com/berenslab/fundus_image_toolbox
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: albumentations
Requires-Dist: captum>=0.7.0
Requires-Dist: gdown>=5.2.0
Requires-Dist: imgaug>=0.4.0
Requires-Dist: matplotlib>=3.6.2
Requires-Dist: matplotlib-inline>=0.1.6
Requires-Dist: munch>=4.0.0
Requires-Dist: numpy>=1.24.0
Requires-Dist: opencv-python-headless>=4.9.0.80
Requires-Dist: openpyxl>=3.1.2
Requires-Dist: pandas>=1.4.2
Requires-Dist: pillow>=10.2.0
Requires-Dist: pyyaml>=6.0.0
Requires-Dist: scikit-image>=0.22.0
Requires-Dist: scikit-learn>=1.1.2
Requires-Dist: scipy>=1.10.0
Requires-Dist: seaborn>=0.13.2
Requires-Dist: timm>=0.9.16
Requires-Dist: torch>=2.2.0
Requires-Dist: torchinfo>=1.8.0
Requires-Dist: torchvision>=0.15.2
Requires-Dist: tqdm>=4.66.2
Requires-Dist: segmentation_quality_control>=0.1.1
Provides-Extra: dev
Requires-Dist: pip>=25.0; extra == "dev"
Requires-Dist: tox>=4.24.1; extra == "dev"
Requires-Dist: tox-uv>=1.25.0; extra == "dev"
Requires-Dist: mypy>=0.910; extra == "dev"
Provides-Extra: notebook
Requires-Dist: ipykernel>=6.29.5; extra == "notebook"
Requires-Dist: ipython>=8.18.1; extra == "notebook"
Requires-Dist: jupyter>=1.1.1; extra == "notebook"
Requires-Dist: jupyter-black>=0.4.0; extra == "notebook"
Requires-Dist: notebook-shim>=0.2.4; extra == "notebook"
Dynamic: license-file

## Fundus Image Toolbox
[![DOI](https://joss.theoj.org/papers/10.21105/joss.07101/status.svg)](https://doi.org/10.21105/joss.07101)  <sup>&nbsp;  A Python package for fundus image processing `pytorch` `cuda` `medical imaging` `retina`</sup>
<img src="icon.svg" alt="Logo" align="right">

<!-- <p style="font-size:3em;">Fundus Image Toolbox</p> -->

<details>
<summary><b>Fundus quality prediction</b></summary>
A quality prediction model for fundus images (gradeable vs. ungradeable) based on an ensemble of 10 models (ResNets and EfficientNets) trained on DeepDRiD and DrimDB data. Can be just used for prediction or retrained. 
<br><a href="./1_read_more/Readmore_quality_prediction.md">Read more</a>. <br>

<img src="./fundus_image_toolbox/quality_prediction/ex.png" alt="Example image" width="800"/>
</details>

<details>
<summary><b>Fundus fovea and optic disc localization</b></summary>
A model to predict the center coordinates of the fovea and the optic disc in fundus images based on a multi-task EfficientNet trained on ADAM, REFUGE and IDRID datasets. Can be just used for prediction or retrained. <br><a href="./1_read_more/Readmore_fovea_od_localization.md">Read more</a>. <br>

<img src="./fundus_image_toolbox/fovea_od_localization/ex1.png" alt="Example image" width="800"/>
<br>Example predictions from the external dataset "DeepDRiD".
</details>

<details>
<summary><b>Fundus registration</b></summary>
Align a fundus photograph to another fundus photograph from the same eye using SuperRetina (<a href="https://arxiv.org/abs/2207.07932">Liu et al., 2022</a>). Image registration also goes by the terms image alignment and image matching. <br><a href="./1_read_more/Readmore_registration.md">Read more</a>. <br>

<img src="./fundus_image_toolbox/registration/image2.png" alt="Example image" width="800"/>
</details>

<details>
<summary><b>Fundus vessel segmentation</b></summary>
Segment the blood vessels in a fundus image using an ensemble of FR-U-Nets trained on the FIVES dataset (<a href="https://openreview.net/forum?id=DDHRGHfwji">Köhler et al., 2024</a>). <br><a href="./1_read_more/Readmore_vessel_segmentation.md">Read more</a>. <br>

<img src="./fundus_image_toolbox/vessel_segmentation/exs.png" alt="Example image" width="800"/>


</details>

<details>
<summary><b>Fundus circle crop</b></summary>
Fastly crop fundus images to a circle and center it (<a href="http://dx.doi.org/10.1007/978-3-030-32239-7_6">Fu et al., 2019</a>).
<br><a href="./1_read_more/Readmore_circle_crop.md">Read more</a>. <br>

<img src="./fundus_image_toolbox/circle_crop/ex.png" alt="Example image" width="500"/>
</details>

<details>
<summary><b>Fundus utilities</b></summary>
A collection of additional utilities that can come in handy when working with fundus images.<br><a href="./1_read_more/Readmore_utilities.md">Read more</a>. <br>

- ImageTorchUtils: Image manipulation based on Pytorch tensors.
- Balancing: A script to balance a torch dataset by both oversampling the minority class and undersampling the majority class from [imbalanced-dataset-sampler](https://github.com/ufoym/imbalanced-dataset-sampler/).
- Fundus transforms: A collection of torchvision data augmentation transforms to apply to fundus images adapted from [pytorch-classification](https://github.com/YijinHuang/pytorch-classification/blob/master/data/transforms.py).
- Get pixel mean std: A script to calculate the mean and standard deviation of the pixel values of a dataset by channel.
- Get efficientnet resnet: Getter for torchvision models with efficientnet and resnet architectures initialized with ImageNet weights.
- Lr scheduler: Get a pytorch learning rate scheduler (plus a warmup scheduler) for a given optimizer: OneCycleLR, CosineAnnealingLR, CosineAnnealingWarmRestarts.
- Multilevel 3-way split: Split a pandas dataframe into train, validation and test splits with the options to split by group (i.e. keep groups together) and stratify by label. Wrapper for [multi_level_split](https://github.com/lmkoch/multi-level-split/).
- Seed everything: Set seed for reproducibility in python, numpy and torch.
</details>

<!-- <br>
<p style="font-size:1.5em;"><b>Usage</b></p> -->
### Usage

The following code summarises the usage of the toolbox. See the [usage_all.ipynb](./0_example_usage/usage_all.ipynb) for a tutorial notebook and [examples directory](./0_example_usage/) for more detailed usage examples information on the respective packages.
```python
# Get sample images. All methods work on path(s) to image(s) or on image(s) as numpy arrays, tensors or PIL images.
fundus1, fundus2 = "path/to/fundus1.jpg", "path/to/fundus2.jpg"
```

```python
import fundus_image_toolbox as fit
fundus1_cropped = fit.crop(fundus1, size=512) # > np.ndarray (512, 512, 3) uint8
```

```python
import fundus_image_toolbox as fit
model, _ = fit.load_fovea_od_model(device="cuda:0")
coordinates = model.predict([fundus1, fundus2]) # > List[np.ndarray[fovea_x,fovea_y,od_x,od_y], ...]
fit.plot_coordinates([fundus1, fundus2], coordinates)
```

```python
import fundus_image_toolbox as fit
ensemble = fit.load_quality_ensemble(device="cuda:0")
confs, labels = fit.ensemble_predict_quality(
    ensemble, [fundus1, fundus2], threshold=0.5 #, img_size=512
) # > np.ndarray[conf1, conf2], np.ndarray[label1, label2]
for img, conf, label in zip([fundus1, fundus2], confs, labels):
    fit.plot_quality(img, conf, label, threshold=0.5)
```
`img_size` defaults to `512` for backward compatibility with v0.1.1. You can pass a
custom value, e.g. to avoid forced upsampling when your inputs are smaller, but note that
the model was trained at `img_size=512`. Prediction scores can shift with image size, so it is advised to keep it constant within a project.

```python
import fundus_image_toolbox as fit

config = fit.get_registration_config()
# if wanted, change the config dictionary
model, matcher = fit.load_registration_model(config)

moving_image_aligned = fit.register(
    fundus1, 
    fundus2, 
    show=True, 
    show_mapping=False, 
    config=config, 
    model=model, 
    matcher=matcher
) # > np.ndarray (h_in, w_in, 3) uint8
```

```python
import fundus_image_toolbox as fit
ensemble = fit.load_segmentation_ensemble(device=device)
vessel_masks = fit.ensemble_predict_segmentation(ensemble, [fundus1, fundus2], threshold=0.5, size=(512, 512)) # > np.ndarray[np.ndarray[h_in, w_in], ...] float64
fit.plot_masks([fundus1, fundus2], vessel_masks)
```

<!-- <br>
<p style="font-size:1.5em;"><b>Installation</b></p> -->
## Installation
<sup>Requires Python >= 3.9</sup> <br>

### From PyPI (recommended)
Install the [latest released version](https://github.com/berenslab/fundus_image_toolbox/releases) :

```bash
pip install fundus_image_toolbox
# or with Jupyter: pip install fundus_image_toolbox[notebook]
```

### From GitHub (development version)
Install the latest development version:

```bash
pip install git+https://github.com/berenslab/fundus_image_toolbox
# or with Jupyter: pip install 'git+https://github.com/berenslab/fundus_image_toolbox#egg=fundus_image_toolbox[notebook]'
```

### Development setup with `uv` (recommended)
Clone and set up a virtual environment with [`uv`](https://docs.astral.sh/uv/getting-started/installation/):

```bash
git clone https://github.com/berenslab/fundus_image_toolbox.git && cd fundus_image_toolbox
uv sync  # or `uv sync --extra notebook` with Jupyter
source .venv/bin/activate  # Windows: .venv\Scripts\activate
```

### Development setup without `uv`
Alternatively, use Python's built-in venv:

```bash
git clone https://github.com/berenslab/fundus_image_toolbox.git && cd fundus_image_toolbox
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install -e .  # or -e ".[notebook]" with Jupyter
```

### Caching
- Weights for `registration`, `fundus_od_localization`, `quality_prediction` and `vessel_segmentation` models are stored into the OS default cache dir. Set the environment variable `FIT_CACHE_DIR` to configure it, or pass the `cache_dir` argument to the respective model loading functions.
- If no `cache_dir` is passed and nothing is found in the default cache location, FIT also checks the legacy package-internal model paths for backward compatibility with versions <= 0.1.1.
- FIT models were trained on Imagenet-initialized weights. Those torch / torchvision weights will be stored in the [default pytorch cache dir](https://docs.pytorch.org/docs/stable/hub.html#where-are-my-downloaded-models-saved), configurable by setting the `TORCH_HOME` environment variable. 

### Contribute
You are very welcome to contribute to the toolbox. Please raise an [Issue](https://github.com/berenslab/fundus_image_toolbox/issues) for bugs, or create a [Pull request](https://github.com/berenslab/fundus_image_toolbox/pulls) for fixes and added features. For everything else, the [Contribution Discussion](https://github.com/berenslab/fundus_image_toolbox/discussions/26) is the right place. Please feel free to contact us there if you have any proposals, questions or need help.

<!-- <br>
<p style="font-size:1.5em;"><b>Cite</b></p> -->
### Cite

If you use this toolbox in your research, consider citing it:

Gervelmeyer et al., (2025). Fundus Image Toolbox: A Python package for fundus image processing. Journal of Open Source Software, 10(108), 7101, https://doi.org/10.21105/joss.07101

<details>
<summary>Bibtex</summary>

```bibtex
@article{Gervelmeyer2025-fit,
  title     = "Fundus Image Toolbox: A Python package for fundus image processing",
  author    = "Gervelmeyer, Julius and M{\"u}ller, Sarah and Huang, Ziwei and Berens, Philipp",
  journal   = "Journal of Open Source Software",
  publisher = "The Open Journal",
  volume    =  10,
  number    =  108,
  pages     = "7101",
  month     =  apr,
  year      =  2025,
  doi       = "https://doi.org/10.21105/joss.07101",
  }
```

</details>
<br>

If you use external parts of the toolbox that this toolbox provides an interface for, please consider citing the respective papers:
- Fundus registration: [Liu et al., 2022](https://arxiv.org/abs/2207.07932)
- Fundus vessel segmentation: [Köhler et al., 2024](https://openreview.net/forum?id=DDHRGHfwji)
- Fundus circle crop: [Fu et al., 2019](http://dx.doi.org/10.1007/978-3-030-32239-7_6)
    <!-- - [Müller et al., 2023](https://zenodo.org/records/10630386) -->
    <!-- -  -->

### OS Compatibility
<details>
<summary>v0.1.3</summary>

<table>
  <thead>
    <tr>
      <th>Python Version</th>
      <th>Linux <br><sup>Rocky 8.8, Kernel 4.18</sup></th>
      <th>macOS <br><sup>Sequoia 15.7</sup></th>
      <th>Windows <br><sup>11 Pro</sup></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td align="center">3.9</td>
      <td align="center">✅</td>
      <td align="center">✅</td>
      <td align="center">✅</td>
    </tr>
    <tr>
      <td align="center">3.10</td>
      <td align="center">✅</td>
      <td align="center">✅</td>
      <td align="center">❓</td>
    </tr>
    <tr>
      <td align="center">3.11</td>
      <td align="center">✅</td>
      <td align="center">✅</td>
      <td align="center">❓</td>
    </tr>
    <tr>
      <td align="center">3.12</td>
      <td align="center">✅</td>
      <td align="center">✅</td>
      <td align="center">✅</td>
    </tr>
  </tbody>
</table>

<sub>✅ Supported & all tests successful &nbsp; 🔸 Partly supported: [sample notebooks]((./0_example_usage/)) succeed but automatic tests fail partly &nbsp; ❓ Untested/unknown &nbsp; ❌ Not supported</sub>
</details>

<details>
<summary>v0.1.2</summary>

<table>
  <thead>
    <tr>
      <th>Python Version</th>
      <th>Linux <br><sup>Rocky 8.8, Kernel 4.18</sup></th>
      <th>macOS <br><sup>Sequoia 15.7</sup></th>
      <th>Windows <br><sup>11 Pro</sup></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td align="center">3.9</td>
      <td align="center">✅</td>
      <td align="center">✅</td>
      <td align="center">❓</td>
    </tr>
    <tr>
      <td align="center">3.10</td>
      <td align="center">✅</td>
      <td align="center">✅</td>
      <td align="center">❓</td>
    </tr>
    <tr>
      <td align="center">3.11</td>
      <td align="center">✅</td>
      <td align="center">✅</td>
      <td align="center">❓</td>
    </tr>
    <tr>
      <td align="center">3.12</td>
      <td align="center">✅</td>
      <td align="center">✅</td>
      <td align="center">✅</td>
    </tr>
  </tbody>
</table>

<sub>✅ Supported & all tests successful &nbsp; 🔸 Partly supported: [sample notebooks]((./0_example_usage/)) succeed but automatic tests fail partly &nbsp; ❓ Untested/unknown &nbsp; ❌ Not supported</sub>
</details>

<details>
<summary>v0.1.1</summary>

<table>
  <thead>
    <tr>
      <th>Python Version</th>
      <th>Linux <br><sup>Rocky 8.8, Kernel 4.18</sup></th>
      <th>macOS <br><sup>Sequoia 15.7</sup></th>
      <th>Windows <br><sup>11 Pro</sup></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td align="center">3.9</td>
      <td align="center">✅</td>
      <td align="center">❓</td>
      <td align="center">✅</td>
    </tr>
    <tr>
      <td align="center">3.10</td>
      <td align="center">❓</td>
      <td align="center">❓</td>
      <td align="center">❓</td>
    </tr>
    <tr>
      <td align="center">3.11</td>
      <td align="center">❓</td>
      <td align="center">❓</td>
      <td align="center">❓</td>
    </tr>
    <tr>
      <td align="center">3.12</td>
      <td align="center">❓</td>
      <td align="center">❓</td>
      <td align="center">❓</td>
    </tr>
  </tbody>
</table>

<sub>✅ Supported & all tests successful &nbsp; 🔸 Partly supported: [sample notebooks]((./0_example_usage/)) succeed but automatic tests fail partly &nbsp; ❓ Untested/unknown &nbsp; ❌ Not supported</sub>
</details>



### License

The toolbox is licensed under the MIT License. See the [license file](./LICENSE) for more information.


