Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add range shifter support #22

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
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
18 changes: 13 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ Script for manipulating dicom plans

```
$ python3 dicomfix/main.py -h
usage: main.py [-h] [-w WEIGHTS] [-o OUTPUT] [-e EXPORT_RACEHORSE] [-a] [-dt] [-ic] [-i] [-tr4] [-rs] [-p PRINT_SPOTS]
[-g GANTRY_ANGLES] [-d DUPLICATE_FIELDS] [-rd RESCALE_DOSE] [-rf RESCALE_FACTOR] [-rm] [-tp TABLE_POSITION]
[-sp SNOUT_POSITION] [-tm TREATMENT_MACHINE] [-pl PLAN_LABEL] [-pn PATIENT_NAME] [-rn REVIEWER_NAME] [-v] [-V]
[inputfile]
usage: main.py [-h] [-w WEIGHTS] [-o OUTPUT] [-e EXPORT_RACEHORSE] [-a] [-dt] [-ic] [-i] [-ia] [-tr4] [-rs]
[-p PRINT_SPOTS] [-g GANTRY_ANGLES] [-d DUPLICATE_FIELDS] [-rd RESCALE_DOSE] [-rf RESCALE_FACTOR]
[-rm] [-tp TABLE_POSITION] [-sp SNOUT_POSITION] [-tm TREATMENT_MACHINE] [-pl PLAN_LABEL]
[-pn PATIENT_NAME] [-rn REVIEWER_NAME] [-v] [-V] [inputfile]

Modify ECLIPSE DICOM proton therapy treatment plans.

Expand All @@ -26,7 +26,8 @@ options:
-dt, --date Set RT date to now
-ic, --intent_curative
Set plan intent to CURATIVE
-i, --inspect Print contents of DICOM file and exit
-i, --inspect Print a summary of the DICOM file and exit
-ia, --inspect_all Print all tags in the DICOM file and exit
-tr4, --wizard_tr4 Prepare plan for TR4: sets approval, gantry, snout, and treatment machine
-rs, --fix_raystation
Make RayStation plans compatible with Varian proton systems
Expand Down Expand Up @@ -57,3 +58,10 @@ options:
-v, --verbosity Give more output. Option is additive, can be used up to 3 times
-V, --version show program's version number and exit
```


To run locally in venv
```
~/Projects/dicomfix$ pip install -e .
~/Projects/dicomfix$ python dicomfix/main.py
```
7 changes: 5 additions & 2 deletions dicomfix/__version__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from importlib.metadata import version as get_version
from importlib.metadata import version, PackageNotFoundError

__version__ = get_version("dicomfix")
try:
__version__ = version("dicomfix")
except PackageNotFoundError:
__version__ = "0.0.0" # Fallback version if package metadata is unavailable
1 change: 1 addition & 0 deletions dicomfix/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def __init__(self, parsed_args):
self.date = parsed_args.date
self.intent_curative = parsed_args.intent_curative
self.inspect = parsed_args.inspect
self.inspect_all = parsed_args.inspect_all
self.wizard_tr4 = parsed_args.wizard_tr4
self.fix_raystation = parsed_args.fix_raystation
self.print_spots = parsed_args.print_spots
Expand Down
5 changes: 4 additions & 1 deletion dicomfix/config_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ def parse_arguments(args=None):
parser.add_argument('-dt', '--date', action='store_true', default=False, help='Set RT date to now')
parser.add_argument('-ic', '--intent_curative', action='store_true', default=False,
help='Set plan intent to CURATIVE')
parser.add_argument('-i', '--inspect', action='store_true', default=False, help='Print contents of DICOM file and exit')
parser.add_argument('-i', '--inspect', action='store_true', default=False,
help='Print a summary of the DICOM file and exit')
parser.add_argument('-ia', '--inspect_all', action='store_true', default=False,
help='Print all tags in the DICOM file and exit')
parser.add_argument('-tr4', '--wizard_tr4', action='store_true', default=False,
help='Prepare plan for TR4: sets approval, gantry, snout, and treatment machine')

Expand Down
14 changes: 11 additions & 3 deletions dicomfix/dicomutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ def __init__(self, inputfile):
self.old_dicom = copy.deepcopy(self.dicom)
self.spots_discarded = 0 # count of spots discarded due to low MU
self.total_number_of_spots = 0
for ib in self.dicom.IonBeamSequence:
self.total_number_of_spots += sum([icp.NumberOfScanSpotPositions for icp in ib.IonControlPointSequence])
self.total_number_of_spots = self.total_number_of_spots // 2 # divide by 2, as each spot has two control points

if hasattr(self.dicom, "IonBeamSequence"):
for ib in self.dicom.IonBeamSequence:
self.total_number_of_spots += sum([icp.NumberOfScanSpotPositions for icp in ib.IonControlPointSequence])
self.total_number_of_spots = self.total_number_of_spots // 2 # divide by 2, as each spot has two control points

