diff --git a/.dockerignore b/.dockerignore
index 07db66344..2486d5f59 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -14,6 +14,7 @@ __pycache__
.vscode
.webpack
node_modules/
+*.log
# Environments
.env
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 388b54176..00dc0aa11 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -91,7 +91,7 @@ jobs:
run: |
rm dist/monai*.tar.gz
- - name: Publish distribution to Test PyPI
+ - name: Publish distribution to Test
if: ${{ github.event.inputs.test_py == 'true' }}
uses: pypa/gh-action-pypi-publish@master
with:
diff --git a/Dockerfile b/Dockerfile
index f47e9137a..cf02e489e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -36,7 +36,12 @@ RUN BUILD_OHIF=false python setup.py bdist_wheel --build-number $(date +'%Y%m%d%
FROM ${FINAL_IMAGE}
LABEL maintainer="monai.contact@gmail.com"
WORKDIR /opt/monailabel
+COPY requirements.txt /opt/monailabel/requirements.txt
+
RUN apt update -y && apt install -y git curl openslide-tools python3 python-is-python3 python3-pip
RUN python -m pip install --no-cache-dir pytest torch torchvision torchaudio
+
COPY --from=build /opt/monailabel/dist/monailabel* /opt/monailabel/dist/
-RUN python -m pip install --no-cache-dir /opt/monailabel/dist/monailabel*.whl
+RUN python -m pip install -v --no-cache-dir /opt/monailabel/dist/monailabel*.whl
+RUN python -m pip uninstall sam2 -y
+RUN python -m pip install -v --no-cache-dir -r /opt/monailabel/requirements.txt
diff --git a/README.md b/README.md
index 3ae5bbc4d..d58360dd2 100644
--- a/README.md
+++ b/README.md
@@ -167,12 +167,6 @@ In addition, you can find a table of the basic supported fields, modalities, vie
-> [**SAM2**](https://github.com/facebookresearch/sam2/)
->
-> By default, SAM2 is included for all the above Apps only when **_python >= 3.10_**
-> - **sam_2d**: for any organ or tissue and others over a given slice/2D image.
-> - **sam_3d**: to support SAM2 propagation over multiple slices (Radiology/MONAI-Bundle).
-
# Getting Started with MONAI Label
### MONAI Label requires a few steps to get started:
- Step 1: [Install MONAI Label](#step-1-installation)
@@ -219,6 +213,19 @@ To install the _**latest features**_ using one of the following options:
docker run --gpus all --rm -ti --ipc=host --net=host projectmonai/monailabel:latest bash
+### SAM-2
+
+> By default, [**SAM2**](https://github.com/facebookresearch/sam2/) model is included for all the Apps when **_python >= 3.10_**
+> - **sam_2d**: for any organ or tissue and others over a given slice/2D image.
+> - **sam_3d**: to support SAM2 propagation over multiple slices (Radiology/MONAI-Bundle).
+
+If you are using `pip install monailabel` by default it uses [SAM-2](https://huggingface.co/facebook/sam2-hiera-large) models.
+
+To use [SAM-2.1](https://huggingface.co/facebook/sam2.1-hiera-large) use one of following options.
+ - Use monailabel [Docker](https://hub.docker.com/r/projectmonai/monailabel) instead of pip package
+ - Run monailabel in dev mode (git checkout)
+ - If you have installed monailabel via pip then uninstall **_sam2_** package `pip uninstall sam2` and then run `pip install -r requirements.txt` or install latest **SAM-2** from it's [github](https://github.com/facebookresearch/sam2/tree/main?tab=readme-ov-file#installation).
+
## Step 2 MONAI Label Sample Applications
Radiology
diff --git a/monailabel/config.py b/monailabel/config.py
index bf195c7bc..844b6728e 100644
--- a/monailabel/config.py
+++ b/monailabel/config.py
@@ -8,14 +8,18 @@
# 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.
-
import os
+from importlib.util import find_spec
from typing import Any, Dict, List, Optional
from pydantic import AnyHttpUrl
from pydantic_settings import BaseSettings, SettingsConfigDict
+def is_package_installed(name):
+ return False if find_spec(name) is None else True
+
+
class Settings(BaseSettings):
MONAI_LABEL_API_STR: str = ""
MONAI_LABEL_PROJECT_NAME: str = "MONAILabel"
@@ -98,6 +102,19 @@ class Settings(BaseSettings):
MONAI_ZOO_REPO: str = "Project-MONAI/model-zoo/hosting_storage_v1"
MONAI_ZOO_AUTH_TOKEN: str = ""
+ # Refer: https://github.com/facebookresearch/sam2?tab=readme-ov-file#model-description
+ # Refer: https://huggingface.co/facebook/sam2-hiera-large
+ MONAI_SAM_MODEL_PT: str = (
+ "https://huggingface.co/facebook/sam2.1-hiera-large/resolve/main/sam2.1_hiera_large.pt"
+ if is_package_installed("SAM-2")
+ else "https://huggingface.co/facebook/sam2-hiera-large/resolve/main/sam2_hiera_large.pt"
+ )
+ MONAI_SAM_MODEL_CFG: str = (
+ "https://huggingface.co/facebook/sam2.1-hiera-large/resolve/main/sam2.1_hiera_l.yaml"
+ if is_package_installed("SAM-2")
+ else "https://huggingface.co/facebook/sam2-hiera-large/resolve/main/sam2_hiera_l.yaml"
+ )
+
model_config = SettingsConfigDict(
env_file=".env",
case_sensitive=True,
diff --git a/monailabel/sam2/infer.py b/monailabel/sam2/infer.py
index 880e2ae7c..1ddca8ed3 100644
--- a/monailabel/sam2/infer.py
+++ b/monailabel/sam2/infer.py
@@ -22,6 +22,8 @@
import pylab
import schedule
import torch
+from hydra import initialize_config_dir
+from hydra.core.global_hydra import GlobalHydra
from monai.transforms import KeepLargestConnectedComponent, LoadImaged
from PIL import Image
from sam2.build_sam import build_sam2, build_sam2_video_predictor
@@ -114,13 +116,21 @@ def __init__(
self._config.update(config)
# Download PreTrained Model
- # https://github.com/facebookresearch/sam2?tab=readme-ov-file#model-description
- pt = "sam2.1_hiera_large.pt"
- url = f"https://dl.fbaipublicfiles.com/segment_anything_2/092824/{pt}"
- self.path = os.path.join(model_dir, f"pretrained_{pt}")
- download_file(url, self.path)
+ pt_url = settings.MONAI_SAM_MODEL_PT
+ conf_url = settings.MONAI_SAM_MODEL_CFG
+ sam_pt = pt_url.split("/")[-1]
+ sam_conf = conf_url.split("/")[-1]
+
+ self.path = os.path.join(model_dir, sam_pt)
+ self.config_path = os.path.join(model_dir, sam_conf)
+
+ GlobalHydra.instance().clear()
+ initialize_config_dir(config_dir=model_dir)
+
+ download_file(pt_url, self.path)
+ download_file(conf_url, self.config_path)
+ self.config_path = sam_conf
- self.config_path = "configs/sam2.1/sam2.1_hiera_l.yaml"
self.predictors = {}
self.image_cache = {}
self.inference_state = None
@@ -393,8 +403,8 @@ def main():
force=True,
)
- app_name = "pathology"
- app_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", "sample-apps", app_name))
+ app_name = "radiology"
+ app_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sample-apps", app_name))
model_dir = os.path.join(app_dir, "model")
logger.info(f"Model Dir: {model_dir}")
if app_name == "pathology":
diff --git a/requirements.txt b/requirements.txt
index 3583645c2..4d05c4ea3 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -45,7 +45,7 @@ scikit-learn
scipy
google-auth==2.29.0
SAM-2 @ git+https://github.com/facebookresearch/sam2.git@c2ec8e14a185632b0a5d8b161928ceb50197eddc ; python_version >= '3.10'
-
+#sam2>=0.4.1; python_version >= '3.10'
# scipy and scikit-learn latest packages are missing on python 3.8
# sudo apt-get install openslide-tools -y
diff --git a/sample-apps/endoscopy/main.py b/sample-apps/endoscopy/main.py
index cd38984c2..258b5cb20 100644
--- a/sample-apps/endoscopy/main.py
+++ b/sample-apps/endoscopy/main.py
@@ -58,9 +58,9 @@ def __init__(self, app_dir, studies, conf):
print(f" all, {', '.join(configs.keys())}")
print("---------------------------------------------------------------------------------------")
print("")
- exit(-1)
+ # exit(-1)
- models = models.split(",")
+ models = models.split(",") if models else []
models = [m.strip() for m in models]
invalid = [m for m in models if m != "all" and not configs.get(m)]
if invalid:
@@ -85,7 +85,7 @@ def __init__(self, app_dir, studies, conf):
logger.info(f"+++ Using Models: {list(self.models.keys())}")
- self.sam = strtobool(conf.get("sam", "true"))
+ self.sam = strtobool(conf.get("sam2", "true"))
super().__init__(
app_dir=app_dir,
studies=studies,
diff --git a/sample-apps/monaibundle/main.py b/sample-apps/monaibundle/main.py
index c698d402a..bd6ff807f 100644
--- a/sample-apps/monaibundle/main.py
+++ b/sample-apps/monaibundle/main.py
@@ -46,7 +46,7 @@ def __init__(self, app_dir, studies, conf):
self.epistemic_simulation_size = int(conf.get("epistemic_simulation_size", "5"))
self.epistemic_dropout = float(conf.get("epistemic_dropout", "0.2"))
- self.sam = strtobool(conf.get("sam", "true"))
+ self.sam = strtobool(conf.get("sam2", "true"))
super().__init__(
app_dir=app_dir,
studies=studies,
diff --git a/sample-apps/pathology/main.py b/sample-apps/pathology/main.py
index 095791792..1f11865b0 100644
--- a/sample-apps/pathology/main.py
+++ b/sample-apps/pathology/main.py
@@ -54,7 +54,7 @@ def __init__(self, app_dir, studies, conf):
configs = {k: v for k, v in sorted(configs.items())}
- models = conf.get("models", "all")
+ models = conf.get("models")
if not models:
print("")
print("---------------------------------------------------------------------------------------")
@@ -63,9 +63,9 @@ def __init__(self, app_dir, studies, conf):
print(f" all, {', '.join(configs.keys())}")
print("---------------------------------------------------------------------------------------")
print("")
- exit(-1)
+ # exit(-1)
- models = models.split(",")
+ models = models.split(",") if models else []
models = [m.strip() for m in models]
invalid = [m for m in models if m != "all" and not configs.get(m)]
if invalid:
@@ -90,7 +90,7 @@ def __init__(self, app_dir, studies, conf):
logger.info(f"+++ Using Models: {list(self.models.keys())}")
- self.sam = strtobool(conf.get("sam", "true"))
+ self.sam = strtobool(conf.get("sam2", "true"))
super().__init__(
app_dir=app_dir,
studies=studies,
diff --git a/sample-apps/radiology/main.py b/sample-apps/radiology/main.py
index 66ef3e4ad..bb7f8ae18 100644
--- a/sample-apps/radiology/main.py
+++ b/sample-apps/radiology/main.py
@@ -64,7 +64,7 @@ def __init__(self, app_dir, studies, conf):
print("")
exit(-1)
- models = models.split(",")
+ models = models.split(",") if models else []
models = [m.strip() for m in models]
# Can be configured with --conf scribbles false or true
self.scribbles = conf.get("scribbles", "true") == "true"
@@ -100,7 +100,7 @@ def __init__(self, app_dir, studies, conf):
# Load models from bundle config files, local or released in Model-Zoo, e.g., --conf bundles
self.bundles = get_bundle_models(app_dir, conf, conf_key="bundles") if conf.get("bundles") else None
- self.sam = strtobool(conf.get("sam", "true"))
+ self.sam = strtobool(conf.get("sam2", "true"))
super().__init__(
app_dir=app_dir,
studies=studies,
diff --git a/setup.cfg b/setup.cfg
index 15e24022d..83b3d77e0 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -70,7 +70,8 @@ install_requires =
scikit-learn
scipy
google-auth>=2.29.0
- SAM-2 @ git+https://github.com/facebookresearch/sam2.git@c2ec8e14a185632b0a5d8b161928ceb50197eddc ; python_version >= '3.10'
+ sam2>=0.4.1; python_version >= '3.10'
+ #SAM-2 @ git+https://github.com/facebookresearch/sam2.git@c2ec8e14a185632b0a5d8b161928ceb50197eddc ; python_version >= '3.10'
[flake8]
select = B,C,E,F,N,P,T4,W,B9