Skip to content

Commit

Permalink
Ohifv3 (#1562)
Browse files Browse the repository at this point in the history
* Add extension and mode for MONAI Label

Signed-off-by: Andres <[email protected]>

* Add toolGroups to mode

Signed-off-by: Andres <[email protected]>

* Extension and model working in class format

Signed-off-by: Andres <[email protected]>

* Connection to MONAI Label server and label fetching are working now

Signed-off-by: Andres <[email protected]>

* Add probe tool

Signed-off-by: Andres <[email protected]>

* add segmentation load/rendering for OHIF v3 (#1525)

* working segmentation load

* segmentation panel

* add frame of reference uid to monai segs

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Signed-off-by: Andres Diaz-Pinto <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Andres Diaz-Pinto <[email protected]>

* Update segmentatio reader function

Signed-off-by: Andres <[email protected]>

* Model inference and label rendering working

Signed-off-by: Andres <[email protected]>

* Convert points from world to ijk - remove all clicks

Signed-off-by: Andres <[email protected]>

* Increase caching files when connecting to DICOM server

Signed-off-by: Andres <[email protected]>

* Add active learning tab

Signed-off-by: Andres <[email protected]>

* Update style for active learning tab

Signed-off-by: Andres <[email protected]>

* Hide the right panel

Signed-off-by: Andres <[email protected]>

* Send centroids to viewer

Signed-off-by: Andres <[email protected]>

* Send segmentation to DICOM Web

Signed-off-by: Andres <[email protected]>

* Fix centroids - json compatible

Signed-off-by: Andres <[email protected]>

* Update gitignore - add build script

Signed-off-by: Andres <[email protected]>

* feat(ohifv3): parse segment centroids for jump and make smartEdit work (#1531)

* working segmentation load

* segmentation panel

* add frame of reference uid to monai segs

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* make probe tool grab color for selected segment

* parse centroids and add to segmentation

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Signed-off-by: Andres Diaz-Pinto <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Andres Diaz-Pinto <[email protected]>

* Fix indexes for centroids

Signed-off-by: Andres <[email protected]>

* Add image

Signed-off-by: Andres <[email protected]>

* Add segmentation panel

Signed-off-by: Andres <[email protected]>

* DICOM-SEG writer is working

Signed-off-by: Andres <[email protected]>

* DeepEdit working on OHIFv3

Signed-off-by: Andres <[email protected]>

* Update tab name

Signed-off-by: Andres <[email protected]>

* Update gitignore

Signed-off-by: Andres <[email protected]>

* OHIFv3 working

Signed-off-by: Andres <[email protected]>

* Update bash scrip to build OHIFv3

Signed-off-by: Andres <[email protected]>

* COOP solved - using orthanc instead of proxy

Signed-off-by: Andres <[email protected]>

* Update print statement

Signed-off-by: Andres <[email protected]>

* Change tab background

Signed-off-by: Andres <[email protected]>

* feat(segmentation tools): working new segmentation panel and brushes (#1545)

* working segmentation load

* segmentation panel

* add frame of reference uid to monai segs

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* make probe tool grab color for selected segment

* parse centroids and add to segmentation

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* initial commit for toolbox

* fix merge

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Signed-off-by: Andres Diaz-Pinto <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Andres Diaz-Pinto <[email protected]>

* feat(labels): add initial labels from the server as starting point (#1546)

* working segmentation load

* segmentation panel

* add frame of reference uid to monai segs

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* make probe tool grab color for selected segment

* parse centroids and add to segmentation

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* initial commit for toolbox

* fix merge

* add initial segments from the server

* fix after pull

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Signed-off-by: Andres Diaz-Pinto <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Andres Diaz-Pinto <[email protected]>

* Add batch infer

Signed-off-by: Andres <[email protected]>

* Change background colors and fix click edition

Signed-off-by: Andres <[email protected]>

* change ohif image

Signed-off-by: Andres <[email protected]>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Proxy Headers

Signed-off-by: Andres <[email protected]>

---------

Signed-off-by: Andres <[email protected]>
Signed-off-by: Andres Diaz-Pinto <[email protected]>
Co-authored-by: Alireza <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 10, 2023
1 parent d2a9bae commit d4209ce
Show file tree
Hide file tree
Showing 69 changed files with 6,237 additions and 11 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,7 @@ junit
test-output.xml
studies
tests/data
yarn.lock
# Packages
node_modules
yarn.lock
2 changes: 1 addition & 1 deletion monailabel/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class Settings(BaseSettings):
MONAI_LABEL_DICOMWEB_FETCH_BY_FRAME: bool = False
MONAI_LABEL_DICOMWEB_CONVERT_TO_NIFTI: bool = True
MONAI_LABEL_DICOMWEB_SEARCH_FILTER: Dict[str, Any] = {"Modality": "CT"}
MONAI_LABEL_DICOMWEB_CACHE_EXPIRY: int = 180
MONAI_LABEL_DICOMWEB_CACHE_EXPIRY: int = 7200
MONAI_LABEL_DICOMWEB_PROXY_TIMEOUT: float = 30.0
MONAI_LABEL_DICOMWEB_READ_TIMEOUT: float = 5.0

Expand Down
2 changes: 1 addition & 1 deletion monailabel/datastore/utils/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def dicom_to_nifti(series_dir, is_seg=False):
return output_file


def binary_to_image(reference_image, label, dtype=np.uint16, file_ext=".nii.gz"):
def binary_to_image(reference_image, label, dtype=np.uint8, file_ext=".nii.gz"):
start = time.time()

image_np, meta_dict = LoadImage(image_only=False)(reference_image)
Expand Down
9 changes: 9 additions & 0 deletions monailabel/endpoints/ohif.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,17 @@ def get_ohif(path: str):
if not os.path.exists(file):
logger.info(file)
raise HTTPException(status_code=404, detail="Resource NOT Found")

return FileResponse(file, media_type=get_mime_type(file))

# headers = {
# "Cross-Origin-Opener-Policy": "same-origin",
# "Cross-Origin-Embedder-Policy": "require-corp",
# "Cross-Origin-Resource-Policy": "same-site",
# }

# return FileResponse(file, media_type=get_mime_type(file), headers=headers)


@router.get("/{path:path}", include_in_schema=False)
async def api_get_ohif(path: str, user: User = Depends(RBAC(settings.MONAI_LABEL_AUTH_ROLE_USER))):
Expand Down
9 changes: 9 additions & 0 deletions monailabel/endpoints/proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ async def proxy_dicom(op: str, path: str, response: Response):
)

# some version of ohif requests metadata using qido so change it to wado
print(
f"This is the server {server} - This is the op {op} - This is the prefix {prefix} - This is the path {path}"
)
if path.endswith("metadata") and op == "qido":
prefix = settings.MONAI_LABEL_WADO_PREFIX

Expand All @@ -78,10 +81,16 @@ async def proxy_dicom(op: str, path: str, response: Response):
settings.MONAI_LABEL_DICOMWEB_PROXY_TIMEOUT,
read=settings.MONAI_LABEL_DICOMWEB_READ_TIMEOUT,
)

print(f"This is the proxy path: {proxy_path}")
proxy = await client.get(proxy_path, timeout=timeout)

response.body = proxy.content
response.status_code = proxy.status_code
# response.headers["Cross-Origin-Opener-Policy"] = "same-origin"
# response.headers["Cross-Origin-Embedder-Policy"] = "require-corp"
# response.headers["Cross-Origin-Resource-Policy"] = "same-site"
# response.headers["Cross-Origin-Resource-Policy"] = "cross-origin"
return response


Expand Down
11 changes: 11 additions & 0 deletions monailabel/tasks/infer/basic_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,17 @@ def __call__(
"transform": data.get("latencies"),
}

# Add Centroids to the result json to consume in OHIF v3
centroids = data.get("centroids", None)
if centroids is not None:
centroids_dict = dict()
for c in centroids:
all_items = list(c.items())
centroids_dict[all_items[0][0]] = [str(i) for i in all_items[0][1]] # making it json compatible
result_json["centroids"] = centroids_dict
else:
result_json["centroids"] = dict()

if result_file_name is not None and isinstance(result_file_name, str):
logger.info(f"Result File: {result_file_name}")
logger.info(f"Result Json Keys: {list(result_json.keys())}")
Expand Down
4 changes: 4 additions & 0 deletions plugins/ohif/monai-label/src/components/MonaiLabelPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ export default class MonaiLabelPanel extends Component {
super(props);

const { viewports, studies, activeIndex } = props;
/* setTimeout(() => {
this.viewConstants = this.getViewConstants(viewports, studies, activeIndex);
}, 2000) */

this.viewConstants = this.getViewConstants(viewports, studies, activeIndex);
console.debug(this.viewConstants);

Expand Down
149 changes: 149 additions & 0 deletions plugins/ohifv3/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<!--
Copyright (c) MONAI Consortium
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

## MONAI Label Plugin for OHIF Viewer
The Open Health Imaging Foundation (OHIF) Viewer is an open-source, web-based platform for medical imaging. OHIF Viewer provides a framework for building complex imaging applications with user-friendly interfaces. MONAI Label supports the web-based OHIF viewer with connectivity to a remote DICOM server via DICOMweb.

<img src="./images/ohifv3.png" width=90% />

### Table of Contents
- [Supported Applications](#supported-applications)
- [Installing OHIF](#installing-ohif)
- [Installing Orthanc](#installing-orthanc-dicomweb)
- [Converting NIFTI Images to DICOM](#converting-nifti-images-to-dicom)
- [Converting NIFTI Annotations to DICOM-SEG](#converting-nifti-annotations-to-dicom-seg)
- [Uploading DICOM to Orthanc](#uploading-dicom-to-orthanc)

### Supported Applications
Supported applications can be found in the [sample-apps](../../sample-apps/radiology/) folder under the radiology section. These applications include models like DeepEdit, DeepGrow, Segmentation, and more, which can be used to create and refine labels for various medical imaging tasks.

### Installing OHIF
When installing MONAI Label with `pip install monailabel`, a version of OHIF that is pre-built with the MONAI Label library is automatically installed. OHIF will be accessible at http://127.0.0.1:8000/ohif/ when you start the MONAI Label server and connect to local/remote DICOM-web storage.

#### Development setup

To build the OHIF plugin for development, follow these steps:
```bash
sudo sh requirements.sh # installs yarn
sh build.sh
```

To run Orthanc from the submodule and avoid building the OHIF package for every code change, use the following commands:
```bash
cd plugins/ohif/Viewers

yarn run dev:orthanc

# OHIF will run at http://127.0.0.1:3000/
```
You can then visit http://127.0.0.1:3000/ on your browser to see the running OHIF.

### Installing Orthanc (DICOMWeb)

#### Ubuntu 20.x

```bash
# Install Orthanc and DICOMweb plugin
sudo apt-get install orthanc orthanc-dicomweb -y

# Install Plastimatch
sudo apt-get install plastimatch -y
```

However, you must upgrade to the latest version by following the steps mentioned on the [Orthanc Installation Guide](https://book.orthanc-server.com/users/debian-packages.html#replacing-the-package-from-the-service-by-the-lsb-binaries)

```bash
sudo service orthanc stop
sudo wget https://lsb.orthanc-server.com/orthanc/1.9.7/Orthanc --output-document /usr/sbin/Orthanc
sudo rm -f /usr/share/orthanc/plugins/*.so

sudo wget https://lsb.orthanc-server.com/orthanc/1.9.7/libServeFolders.so --output-document /usr/share/orthanc/plugins/libServeFolders.so
sudo wget https://lsb.orthanc-server.com/orthanc/1.9.7/libModalityWorklists.so --output-document /usr/share/orthanc/plugins/libModalityWorklists.so
sudo wget https://lsb.orthanc-server.com/plugin-dicom-web/1.6/libOrthancDicomWeb.so --output-document /usr/share/orthanc/plugins/libOrthancDicomWeb.so

sudo service orthanc restart
```

#### Windows/Others _(latest version)_

- Download and Install Orthanc from https://www.orthanc-server.com/download.php

### Converting NIFTI images to DICOM
To use Orthanc, your files need to be in DICOM format. You can convert any Nifti files to DICOM using the following command:
```bash
plastimatch convert --patient-id patient1 --input image.nii.gz --output-dicom test
```
- `plastimatch convert`: This is the command to run the conversion tool.
- `--patient-id patient1`: This option specifies the ID of the patient to be associated with the DICOM files. In this example, it is set to `patient1`.
- `--input image.nii.gz`: This option specifies the path to the input Nifti file that you want to convert to DICOM. In this example, the input file is `image.nii.gz`.
- `--output-dicom test`: This option specifies the path to the output folder where the DICOM files will be saved. In this example, the output folder is named `test`.

When you run this command, plastimatch will read the input Nifti file and convert it to a series of DICOM files with the specified patient ID. These files will be saved in the test folder in DICOM format, which can be uploaded to an Orthanc server.

### Converting NIFTI Annotations to DICOM-SEG

If you want to upload image annotations to the DICOMWeb server (such as Orthanc), you should use DICOM-SEG format. DICOM-SEG is a DICOM standard format for image segmentation. To convert NIFTI annotations to DICOM-SEG, you can use the itkimage2segimage tool from ITK (Insight Toolkit).

Here's how to use itkimage2segimage to convert NIFTI annotations to DICOM-SEG:

1. Install ITK: You can download and install ITK from their website, or use a package manager such as pip or conda to install it.
2. Convert NIFTI annotations to NIFTI-Segmentations: Use the `plastimatch convert` command to convert the NIFTI annotations to NIFTI-Segmentations format. This format is required as an input to `itkimage2segimage`. The command is similar to the one used to convert NIFTI images to DICOM, but with an additional option:

```bash
plastimatch convert --input annotations.nii.gz --output-nifti-seg annotations-seg.nii.gz
```
This command will convert the NIFTI annotations file named `annotations.nii.gz` to NIFTI-Segmentations format and save the result in a file named `annotations-seg.nii.gz`.

3. Convert NIFTI-Segmentations to DICOM-SEG: Use the `itkimage2segimage` command to convert the NIFTI-Segmentations file to DICOM-SEG format. Here's an example command:

```bash
itkimage2segimage --inputImage annotations-seg.nii.gz --outputDICOM annotations-seg.dcm --patientID patient1
```
This command will convert the `annotations-seg.nii.gz` file to DICOM-SEG format and save the result in a file named `annotations-seg.dcm`. The `--patientID` option specifies the ID of the patient to be associated with the DICOM-SEG file.

After conversion, you can upload the DICOM-SEG file to the DICOMWeb server such as Orthanc.


### Uploading DICOM to Orthanc

#### Use Orthanc Browser
You can use the Orthanc browser located at http://127.0.0.1:8042/app/explorer.html#upload to upload files.

#### Using STORE SCP/SCU
To upload files using STORE SCP/SCU, you need to enable AET by editing the `orthanc.json` file:
`sudo vim /etc/orthanc/orthanc.json`

```json5
// The list of the known DICOM modalities
"DicomModalities" : {
/**
* Uncommenting the following line would enable Orthanc to
* connect to an instance of the "storescp" open-source DICOM
* store (shipped in the DCMTK distribution) started by the
* command line "storescp 2000".
**/
"sample": ["MONAILABEL", "127.0.0.1", 104]
```
Then, restart Orthanc:
```
sudo service orthanc restart
```
#### Upload Files
To upload files, use the following command:
```bash
python -m pynetdicom storescu 127.0.0.1 4242 test -aet MONAILABEL -r
```
That's it! With these steps, you should have successfully installed MONAI Label with the OHIF viewer plugin and connected it to a remote DICOM server via DICOMweb.
75 changes: 75 additions & 0 deletions plugins/ohifv3/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/bin/bash

# Copyright (c) MONAI Consortium
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

curr_dir="$(pwd)"
my_dir="$(dirname "$(readlink -f "$0")")"

echo "Installing requirements..."
sh $my_dir/requirements.sh

install_dir=${1:-$my_dir/../../monailabel/endpoints/static/ohif}

echo "Current Dir: ${curr_dir}"
echo "My Dir: ${my_dir}"
echo "Installing OHIF at: ${install_dir}"

cd ${my_dir}
rm -rf Viewers
git clone https://github.com/OHIF/Viewers.git
cd Viewers
git checkout feat/monai-label


sed -i "s|routerBasename: '/'|routerBasename: '/ohif/'|g" ./platform/app/public/config/default.js
sed -i "s|name: 'aws'|name: 'Orthanc'|g" ./platform/app/public/config/default.js
sed -i "s|wadoUriRoot: 'https://d33do7qe4w26qo.cloudfront.net/dicomweb'|wadoUriRoot: 'http://localhost/dicom-web'|g" ./platform/app/public/config/default.js
sed -i "s|wadoRoot: 'https://d33do7qe4w26qo.cloudfront.net/dicomweb'|wadoRoot: 'http://localhost/dicom-web'|g" ./platform/app/public/config/default.js
sed -i "s|qidoRoot: 'https://d33do7qe4w26qo.cloudfront.net/dicomweb'|qidoRoot: 'http://localhost/dicom-web'|g" ./platform/app/public/config/default.js

sed -i "s|PUBLIC_URL=/|PUBLIC_URL=/ohif/|g" ./platform/app/.env


yarn install

# Link the mode and extension HERE
echo "Linking extension and mode at: $(pwd)"
yarn run cli link-extension ../extension-monai-label
yarn run cli link-mode ../mode-monai-label

cd ../extension-monai-label

echo "Running install again at: $(pwd)"

yarn install

echo "Moving nrrd-js and itk node modules to Viewersnode_modules/"

cp -r ./node_modules/nrrd-js ../Viewers/node_modules/

cp -r ./node_modules/itk ../Viewers/node_modules/

echo "Moving to Viewers folder to build OHIF"

cd ../Viewers

echo "Viewers folder before building OHIF $(pwd)"

QUICK_BUILD=true yarn run build

rm -rf ${install_dir}
mv ./platform/app/dist/ ${install_dir}
echo "Copied OHIF to ${install_dir}"

rm -rf ../Viewers

cd ${curr_dir}
Loading

0 comments on commit d4209ce

Please sign in to comment.