Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
118 changes: 10 additions & 108 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ https://github.com/user-attachments/assets/c9f9ee0a-f74d-4907-aa21-484dcfd10948
## Table of contents

- [Installation](#installation)
- [Server side](#server-side)
- [Client side: Installation in 3D Slicer](#client-side-installation-in-3d-slicer)
- [Installation in 3D Slicer](#installation-in-3d-slicer)
- [External server setup (macOS and advanced use)](external-server-setup.md)
- [Usage](#usage)
- [Editing an existing segment
](#editing-an-existing-segment)
Expand All @@ -29,117 +29,17 @@ https://github.com/user-attachments/assets/c9f9ee0a-f74d-4907-aa21-484dcfd10948

## Installation

`SlicerNNInteractive` needs to be set up on the server side and the client side. The server side needs relatively heavy compute, as described here:

> You need a Linux or Windows computer with a Nvidia GPU. 10GB of VRAM is recommended. Small objects should work with <6GB. nnInteractive supports Python 3.10+
>
> — [The nnInteractive README](https://github.com/MIC-DKFZ/nnInteractive?tab=readme-ov-file#prerequisites)

The client machine _can_ be the same as the server machine.

### Server side

#### Server running on Linux

You can install the server side of `SlicerNNInteractive` in three different ways:

##### Option 1: Using Docker

```
docker pull coendevente/nninteractive-slicer-server:latest
docker run --gpus all --rm -it -p 1527:1527 coendevente/nninteractive-slicer-server:latest
```

This will make the server available under port `1527` on your machine. If you would like to use a different port, say `1627`, replace `-p 1527:1527` with `-p 1627:1527`.

##### Option 2: Using `uv`

Another option is to run the server with [`uv`](https://docs.astral.sh/uv/) (see `uv` installation instructions [here](https://docs.astral.sh/uv/getting-started/installation/)):

```bash
uv run --with nninteractive-slicer-server nninteractive-slicer-server --host 0.0.0.0 --port 1527
```

##### Option 3: Using `pip`

_Step 1. Create a Python virtual environment_

If setting up the server for the first time, you need to create a Python virtual environment (e.g., using `conda` or `venv`) by specifying a location on your disk and activating that environment. For example, on Linux, using `venv`, you can accomplish this using these commands:

```bash
python3 -m venv path_to_your_virtual_environment
source path_to_your_virtual_environment/bin/activate
```

_Step 2. Install the server_

Next, you can install the server to this environment with these commands:

```bash
pip install nninteractive-slicer-server
nninteractive-slicer-server --host 0.0.0.0 --port 1527
```

If you would like to use a different port, say `1627`, replace `--port 1527` with `--port 1627`.

> [!NOTE]
> Remember that you'll have to start the server again if it was stopped for some reason (e.g., after rebooting your machine). To do so, activate your virtual Python environment with the `source` command above and run `nninteractive-slicer-server --host 0.0.0.0 --port 1527` again to start the server.

> [!NOTE]
> When starting the server, you can ignore the message `nnUNet_raw is not defined [...] how to set this up.`. Setting up these environment variables is not necessary when using `SlicerNNInteractive`.

#### Server running on Windows

##### One-time setup

Python and a pytorch package with GPU support is required. You can follow the steps below to set these up on your computer for your user:

1. Download pixi package manager by running this command in `Terminal` (to launch terminal, press the Windows button on your keyboard, type `terminal` and hit `Enter` key):

```
powershell -ExecutionPolicy ByPass -c "irm -useb https://pixi.sh/install.ps1 | iex"
```

2. Close the terminal and open a new Terminal to run the commands below to install Python and pytorch. The last step may take 10 minutes to complete, with no updates on the output for several minutes.

```
cd /d %localappdata%
mkdir nninteractive-server
cd nninteractive-server
pixi init .
pixi add python=3.12 pip
cd .pixi\envs\default\Scripts
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
```

##### Start the server

To start the server, there is no need to redo the steps above (install pixi and Python), just open `Terminal` and run these commands:

```
cd /d %localappdata%\nninteractive-server\.pixi\envs\default\Scripts
pip install nninteractive-slicer-server
nninteractive-slicer-server --host 0.0.0.0 --port 1527
```

If the firewall asks permission to access the port then allow it.

If you would like to use a different port, say `1627`, replace `--port 1527` with `--port 1627`.

> [!NOTE]
> When starting the server, you can ignore the message `nnUNet_raw is not defined [...] how to set this up.`. Setting up these environment variables is not necessary when using `SlicerNNInteractive`.

### Client side: Installation in 3D Slicer
Hardware requirements: `nnInteractive` computations require a Windows or Linux computer with an NVIDIA GPU. 10GB of VRAM is recommended. Small objects should work with <6GB. nnInteractive supports Python 3.10+> (source: [The nnInteractive README](https://github.com/MIC-DKFZ/nnInteractive?tab=readme-ov-file#prerequisites). macOS users can run Slicer with the nnInteractive extension on their computer but they need access to a Linux or Windows computer and [set up an external server application](external-server-setup.md).

1. [Download and install latest version of **3D Slicer**](https://slicer.readthedocs.io/en/latest/user_guide/getting_started.html#installing-3d-slicer)
2. [Install **NNInteractive** extension](https://slicer.readthedocs.io/en/latest/user_guide/extensions_manager.html#install-extensions)
3. Go to the `nnInteractive` module in Slicer and in the `Configuration` tab type in the URL of the server you set up in the [server side](#server-side) installation procedure. This should look something like `http://remote_host_name:1527` or, if you run the server locally, `http://localhost:1527`. If running the server on the same Windows computer as 3D Slicer, you must use `localhost` (ignore that the server suggests that `0.0.0.0` may be used).
3. On computers that do not have a suitable GPU for running nnInteractive (such as macOS computers): [set up an external server application](external-server-setup.md) on a suitable computer.

## Usage

Once you have completed the installation above, you can use `SlicerNNInteractive` as follows:
Once you have completed the installation above, you can use `NNInteractive` as follows:

1. If you haven't done so already, load in your image (e.g., through dragging your image file into Slicer).
1. If you haven't done so already, load in your image (e.g., by dragging your image file into Slicer application window).

2. Click one of the Interaction Tool buttons from the Interactive Prompts tab (point, bounding box, scribble, or lasso) and place your prompt in the image. This should result in a segmentation.

Expand All @@ -159,9 +59,11 @@ Each button in the Interactive Prompts tab has a keyboard shortcut, indicated by

## Common issues

- When resetting the server, the Slicer extension sometimes fails silently. Reloading the plugin or restarting Slicer often helps.
- The computation server may fail silently. Reloading the plugin or restarting Slicer often helps. If this does not solve the problem then stop the server process (a python executable with significant memory usage) or restart the computer.

## Developers

## Testing
### Testing

`SlicerNNInteractiveSegmentationTest` is a set of regression tests that verifies the output of `SlicerNNInteractive`. For every interaction type, it processes a set of test cases through the extension – which requires a running server – and compares the resulting segmentations against reference segementations. All tests use the publicly available `MRBrainTumor2` volume from the `Sample Data` extension.

Expand Down
95 changes: 95 additions & 0 deletions external-server-setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# External server setup

Follow the instructions below to set up an nnInteractive computation server application manually and connect to it from 3D Slicer.

Hardware requirements: a Windows or Linux computer with an NVIDIA GPU. 10GB of VRAM is recommended. Small objects should work with <6GB. nnInteractive supports Python 3.10+> (source: [The nnInteractive README](https://github.com/MIC-DKFZ/nnInteractive?tab=readme-ov-file#prerequisites).

After setting up the server, go to the `nnInteractive` module in Slicer, open the `Configuration` tab, select `External server`, and enter the server URL. This should look something like `http://remote_host_name:1527`, or `http://localhost:1527` if running locally. If running the server on the same Windows computer as 3D Slicer, use `localhost` (ignore that the server suggests `0.0.0.0` may be used).

## Server running on Linux

### Option 1: Using Docker

```
docker pull coendevente/nninteractive-slicer-server:latest
docker run --gpus all --rm -it -p 1527:1527 coendevente/nninteractive-slicer-server:latest
```

This will make the server available under port `1527` on your machine. If you would like to use a different port, say `1627`, replace `-p 1527:1527` with `-p 1627:1527`.

### Option 2: Using `uv`

Another option is to run the server with [`uv`](https://docs.astral.sh/uv/) (see `uv` installation instructions [here](https://docs.astral.sh/uv/getting-started/installation/)):

```bash
uv run --with nninteractive-slicer-server nninteractive-slicer-server --host 0.0.0.0 --port 1527
```

### Option 3: Using `pip`

_Step 1. Create a Python virtual environment_

If setting up the server for the first time, you need to create a Python virtual environment (e.g., using `conda` or `venv`) by specifying a location on your disk and activating that environment. For example, on Linux, using `venv`, you can accomplish this using these commands:

```bash
python3 -m venv path_to_your_virtual_environment
source path_to_your_virtual_environment/bin/activate
```

_Step 2. Install the server_

Next, you can install the server to this environment with these commands:

```bash
pip install nninteractive-slicer-server
nninteractive-slicer-server --host 0.0.0.0 --port 1527
```

If you would like to use a different port, say `1627`, replace `--port 1527` with `--port 1627`.

> [!NOTE]
> Remember that you'll have to start the server again if it was stopped for some reason (e.g., after rebooting your machine). To do so, activate your virtual Python environment with the `source` command above and run `nninteractive-slicer-server --host 0.0.0.0 --port 1527` again to start the server.

> [!NOTE]
> When starting the server, you can ignore the message `nnUNet_raw is not defined [...] how to set this up.`. Setting up these environment variables is not necessary when using `SlicerNNInteractive`.

## Server running on Windows

### One-time setup

Python and a pytorch package with GPU support is required. You can follow the steps below to set these up on your computer for your user:

1. Download pixi package manager by running this command in `Terminal` (to launch terminal, press the Windows button on your keyboard, type `terminal` and hit `Enter` key):

```
powershell -ExecutionPolicy ByPass -c "irm -useb https://pixi.sh/install.ps1 | iex"
```

2. Close the terminal and open a new Terminal to run the commands below to install Python and pytorch. The last step may take 10 minutes to complete, with no updates on the output for several minutes.

```
cd /d %localappdata%
mkdir nninteractive-server
cd nninteractive-server
pixi init .
pixi add python=3.12 pip
cd .pixi\envs\default\Scripts
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
```

### Start the server

To start the server, there is no need to redo the steps above (install pixi and Python), just open `Terminal` and run these commands:

```
cd /d %localappdata%\nninteractive-server\.pixi\envs\default\Scripts
pip install nninteractive-slicer-server
nninteractive-slicer-server --host 0.0.0.0 --port 1527
```

If the firewall asks permission to access the port then allow it.

If you would like to use a different port, say `1627`, replace `--port 1527` with `--port 1627`.

> [!NOTE]
> When starting the server, you can ignore the message `nnUNet_raw is not defined [...] how to set this up.`. Setting up these environment variables is not necessary when using `SlicerNNInteractive`.
23 changes: 18 additions & 5 deletions server/nninteractive_slicer_server/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
###############################################################################
REPO_ID = "nnInteractive/nnInteractive"
MODEL_NAME = "nnInteractive_v1.0" # Updated models may be available in the future
DOWNLOAD_DIR = ".nninteractive_weights" # Specify the download directory
DOWNLOAD_DIR = os.path.join(os.path.expanduser("~"), ".nninteractive_weights")

app = FastAPI()

Expand Down Expand Up @@ -105,10 +105,10 @@ def process_mask_and_click_input(file_bytes, positive_click):


def get_error_if_img_not_set():
if PROMPT_MANAGER.img is None:
if PROMPT_MANAGER is None or PROMPT_MANAGER.img is None:
warnings.warn("There is no image in the server. Be sure to send it before")
return {"status": "error", "message": "No image uploaded"}

return


Expand Down Expand Up @@ -244,9 +244,15 @@ def add_scribble_interaction(self, mask, include_interaction):


###############################################################################
# Global prompt manager instance
# Global prompt manager instance (initialized on startup)
###############################################################################
PROMPT_MANAGER = PromptManager()
PROMPT_MANAGER = None


@app.on_event("startup")
async def startup_event():
global PROMPT_MANAGER
PROMPT_MANAGER = PromptManager()


###############################################################################
Expand Down Expand Up @@ -426,10 +432,17 @@ async def add_scribble_interaction(


def main():
global DOWNLOAD_DIR
parser = argparse.ArgumentParser(description="Run the nnInteractive Slicer server.")
parser.add_argument("--host", default="0.0.0.0", help="Host interface to bind to.")
parser.add_argument("--port", type=int, default=1527, help="Port to listen on.")
parser.add_argument(
"--weights-dir",
default=DOWNLOAD_DIR,
help="Directory for model weights (default: ~/.nninteractive_weights).",
)
args = parser.parse_args()
DOWNLOAD_DIR = args.weights_dir

uvicorn.run(app, host=args.host, port=args.port)

Expand Down
2 changes: 1 addition & 1 deletion slicer_plugin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ set(EXTENSION_CONTRIBUTORS "Coen de Vente (University of Amsterdam)")
set(EXTENSION_DESCRIPTION "Deep learning-based framework for interactive segmentation of 3D images. The extension is available under an Apache-2.0 license, but the weights that are being downloaded when running the SlicerNNInteractive server are available under a Creative Commons Attribution Non Commercial Share Alike 4.0 license, as described in the original nnInteractive respository.")
set(EXTENSION_ICONURL "https://raw.githubusercontent.com/coendevente/SlicerNNInteractive/main/slicer_plugin/SlicerNNInteractive/Resources/Icons/SlicerNNInteractive.png")
set(EXTENSION_SCREENSHOTURLS "https://raw.githubusercontent.com/coendevente/SlicerNNInteractive/main/img/segmentation_result.jpg https://raw.githubusercontent.com/coendevente/SlicerNNInteractive/main/img/plugin_first_sight.png")
set(EXTENSION_DEPENDS "NA") # Specified as a list or "NA" if no dependencies
set(EXTENSION_DEPENDS "NNUNet") # Specified as a list or "NA" if no dependencies

#-----------------------------------------------------------------------------
# Extension dependencies
Expand Down
11 changes: 11 additions & 0 deletions slicer_plugin/SlicerNNInteractive/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,14 @@ slicerMacroBuildScriptedModule(
RESOURCES ${MODULE_PYTHON_RESOURCES}
WITH_GENERIC_TESTS
)

#-----------------------------------------------------------------------------
# Install the server Python package alongside the module script so that
# SlicerNNInteractive.py can locate it via Path(__file__).parent at runtime.
set(NNINTERACTIVE_SERVER_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../server/nninteractive_slicer_server")

install(
DIRECTORY "${NNINTERACTIVE_SERVER_DIR}"
DESTINATION "${Slicer_INSTALL_QTSCRIPTEDMODULES_LIB_DIR}"
COMPONENT RuntimeLibraries
)
Loading
Loading