Metadata-Version: 2.5
Name: tsmist
Version: 1.0.0
Summary: A Python Command Line Interface (CLI) application and package to run the Merging Instance Segmentation Tiler (MIST) with ML computer vision models
Project-URL: Homepage, https://github.com/Theia-Scientific/mist
Project-URL: Source, https://github.com/Theia-Scientific/mist
Project-URL: Tracker, https://github.com/Theia-Scientific/mist/issues
Author-email: Christopher Field <chris.field@theiascientific.com>
License-File: LICENSE
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Environment :: GPU
Classifier: Framework :: Pydantic
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Image Recognition
Requires-Python: >=3.11
Requires-Dist: numpy
Requires-Dist: opencv-python-headless
Requires-Dist: pydantic
Requires-Dist: supervision>=0.30
Provides-Extra: cli
Requires-Dist: imagecodecs; extra == 'cli'
Requires-Dist: natsort; extra == 'cli'
Requires-Dist: tifffile; extra == 'cli'
Requires-Dist: typer; extra == 'cli'
Requires-Dist: ultralytics-opencv-headless; extra == 'cli'
Provides-Extra: dev
Requires-Dist: black; extra == 'dev'
Requires-Dist: build; extra == 'dev'
Requires-Dist: flake8; extra == 'dev'
Requires-Dist: hatch; extra == 'dev'
Requires-Dist: imagecodecs; extra == 'dev'
Requires-Dist: isort; extra == 'dev'
Requires-Dist: natsort; extra == 'dev'
Requires-Dist: pytest; extra == 'dev'
Requires-Dist: pytest-cov; extra == 'dev'
Requires-Dist: pytest-mock; extra == 'dev'
Requires-Dist: tifffile; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Requires-Dist: typer; extra == 'dev'
Requires-Dist: ultralytics-opencv-headless; extra == 'dev'
Description-Content-Type: text/markdown

# MIST: Merging Instance Segmentation Tiler

