# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['histolab', 'histolab.data', 'histolab.filters']

package_data = \
{'': ['*']}

install_requires = \
['Pillow>=9.1.0,<10.0.0',
 'importlib-metadata>=4.12,<7.0',
 'numpy>=1.18.4,<1.23.1',
 'openslide-python>=1.1.2,<1.2.1',
 'scikit-image>=0.19.0,<0.19.4',
 'scipy>=1.5.0,<1.8.2',
 'typing-extensions>=4.0.0,<5.0.0']

extras_require = \
{'docs': ['Sphinx>=5.1.1,<6.0.0',
          'sphinx-rtd-theme>=1.0.0,<2.0.0',
          'sphinxcontrib-katex>=0.8.6,<0.10.0',
          'sphinxemoji>=0.2.0,<0.3.0',
          'sphinx-prompt>=1.5.0,<2.0.0']}

setup_kwargs = {
    'name': 'histolab',
    'version': '0.6.0',
    'description': 'Python library for Digital Pathology Image Processing',
    'long_description': '<img width="390" alt="histolab" src="https://user-images.githubusercontent.com/4196091/164645273-3d256916-1d5b-46fd-94fd-04358bb0db97.png">\n\n\n![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.png?v=103)\n\n<table>\n<tr>\n    <td>Test Status</td>\n    <td>\n        <img src="https://github.com/histolab/histolab/workflows/CI/badge.svg?branch=master">\n        <a href="https://codecov.io/gh/histolab/histolab">\n            <img src="https://codecov.io/gh/histolab/histolab/branch/master/graph/badge.svg?token=PL3VIM1PGL"/>\n        </a>\n    </td>\n</tr>\n<tr>\n    <td>Code Quality</td>\n    <td>\n        <img src="https://github.com/histolab/histolab/actions/workflows/codeql.yml/badge.svg?branch=master&event=push">\n        <a href="https://www.codefactor.io/repository/github/histolab/histolab" target="_blank"><img src="https://www.codefactor.io/repository/github/histolab/histolab/badge"></a>\n        <a href="https://github.com/psf/black" target="_blank"><img src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>\n        <a href="https://github.com/PyCQA/bandit" target="_blank"><img src="https://img.shields.io/badge/security-bandit-yellow.svg"></a>\n</tr>\n<tr>\n    <td>Version Info</td>\n    <td>\n        <a href="https://pypi.org/project/histolab/" target="_blank"><img src="https://img.shields.io/pypi/v/histolab"></a>\n        <a href="https://anaconda.org/conda-forge/histolab"><img src="https://anaconda.org/conda-forge/histolab/badges/version.svg" /></a>\n        <img src="https://img.shields.io/pypi/pyversions/histolab">\n        <img src="https://img.shields.io/pypi/wheel/histolab">\n    </td>\n</tr>\n<tr>\n    <td>License</td>\n    <td>\n        <a href=https://github.com/histolab/histolab/blob/master/LICENSE.txt" target="_blank"><img src="https://img.shields.io/github/license/histolab/histolab"></a>\n    </td>\n</tr>\n<tr>\n    <td>Documentation</td>\n    <td><a href="https://histolab.readthedocs.io/en/latest/" target="_blank"><img src="https://readthedocs.org/projects/histolab/badge/?version=latest"></a>\n</td>\n</tr>\n</table>\n\n\n**Compatibility Details**\n\n| Operating System  | Python version  |\n|-------------------|-----------------|\n|  Linux            | <img src=https://img.shields.io/badge/-3.7%20%7C%203.8%20%7C%203.9%20%7C%203.10-blue>|\n|  MacOs            | <img src=https://img.shields.io/badge/-3.7%20%7C%203.8%20%7C%203.9%20%7C%203.10-blue>|\n|  Windows          | <img src=https://img.shields.io/badge/-3.7%20-blue>|\n\n---\n\n## Table of Contents\n\n- [Motivation](#motivation)\n- [Quickstart](#quickstart)\n  - [TCGA data](#tcga-data)\n  - [Slide initialization](#slide-initialization)\n  - [Tile extraction](#tile-extraction)\n    - [Random Extraction](#random-extraction)\n    - [Grid Extraction](#grid-extraction)\n    - [Score-based extraction](#score-based-extraction)\n  - [Versioning](#versioning)\n  - [Authors](#authors)\n  - [License](#license)\n  - [Roadmap](#roadmap)\n  - [Acknowledgements](#acknowledgements)\n  - [References](#references)\n  - [Contribution guidelines](#contribution-guidelines)\n\n\n## Motivation\nThe histo-pathological analysis of tissue sections is the gold standard to assess the presence of many complex diseases, such as tumors, and understand their nature.\nIn daily practice, pathologists usually perform microscopy examination of tissue slides considering a limited number of regions and the clinical evaluation relies on several factors such as nuclei morphology, cell distribution, and color (staining): this process is time consuming, could lead to information loss, and suffers from inter-observer variability.\n\nThe advent of digital pathology is changing the way pathologists work and collaborate, and has opened the way to a new era in computational pathology. In particular, histopathology is expected to be at the center of the AI revolution in medicine [1], prevision supported by the increasing success of deep learning applications to digital pathology.\n\nWhole Slide Images (WSIs), namely the translation of tissue slides from glass to digital format, are a great source of information from both a medical and a computational point of view. WSIs can be coloured with different staining techniques (e.g. H&E or IHC), and are usually very large in size (up to several GB per slide). Because of WSIs typical pyramidal structure, images can be retrieved at different magnification factors, providing a further layer of information beyond color.\n\nHowever, processing WSIs is far from being trivial. First of all, WSIs can be stored in different proprietary formats, according to the scanner used to digitalize the slides, and a standard protocol is still missing. WSIs can also present artifacts, such as shadows, mold, or annotations (pen marks) that are not useful. Moreover, giving their dimensions, it is not possible to process a WSI all at once, or, for example, to feed a neural network: it is necessary to crop smaller regions of tissues (tiles), which in turns require a tissue detection step.\n\nThe aim of this project is to provide a tool for WSI processing in a reproducible environment to support clinical and scientific research. histolab is designed to handle WSIs, automatically detect the tissue, and retrieve informative tiles, and it can thus be integrated in a deep learning pipeline.\n\n## Getting Started\n\n### Prerequisites\n\nPlease see [installation instructions](https://github.com/histolab/histolab/blob/master/docs/installation.rst).\n\n### Documentation\n\nRead the full documentation here https://histolab.readthedocs.io/en/latest/.\n\n### Communication\n\nJoin our user group on <img src=https://user-images.githubusercontent.com/4196091/101638148-01522780-3a2e-11eb-8502-f718564ffd43.png> [Slack](https://communityinviter.com/apps/histolab/histolab)\n\n### 5 minutes introduction\n\n<a href="https://youtu.be/AdR4JK-Eq60" target="_blank"><img src=https://user-images.githubusercontent.com/4196091/105097293-a68a0200-5aa8-11eb-8327-6039940fbdca.png></a>\n\n\n# Quickstart\nHere we present a step-by-step tutorial on the use of `histolab` to\nextract a tile dataset from example WSIs. The corresponding Jupyter\nNotebook is available at <https://github.com/histolab/histolab-box>:\nthis repository contains a complete `histolab` environment that can be\nused through [Docker](http://www.docker.com) on all platforms.\n\nThus, the user can decide either to use `histolab` through\n`histolab-box` or installing it in his/her python virtual environment\n(using conda, pipenv, pyenv, virtualenv, etc...). In the latter case, as\nthe `histolab` package has been published on ([PyPi](http://www.pypi.org)),\nit can be easily installed via the command:\n\n```\npip install histolab\n```\n\nalternatively, it can be installed via conda:\n\n```\nconda install -c conda-forge histolab\n```\n\n## TCGA data\n\nFirst things first, let’s import some data to work with, for example the\nprostate tissue slide and the ovarian tissue slide available in the\n`data` module:\n\n```python\nfrom histolab.data import prostate_tissue, ovarian_tissue\n```\n\n**Note:** To use the `data` module, you need to install `pooch`, also\navailable on PyPI (<https://pypi.org/project/pooch/>). This step is\nneedless if we are using the Vagrant/Docker virtual environment.\n\nThe calling to a `data` function will automatically download the WSI\nfrom the corresponding repository and save the slide in a cached\ndirectory:\n\n```python\nprostate_svs, prostate_path = prostate_tissue()\novarian_svs, ovarian_path = ovarian_tissue()\n```\n\nNotice that each `data` function outputs the corresponding slide, as an\nOpenSlide object, and the path where the slide has been saved.\n\n## Slide initialization\n\n`histolab` maps a WSI file into a `Slide` object. Each usage of a WSI\nrequires a 1-o-1 association with a `Slide` object contained in the\n`slide` module:\n\n```python\nfrom histolab.slide import Slide\n```\n\nTo initialize a Slide it is necessary to specify the WSI path, and the\n`processed_path` where the tiles will be saved. In our\nexample, we want the `processed_path` of each slide to be a subfolder of\nthe current working directory:\n\n```python\nimport os\n\nBASE_PATH = os.getcwd()\n\nPROCESS_PATH_PROSTATE = os.path.join(BASE_PATH, \'prostate\', \'processed\')\nPROCESS_PATH_OVARIAN = os.path.join(BASE_PATH, \'ovarian\', \'processed\')\n\nprostate_slide = Slide(prostate_path, processed_path=PROCESS_PATH_PROSTATE)\novarian_slide = Slide(ovarian_path, processed_path=PROCESS_PATH_OVARIAN)\n```\n\n**Note:** If the slides were stored in the same folder, this can be done\ndirectly on the whole dataset by using the `SlideSet` object of the\n`slide` module.\n\nWith a `Slide` object we can easily retrieve information about the\nslide, such as the slide name, the number of available levels, the\ndimensions at native magnification or at a specified level:\n\n```python\nprint(f"Slide name: {prostate_slide.name}")\nprint(f"Levels: {prostate_slide.levels}")\nprint(f"Dimensions at level 0: {prostate_slide.dimensions}")\nprint(f"Dimensions at level 1: {prostate_slide.level_dimensions(level=1)}")\nprint(f"Dimensions at level 2: {prostate_slide.level_dimensions(level=2)}")\n```\n\n```\nSlide name: 6b725022-f1d5-4672-8c6c-de8140345210\nLevels: [0, 1, 2]\nDimensions at level 0: (16000, 15316)\nDimensions at level 1: (4000, 3829)\nDimensions at level 2: (2000, 1914)\n```\n\n```python\nprint(f"Slide name: {ovarian_slide.name}")\nprint(f"Levels: {ovarian_slide.levels}")\nprint(f"Dimensions at level 0: {ovarian_slide.dimensions}")\nprint(f"Dimensions at level 1: {ovarian_slide.level_dimensions(level=1)}")\nprint(f"Dimensions at level 2: {ovarian_slide.level_dimensions(level=2)}")\n```\n\n```\nSlide name: b777ec99-2811-4aa4-9568-13f68e380c86\nLevels: [0, 1, 2]\nDimensions at level 0: (30001, 33987)\nDimensions at level 1: (7500, 8496)\nDimensions at level 2: (1875, 2124)\n```\n\n**Note:**\n    If the native magnification, *i.e.*, the magnification factor used to scan the slide, is provided in the slide properties, it is also possible\n    to convert the desired level to its corresponding magnification factor with the ``level_magnification_factor`` property.\n\n```python\n   print(\n        "Native magnification factor:",\n        prostate_slide.level_magnification_factor()\n    )\n\n    print(\n        "Magnification factor corresponding to level 1:",\n        prostate_slide.level_magnification_factor(level=1),\n    )\n```\n```\n    Native magnification factor: 20X\n    Magnification factor corresponding to level 1: 5.0X\n```\nMoreover, we can retrieve or show the slide thumbnail in a separate window:\n\n```python\nprostate_slide.thumbnail\nprostate_slide.show()\n```\n\n![](https://user-images.githubusercontent.com/4196091/92748324-5033e680-f385-11ea-812b-6a9a225ceca4.png)\n\n```python\novarian_slide.thumbnail\novarian_slide.show()\n```\n\n![](https://user-images.githubusercontent.com/4196091/92748248-3db9ad00-f385-11ea-846b-a5ce8cf3ca09.png)\n\n## Tile extraction\n\nOnce that the `Slide` objects are defined, we can proceed to extract the\ntiles. To speed up the extraction process, `histolab` automatically\ndetects the tissue region with the largest connected area and crops the\ntiles within this field. The `tiler` module implements different\nstrategies for the tiles extraction and provides an intuitive interface\nto easily retrieve a tile dataset suitable for our task. In particular,\neach extraction method is customizable with several common parameters:\n\n-   `tile_size`: the tile size;\n-   `level`: the extraction level (from 0 to the number of available\n    levels);\n-   `check_tissue`: if a minimum percentage of tissue is required to\n    save the tiles;\n-  `tissue_percent`: number between 0.0 and 100.0 representing the\n    minimum required percentage of tissue over the total area of the image\n    (default is 80.0);\n-   `prefix`: a prefix to be added at the beginning of the tiles’\n    filename (default is the empty string);\n-   `suffix`: a suffix to be added to the end of the tiles’ filename\n    (default is `.png`).\n\n### Random Extraction\n\nThe simplest approach we may adopt is to randomly crop a fixed number of\ntiles from our slides; in this case, we need the `RandomTiler`\nextractor:\n\n```python\nfrom histolab.tiler import RandomTiler\n```\n\nLet us suppose that we want to randomly extract 30 squared tiles at level\n2 of size 128 from our prostate slide, and that we want to save them only\nif they have at least 80% of tissue inside. We then initialize our\n`RandomTiler` extractor as follows:\n\n```python\nrandom_tiles_extractor = RandomTiler(\n    tile_size=(128, 128),\n    n_tiles=30,\n    level=2,\n    seed=42,\n    check_tissue=True, # default\n    tissue_percent=80.0, # default\n    prefix="random/", # save tiles in the "random" subdirectory of slide\'s processed_path\n    suffix=".png" # default\n)\n```\n\nNotice that we also specify the random seed to ensure the\nreproducibility of the extraction process.\n\nWe may want to check which tiles have been selected by the tiler, before starting the extraction procedure and saving them;\nthe ``locate_tiles`` method of ``RandomTiler`` returns a scaled version of the slide with the corresponding tiles outlined. It is also possible to specify\nthe transparency of the background slide, and the color used for the border of each tile:\n\n```python\nrandom_tiles_extractor.locate_tiles(\n    slide=prostate_slide,\n    scale_factor=24,  # default\n    alpha=128,  # default\n    outline="red",  # default\n)\n```\n\n![](https://user-images.githubusercontent.com/31658006/104055082-6bf1b100-51ee-11eb-8353-1f5958d521d8.png)\n\nStarting the extraction is then as simple as calling the `extract` method on the extractor, passing the\nslide as parameter:\n\n```python\nrandom_tiles_extractor.extract(prostate_slide)\n```\n\n![](https://user-images.githubusercontent.com/31658006/104056327-9ba1b880-51f0-11eb-9a06-7f04ba2bb1dc.jpeg)\n\nRandom tiles extracted from the prostate slide at level 2.\n\n### Grid Extraction\n\nInstead of picking tiles at random, we may want to retrieve all the\ntiles available. The Grid Tiler extractor crops the tiles following a grid\nstructure on the largest tissue region detected in the WSI:\n\n```python\nfrom histolab.tiler import GridTiler\n```\n\nIn our example, we want to extract squared tiles at level 0 of size 512\nfrom our ovarian slide, independently of the amount of tissue detected.\nBy default, tiles will not overlap, namely the parameter defining the\nnumber of overlapping pixels between two adjacent tiles,\n`pixel_overlap`, is set to zero:\n\n```python\ngrid_tiles_extractor = GridTiler(\n   tile_size=(512, 512),\n   level=0,\n   check_tissue=False,\n   pixel_overlap=0, # default\n   prefix="grid/", # save tiles in the "grid" subdirectory of slide\'s processed_path\n   suffix=".png" # default\n)\n```\n\nAgain, we can exploit the ``locate_tiles`` method to visualize the selected tiles on a scaled version of the slide:\n\n```python\ngrid_tiles_extractor.locate_tiles(\n    slide=ovarian_slide,\n    scale_factor=64,\n    alpha=64,\n    outline="#046C4C",\n)\n```\n\n![](https://user-images.githubusercontent.com/31658006/104107093-37e3c200-52ba-11eb-8750-67a62bf62ca5.png)\n\n```python\ngrid_tiles_extractor.extract(ovarian_slide)\n```\n\nand the extraction process starts when the extract method is called\non our extractor:\n\n![](https://user-images.githubusercontent.com/4196091/92751173-0993bb80-f388-11ea-9d30-a6cd17769d76.png)\n\nExamples of non-overlapping grid tiles extracted from the ovarian slide\nat level 0.\n\n### Score-based extraction\n\nDepending on the task we will use our tile dataset for, the extracted\ntiles may not be equally informative. The `ScoreTiler` allows us to save\nonly the "best" tiles, among all the ones extracted with a grid\nstructure, based on a specific scoring function. For example, let us\nsuppose that our goal is the detection of mitotic activity on our\novarian slide. In this case, tiles with a higher presence of nuclei are\npreferable over tiles with few or no nuclei. We can leverage the\n`NucleiScorer` function of the `scorer` module to order the extracted\ntiles based on the proportion of the tissue and of the hematoxylin\nstaining. In particular, the score is computed as ![formula](https://render.githubusercontent.com/render/math?math=N_t\\cdot\\mathrm{tanh}(T_t)) where ![formula](https://render.githubusercontent.com/render/math?math=N_t) is the percentage of nuclei and  ![formula](https://render.githubusercontent.com/render/math?math=T_t) the percentage of tissue in the tile *t*\n\nFirst, we need the extractor and the scorer:\n\n```python\nfrom histolab.tiler import ScoreTiler\nfrom histolab.scorer import NucleiScorer\n```\n\nAs the `ScoreTiler` extends the `GridTiler` extractor, we also set the\n`pixel_overlap` as additional parameter. Moreover, we can specify the\nnumber of the top tiles we want to save with the `n_tile` parameter:\n\n```python\nscored_tiles_extractor = ScoreTiler(\n    scorer = NucleiScorer(),\n    tile_size=(512, 512),\n    n_tiles=100,\n    level=0,\n    check_tissue=True,\n    tissue_percent=80.0,\n    pixel_overlap=0, # default\n    prefix="scored/", # save tiles in the "scored" subdirectory of slide\'s processed_path\n    suffix=".png" # default\n)\n```\n\nNotice that also the ``ScoreTiler`` implements the ``locate_tiles`` method, which visualizes (on a scaled version of the slide) the first ``n_tiles`` with the highest scores:\n\n```python\ngrid_tiles_extractor.locate_tiles(slide=ovarian_slide)\n```\n\n![](https://user-images.githubusercontent.com/31658006/104172715-fc094380-5404-11eb-942a-4130b5cdb037.png)\n\nFinally, when we extract our cropped images, we can also write a report\nof the saved tiles and their scores in a CSV file:\n\n```python\nsummary_filename = "summary_ovarian_tiles.csv"\nSUMMARY_PATH = os.path.join(ovarian_slide.processed_path, summary_filename)\n\nscored_tiles_extractor.extract(ovarian_slide, report_path=SUMMARY_PATH)\n```\n\n<img src="https://user-images.githubusercontent.com/4196091/92751801-9d658780-f388-11ea-8132-5d0c82bb112b.png" width=500>\n\nRepresentation of the score assigned to each extracted tile by the\n`NucleiScorer`, based on the amount of nuclei detected.\n\n## Versioning\n\nWe use [PEP 440](https://www.python.org/dev/peps/pep-0440/) for versioning.\n\n## Authors\n\n* **[Alessia Marcolini](https://github.com/alessiamarcolini)**\n* **[Ernesto Arbitrio](https://github.com/ernestoarbitrio)**\n* **[Nicole Bussola](https://gitlab.fbk.eu/bussola)**\n\n\n## License\n\nThis project is licensed under `Apache License  Version 2.0` - see the [LICENSE.txt](https://github.com/histolab/histolab/blob/master/LICENSE.txt) file for details\n\n## Roadmap\n\n[Open issues](https://github.com/histolab/histolab/issues)\n\n## Acknowledgements\n\n* [https://github.com/deroneriksson](https://github.com/deroneriksson)\n\n## References\n[1] Colling, Richard, et al. "Artificial intelligence in digital pathology: A roadmap to routine use in clinical practice." The Journal of pathology 249.2 (2019)\n\n## Contribution guidelines\nIf you want to contribute to histolab, be sure to review the [contribution guidelines](CONTRIBUTING.md)\n',
    'author': 'E. Arbitrio, N. Bussola, A. Marcolini',
    'author_email': 'None',
    'maintainer': 'Ernesto Arbitrio',
    'maintainer_email': 'ernesto.arbitrio@gmail.com',
    'url': 'https://github.com/histolab/histolab',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'extras_require': extras_require,
    'python_requires': '>=3.7,<3.11',
}


setup(**setup_kwargs)