@staticmethod
def load_dicom(inputfile):
Expand Down Expand Up @@ -716,6 +718,12 @@ def safe_get(attr, default="N/A"):
# Return the concatenated output as a string
return "\n".join(output)

def inspect_all(self):
""" Print all attributes of the DICOM file to the console. """

logger.debug("Inspecting all DICOM attributes:")
print(self.dicom)

def print_dicom_spot_comparison(self, num_values):
"""
Compare spot meterset weights between the original and modified DICOM plans.
Expand Down
7 changes: 6 additions & 1 deletion dicomfix/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ def main(args=None):

# Handle inspect option
if config.inspect:
logger.info(dp.inspect())
print(dp.inspect())
exit(0)

# Handle inspect_all option
if config.inspect_all:
print(dp.inspect_all())
exit(0)

# Apply all modifications to the plan using the config object
Expand Down
14 changes: 9 additions & 5 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@ RUN pip install --upgrade pip \
&& pip install .

# Install optional dependencies for web UI (Streamlit)
RUN pip install .[dev]
RUN pip install .[web]
RUN pip install .[dev,web]

RUN pytest tests/

# Command to run the Streamlit app
# http
# Expose the port that Streamlit will run on
EXPOSE 8501
# EXPOSE 8501
# CMD ["streamlit", "run", "dicomfix/web/app.py", "--server.port=8501", "--server.address=0.0.0.0"]

# https if you have the certificate and key files
EXPOSE 8443
CMD ["streamlit", "run", "dicomfix/web/app.py", "--server.port=8443", "--server.address=0.0.0.0", "--server.sslCertFile=${SSL_CERT_FILE}", "--server.sslKeyFile=${SSL_KEY_FILE}"]

# Command to run the Streamlit app
CMD ["streamlit", "run", "dicomfix/web/app.py", "--server.port=8501", "--server.address=0.0.0.0"]
13 changes: 9 additions & 4 deletions docker/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
```
docker build -t dicomfix-webapp -f docker/Dockerfile .
docker run -p 8501:8501 dicomfix-webapp
sudo docker build -t dicomfix-webapp -f docker/Dockerfile .
sudo docker run -p 8501:8501 dicomfix-webapp
```
To export to systems with no www access
```
docker save -o dicomfix-webapp.tar dicomfix-webapp
sudo docker save -o dicomfix-webapp.tar dicomfix-webapp
sudo chown xxx:xxx dicomfix-webapp.tar
scp dicomfix-webapp.tar xxx@xxx:/xxx
```

On remote system:
```
docker load -i ./dicomfix-webapp.tar
docker run -p 8501:8501 dicomfix-webapp
# HTTP version:
docker run -p 8501:8501 dicomfix-webapp # will overwrite any existing :latest image

# HTTPS version:
docker run -p 8443:8443 -e SSL_CERT_FILE=/etc/ssl/certs/dicomfix.crt -e SSL_KEY_FILE=/etc/ssl/private/dicomfix.key dicomfix-webapp:latest
```
22 changes: 22 additions & 0 deletions docker/dicomfix-webapp.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[Unit]
Description=DicomFix WebApp Docker Container
After=network.target

[Service]
User=dcptclin
Restart=always
# ExecStart=/usr/bin/docker run --privileged -p 8501:8501 dicomfix-webapp # http
xecStart=/usr/bin/docker run --privileged \
-p 8443:8443 \
-e SSL_CERT_FILE=/etc/ssl/certs/dicomfix.crt \
-e SSL_KEY_FILE=/etc/ssl/private/dicomfix.key \
-v /etc/ssl/certs/dicomfix.crt:/etc/ssl/certs/dicomfix.crt:ro \
-v /etc/ssl/private/dicomfix.key:/etc/ssl/private/dicomfix.key:ro \
dicomfix-webapp:latest
ExecStop=/usr/bin/docker stop dicomfix-webapp
ExecStopPost=/usr/bin/docker rm dicomfix-webapp
TimeoutSec=30
RestartSec=10

[Install]
WantedBy=multi-user.target
11 changes: 8 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
[build-system]
requires = ["setuptools>=42", "wheel", "setuptools-scm"]
build-backend = "setuptools.build_meta"

[project]
name = "dicomfix"
version = "0.1.0"
# version = "0.1.0" # Version is managed by setuptools_scm
description = "A brief description of what your project does"
authors = [
{ name = "Niels Bassler", email = "[email protected]" },
Expand All @@ -14,6 +18,7 @@ dependencies = [
"pylibjpeg-openjpeg", # Support for JPEG 2000 compression
"pillow", # Support for other image formats
]
dynamic = ["version"]

[tool.setuptools]
packages = ["dicomfix"]
Expand Down Expand Up @@ -41,5 +46,5 @@ based_on_style = "pep8"
column_limit = 127

[tool.setuptools_scm]
version_scheme = "guess-next-dev"
local_scheme = "node-and-timestamp"
version_scheme = "post-release"
local_scheme = "node-and-date"
Loading