[![CI](https://github.com/Theia-Scientific/mist/actions/workflows/ci.yml/badge.svg)](https://github.com/Theia-Scientific/mist/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/Theia-Scientific/MIST/graph/badge.svg?token=jQlaknKYBC)](https://codecov.io/gh/Theia-Scientific/MIST)
![PyPI Version](https://img.shields.io/pypi/v/tsmist)
![GitHub Release](https://img.shields.io/github/v/release/Theia-Scientific/mist)

A Command Line Interface (CLI) application and Python package for running the
Merging Instance Segmentation Tiler (MIST) with Machine Learning (ML) computer
vision models. MIST creates tiles from a large image, runs inference on each
tile, and combines, or merges, instances of the same class together using the
instance segmentation results from inference. Non-maximum suppression (NMS) is
_not_ used to determine overlap. Instead, each instance of a class is logically
"anded" into a binary mask. The individual instances within a class are
identified as contours through OpenCV's connectivity algorithm. In this manner,
large instances that span multiple tiles are combined, or merged, into a single
instance and small instances within the overlap region between two or more tiles
are automatically filtered and reduced to a single instance. Only a single
"pass" per class is required.

MIST is inspired by the [Slicing Aided Hyper Inference] (SAHI), [YOLO
Patch-Based Inference] (YPBI), and [dask_relabeling] packages. The SAHI tiler
does not merge large instances spanning multiple tiles and uses NMS for
instance reduction in overlap regions. The YPBI tiler does instance
segmentations but does not merge large instances, and it performs multiple NMS
iterations for both bounding boxes and segmentations. The `dask_relabeling`
package does instance segmentations and merging large instances, but it does not
work with YOLO models and GPU-powered inference.

1. [Prerequisites](#prerequisites)
   1. [Python](#prerequisites-python)
      1. [Ubuntu](#prerequisites-python-ubuntu)
      2. [macOS](#prerequisites-python-macos)
   2. [pipx](#prerequisites-pipx)
      1. [Ubuntu](#prerequisites-pipx-ubuntu)
      2. [macOS](#prerequisites-pipx-macos)
2. [Installation](#installation)
   1. [pipx](#installation-pipx) (recommended)
   2. [Source](#installation-source)
3. [Upgrade](#upgrade)
   1. [pipx](#upgrade-pipx)
   2. [Source](#upgrade-source)
4. [Usage](#usage)
   1. [Terminal](#usage-terminal)
   2. [Python](#usage-python)
5. [Contributing](#contributing)
6. [License](#license)

## Prerequisites

All of the prerequisites may already be installed and configured by the
superuser, a.k.a. root, of the computer. The prerequisites only need to be
installed and configured once per machine.

### Python

<a name="prerequisites-python"></a>

The [Python] programming language is needed to run the `mist` Command Line
Interface (CLI) application and/or use the `mist` package in other Python
scripts or [Jupyter] notebooks. Both macOS and Linux have the Python programming
language installed, but it is generally reserved for the operating system (OS)
to use and is an older version. It is best practice to install a newer version
that is separate from the system-provided Python version.

#### Ubuntu

<a name="prerequisites-python-ubuntu"></a>

MIST was developed and tested on Ubuntu 22.04 Linux. The following steps are for
Ubuntu Linux, but any Linux distribution can be used. The commands will be
similar but different for other Linux distributions.

1. Add the "[deadsnakes]" Ubuntu Personal Package Archives (PPA).

    ```sh
    sudo add-apt-repository ppa:deadsnakes/ppa
    ```
    
2. Obtain the latest packages from the PPA.

   ```sh
   sudo apt update
   ```
   
3. Install Python v3.11 or newer.

   ```sh
   sudo apt install -y python3.11
   ```
   
4. Install the `venv` package.

   ```sh
   sudo apt install -y python3.11-venv
   ```
   
#### macOS

<a name="prerequisites-python-macos"></a>

MIST has been deployed and tested on a Macbook Pro laptop with a M3 Apple
Silicon processor.

1. Install [Homebrew] if it is not already installed.

   ```sh
   /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
   ```
   
2. Install Python v3.11 or newer.

   ```sh
   brew install python@3.11
   ```

### pipx

<a name="prerequisites-pipx"></a>

The [pipx] utility enables distribution of Python-based CLI applications, like
`mist`, to be installed for all users with all of the appropriate dependencies
within an isolated environment. It is the recommended installation for the
`mist` application.

#### Ubuntu

<a name="prerequisites-pipx-ubuntu"></a>

1. Create a virtual environment for `pipx` and Python v3.11 or newer.

   ```sh
   sudo python3.11 -m venv --upgrade-deps /opt/pipx
   ```
   
2. Install `pipx` for all users.

   ```sh
   sudo /opt/pipx/bin/pip install pipx
   ```
   
3. Ensure the `pipx` command is available to all users.

   ```sh
   sudo ln -s /opt/pipx/bin/pipx /usr/local/bin/pipx
   ```

4. Add `pipx` to the `PATH` environment variable.

   ```sh
   pipx ensurepath
   ```
   
5. Add `pipx` for all users.

   ```sh
   sudo pipx ensurepath --global
   ```
   
Post-installation, the `pipx` application can be upgraded with the following
command:

```sh
sudo /opt/pipx/bin/pip install --upgrade pipx
```

#### macOS

<a name="prerequisites-pipx-macos"></a>

1. Install `pipx` using [Homebrew].

   ```sh
   brew install pipx
   ```
   
2. Add `pipx` to the `PATH` environment variable.

   ```sh
   pipx ensurepath
   ```
   
3. Add `pipx` for all users.

   ```sh
   sudo pipx ensurepath --global
   ```
   
Post-installation, the `pipx` application can be upgraded with the following
command:

``` sh
brew update && brew upgrade pipx
```
  
## Installation

### pipx (recommended)

<a name="installation-pipx"></a>

1. Ensure `pipx` is installed. See the [Prerequisites](#prerequisites).

   ```sh
   $ pipx --version
   1.7.1
   ```
   
2. Install `mist` command globally for all users.

   ```sh
   sudo pipx install --global --python python3.11 "tsmist[cli]"
   ```
   
3. Verify `mist` command is available.

   ```sh
   $ mist --version
   mist 0.1.0
   ```
   
### Source

<a name="installation-source"></a>

1. Clone this repository.

   ```sh
   git clone https://github.com/Theia-Scientific/mist.git && cd mist
   ```

2. Create a virtual environment.

   ```sh
   python3 -m venv .venv
   ```

3. Activate the virtual environment.

   ```sh
   source .venv/bin/activate
   ```
   
   or if [direnv] is installed:
   
   ```sh
   cp .envrc.example .envrc
   ```
   
   followed by:
   
   ```sh
   direnv allow
   ```

4. Upgrade `pip` to the latest version.

   ```sh
   python3 -m pip install --upgrade pip
   ```

5. Locally install the package, utility, and its dependencies. This will create
   the `mist` command within the virtual environment. 

   ```sh
   python3 -m pip install -e ".[cli]"
   ```

## Upgrade

### pipx (recommended)

<a name="upgrade-pipx"></a>

1. Upgrade the `mist` application via `pipx`.

   ```sh
   sudo pipx install --global --python python3.11 --force tsmist
   ```
   
2. Verify new version.

   ```sh
   $ mist --version
   mist 0.1.0
   ```
   
### Source

<a name="upgrade-source"></a>

1. Navigate to the root of the source tree.

   ```sh
   cd ~/Code/mist
   ```

2. Activate the virtual environment.

   ```sh
   source .venv/bin/activate
   ```
   
   or if [direnv] is installed, the virtual environment will automatically be
   activated.
   
3. Pull the latest changes on `main`.

   ```sh
   git pull
   ```
   
4. Upgrade the `mist` application within the virtual environment.

   ```sh
   python -m pip install --upgrade -e .
   ```

5. Verify new version.

   ```sh
   $ mist --version
   mist 0.1.0
   ```

## Usage

### Terminal

<a name="usage-terminal"></a>

Using the Ultralytics YOLOv8 model:

```sh
mist yolov8n-seg.pt example1.jpg example2.jpg /path/to/images/dir
```

For running on macOS:

```sh
mist --device=mps yolov8n-seg.pt example1.jpg example2.jpg /path/to/images/dir
```

### Python

<a name="usage-python"></a>

Using an Ultralytics YOLO segmentation model and defaults.

```python
import numpy as np
import numpy.typing as npt
import supervision as sv

from mist import detecting
from pathlib import Path
from ultralytics.models import YOLO

model = YOLO("yolo26n-seg.pt")


def predict(image: npt.NDArray[np.uint8]) -> sv.Detections:
    return sv.Detections.from_ultralytics(
        list(
            model(
                image,
                agnostic_nms=False,
                device="cuda:0",
                classes=None,
                conf=0.35,
                imgsz=640,
                iou=0.7,
                max_det=1000,
                retina_masks=True,
                verbose=False
            )
        )[0]
    )


result = detecting.run(
    np.zeros((3, 4096, 4096), dtype=np.uint8),
    predict,
    class_names=[name for _, name in sorted(model.names.items())],
)
print(results)
```

Using a custom model.

```python
import numpy as np
import numpy.typing as npt
import supervision as sv

from mist import detecting
from pathlib import Path

model = CustomModel(weights_file)


def predict(image: npt.NDArray[np.uint8]) -> sv.Detections:
    return sv.Detections.from_inference(model(image))


results = detecting.run(
    np.zeros((3, 4096, 4096), dtype=np.uint8),
    predict,
    class_names=["object"]
)
print(results)
```

## Contributing

1. Clone this repository.

   ```sh
   git clone https://github.com/Theia-Scientific/mist.git && cd mist
   ```

2. Create a virtual environment.

   ```sh
   python3 -m venv .venv
   ```

3. Activate the virtual environment.

   ```sh
   source .venv/bin/activate
   ```

   or if [direnv] is installed:
   
   ```sh
   cp .envrc.example .envrc
   ```
   
   followed by:
   
   ```sh
   direnv allow
   ```

4. Install the package, utility, the required dependencies, and the development
   dependencies.

   ```sh
   pip install -e ".[cli,dev]"
   ```

5. Create a local branch.

   ```sh
   git checkout -b feature-awesome-new-feature
   ```

6. Modify the code.
7. Run the tests.

   ```sh
   pytest --color=yes
   ```

8. Commit changes to your local branch.

   ```sh
   git add -A && git commit -m "Add new feature"
   ```

9. Push your local branch to GitHub to create a Pull Request (PR).

   ```sh
   git push origin feature-awesome-new-feature
   ```

10. Create a Pull Request (PR) in GitHub.
11. Wait for CI to complete.
12. Add comment to PR that it is ready to review.

## License

- [LICENSE](https://github.com/Theia-Scientific/mist/blob/main/LICENSE).

## Acknowledgments

This material is based upon work supported by the U.S. Department of Energy,
Office of Science and Office of Nuclear Energy under Awards: DE-SC0021529 and
DE-SC0021936, respectively.

[dask_relabeling]: https://github.com/TheJacksonLaboratory/dask_relabeling
[deadsnakes]: https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa
[direnv]: https://direnv.net/
[homebrew]: https://brew.sh/
[jupyter]: https://jupyter.org/
[pipx]: https://pipx.pypa.io/stable/
[python]: https://www.python.org
[slicing aided hyper inference]: https://github.com/obss/sahi
[yolo patch-based inference]: https://github.com/Koldim2001/YOLO-Patch-Based-Inference
