feat: Introduce nnUNet inference pipeline with DICOM conversion, pretrained model installation, and configuration, updating gitignore to exclude archives.
This commit is contained in:
parent
2bfa789006
commit
78e3c012ef
9 changed files with 165 additions and 0 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -162,3 +162,5 @@ cython_debug/
|
|||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
*.pth
|
||||
*.zip
|
||||
|
|
|
|||
5
src/2508.yaml
Normal file
5
src/2508.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
dataset_name_or_id: 2508 # models trained on NTUH database
|
||||
# dataset_name_or_id: 3828 # models trained on BraTS + NTUH
|
||||
nnunet_preprocessed: "./nnUNet/preprocessed" # directory for storing pre-processed data (optional)
|
||||
nnunet_raw: "./nnUNet/raw/" # directory for storing formated raw data (optional)
|
||||
nnunet_results: "./nnUNet/results" # directory for storing trained model checkpoints (optional)
|
||||
4
src/2602.yaml
Normal file
4
src/2602.yaml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
dataset_name_or_id: 2602 # models trained on BraTS + NTUH
|
||||
nnunet_preprocessed: "./nnUNet/preprocessed" # directory for storing pre-processed data (optional)
|
||||
nnunet_raw: "./nnUNet/raw/" # directory for storing formated raw data (optional)
|
||||
nnunet_results: "./nnUNet/results" # directory for storing trained model checkpoints (optional)
|
||||
5
src/3828.yaml
Normal file
5
src/3828.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# dataset_name_or_id: 2508 # models trained on NTUH database
|
||||
dataset_name_or_id: 3828 # models trained on BraTS + NTUH
|
||||
nnunet_preprocessed: "./nnUNet/preprocessed" # directory for storing pre-processed data (optional)
|
||||
nnunet_raw: "./nnUNet/raw/" # directory for storing formated raw data (optional)
|
||||
nnunet_results: "./nnUNet/results" # directory for storing trained model checkpoints (optional)
|
||||
26
src/check_dicom.py
Normal file
26
src/check_dicom.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import pydicom
|
||||
import os
|
||||
import sys
|
||||
|
||||
filepath = "/mnt/nextcloud/2026/計畫/TSHA_腦腫瘤驗證標記資料/Brain Tumor Label example/1.2.826.0.1.3680043.8.498.16118352232694493510220170548312112804.dcm"
|
||||
|
||||
try:
|
||||
ds = pydicom.dcmread(filepath)
|
||||
print(f"Transfer Syntax: {ds.file_meta.TransferSyntaxUID}")
|
||||
|
||||
try:
|
||||
arr = ds.pixel_array
|
||||
print("Successfully accessed pixel_array")
|
||||
|
||||
# Try converting to uncompressed
|
||||
ds.decompress()
|
||||
print("Successfully decompressed")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error accessing pixel_array or decompressing: {e}")
|
||||
# Check for handlers
|
||||
import pydicom.uids
|
||||
print(f"Available handlers for this syntax: {pydicom.config.pixel_data_handlers}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error reading file: {e}")
|
||||
110
src/inference.py
Normal file
110
src/inference.py
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
import os
|
||||
import shutil
|
||||
|
||||
from monai.apps.nnunet import nnUNetV2Runner
|
||||
|
||||
import subprocess
|
||||
|
||||
DATASET="Dataset2508_CKTarget"
|
||||
YAML ="2508.yaml"
|
||||
|
||||
DATASET="Dataset2602_BraTS-CK"
|
||||
YAML ="2602.yaml"
|
||||
|
||||
DATA_DIR='/mnt/nextcloud/2026/計畫/TSHA_腦腫瘤驗證標記資料/Brain Tumor Label example'
|
||||
|
||||
imagesTs = f'./nnUNet/raw/{DATASET}/imagesTs/'
|
||||
postprocessed = f'./nnUNet/results/{DATASET}/ensemble_predictions_postprocessed'
|
||||
|
||||
OUTPUT_DIR = '/mnt/b4/Public/0'
|
||||
OUTPUT_DIR = '/mnt/nextcloud/2026/計畫/TSHA_腦腫瘤驗證標記資料/標記資料'
|
||||
|
||||
def main():
|
||||
if not os.path.exists(DATA_DIR):
|
||||
print(f"Error: DATA_DIR {DATA_DIR} does not exist.")
|
||||
else:
|
||||
if os.path.exists(imagesTs):
|
||||
shutil.rmtree(imagesTs)
|
||||
os.makedirs(imagesTs)
|
||||
|
||||
print(f"Converting DICOM from {DATA_DIR} to NIfTI in {imagesTs}...")
|
||||
try:
|
||||
# dicom2nifti.convert_directory(DATA_DIR, imagesTs, compression=True, reorient=True)
|
||||
cmd = ["dcm2niix", "-o", imagesTs, "-f", "%n", "-z", "y", DATA_DIR]
|
||||
print(' '.join(cmd))
|
||||
subprocess.run(cmd, check=True)
|
||||
print("Conversion completed successfully.")
|
||||
except subprocess.CalledProcessError:
|
||||
print("dcm2niix failed, likely due to compression. Attempting decompression with gdcmconv...")
|
||||
|
||||
# Create a temporary directory for decompressed files
|
||||
temp_dir = os.path.join(imagesTs, "temp_decompressed")
|
||||
if os.path.exists(temp_dir):
|
||||
shutil.rmtree(temp_dir)
|
||||
os.makedirs(temp_dir)
|
||||
|
||||
try:
|
||||
# Decompress Dicom files
|
||||
# Check for gdcmconv
|
||||
if shutil.which("gdcmconv") is None:
|
||||
raise FileNotFoundError("gdcmconv not found. Please install gdcm-tools (e.g. conda install -c conda-forge gdcm).")
|
||||
|
||||
files_processed = 0
|
||||
for fname in os.listdir(DATA_DIR):
|
||||
fpath = os.path.join(DATA_DIR, fname)
|
||||
if os.path.isfile(fpath):
|
||||
# Attempt validation/decompression
|
||||
subprocess.run(["gdcmconv", "-w", fpath, os.path.join(temp_dir, fname)], check=False)
|
||||
files_processed += 1
|
||||
|
||||
if files_processed == 0:
|
||||
raise Exception("No files found to decompress.")
|
||||
|
||||
print(f"Decompressed {files_processed} files to {temp_dir}")
|
||||
|
||||
# Retry conversion
|
||||
cmd = ["dcm2niix", "-o", imagesTs, "-f", "%n", "-z", "y", temp_dir]
|
||||
print(' '.join(cmd))
|
||||
subprocess.run(cmd, check=True)
|
||||
print("Conversion completed successfully (after decompression).")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Fallback conversion failed: {e}")
|
||||
finally:
|
||||
# Cleanup
|
||||
if os.path.exists(temp_dir):
|
||||
shutil.rmtree(temp_dir)
|
||||
except Exception as e:
|
||||
print(f"Conversion failed: {e}")
|
||||
|
||||
INPUT_LIST = []
|
||||
|
||||
for f in sorted(os.scandir(imagesTs), key=lambda x: x.name):
|
||||
if f.name.endswith(".nii.gz"):
|
||||
if not f.name.endswith("_0000.nii.gz"):
|
||||
new_path = f.path.replace(".nii.gz", "_0000.nii.gz")
|
||||
INPUT_LIST.append(new_path)
|
||||
os.rename(f.path, new_path)
|
||||
print(f.path, new_path)
|
||||
|
||||
runner = nnUNetV2Runner(YAML)
|
||||
|
||||
runner.predict_ensemble_postprocessing()
|
||||
|
||||
for p in INPUT_LIST:
|
||||
basename = os.path.basename(p).replace("_0000.nii.gz", ".nii.gz")
|
||||
preprocessed = os.path.join(f'./nnUNet/results/{DATASET}/ensemble_predictions_postprocessed/', basename)
|
||||
output_file = os.path.join(OUTPUT_DIR, basename)
|
||||
shutil.move(preprocessed, output_file)
|
||||
print(preprocessed, output_file)
|
||||
|
||||
|
||||
# clean up
|
||||
shutil.rmtree(f'./nnUNet/results/{DATASET}/pred_2d', ignore_errors=True)
|
||||
shutil.rmtree(f'./nnUNet/results/{DATASET}/pred_3d_fullres', ignore_errors=True)
|
||||
shutil.rmtree(f'./nnUNet/results/{DATASET}/pred_3d_lowres', ignore_errors=True)
|
||||
shutil.rmtree(f'./nnUNet/results/{DATASET}/ensemble_predictions')
|
||||
shutil.rmtree(f'./nnUNet/results/{DATASET}/ensemble_predictions_postprocessed')
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
5
src/input.yaml
Normal file
5
src/input.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# dataset_name_or_id: 2508 # models trained on NTUH database
|
||||
dataset_name_or_id: 3828 # models trained on BraTS + NTUH
|
||||
nnunet_preprocessed: "./nnUNet/preprocessed" # directory for storing pre-processed data (optional)
|
||||
nnunet_raw: "./nnUNet/raw" # directory for storing formated raw data (optional)
|
||||
nnunet_results: "./nnUNet/results" # directory for storing trained model checkpoints (optional)
|
||||
7
src/install_model.sh
Normal file
7
src/install_model.sh
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
SCRIPT_PATH="$(dirname "$(readlink -f "$0")")"
|
||||
|
||||
export nnUNet_preprocessed=./nnUNet/preprocessed
|
||||
export nnUNet_results=./nnUNet/results
|
||||
export nnUNet_raw=./nnUNet/rawy
|
||||
#nnUNetv2_install_pretrained_model_from_zip $SCRIPT_PATH/3828.zip
|
||||
nnUNetv2_install_pretrained_model_from_zip $SCRIPT_PATH/2602.zip
|
||||
1
src/nnUNet
Symbolic link
1
src/nnUNet
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
/mnt/b4/Public/nnUNet/
|
||||
Loading…
Reference in a new issue