Dicom Reorganizer
Overview
The provided code is a Rust library that is designed to work with Python using the pyo3
crate, which allows Rust code to be called from Python. The purpose of this code is to reorganize DICOM files based on information provided in a CSV file.
Requirements: [Source]
-
The code requires the following Rust crates:
pyo3
: Enables integration with Python.rayon
: Provides parallelism for faster processing.csv
: Allows reading CSV files.-
anyhow
: Helps with error handling.
-
It expects a CSV file containing the following columns:
subject_name
: Represents the subject or patient name.session_date
: Represents the date of the session.dicom_type
: Represents the type of DICOM file (e.g., anat, func, etc).current_path
: Represents the current file path of the DICOM file.
Info
I build a tool to extract all tags (alongside path) of every disom in a given dataset that can be used to build the needed csv file for this step. You can find more information if you look at Dicom Metadata Extractor
Functionality: [Source]
The code defines a Python function reorganize_dicoms
that takes the following arguments:
csv_path
(String): The path to the CSV file containing the DICOM file information.root_name
(String): The root directory name where the reorganized files will be stored.columns
(PyDict): A Python dictionary containing the column names forsubject_name
,session_date
,dicom_type
, andcurrent_path
.-
copy_files
(Option): An optional boolean flag indicating whether to copy or move the files. If not provided, it defaults to true
(copy).#[pyfunction] fn reorganize_dicoms( csv_path: String, root_name: String, columns: &PyDict, copy_files: Option<bool> ) -> PyResult<()> { let subject_name_column = columns.get_item("subject_name").unwrap().extract::<&str>().unwrap(); let session_date_column = columns.get_item("session_date").unwrap().extract::<&str>().unwrap(); let dicom_type_column = columns.get_item("dicom_type").unwrap().extract::<&str>().unwrap(); let current_path_column = columns.get_item("current_path").unwrap().extract::<&str>().unwrap(); let should_copy = copy_files.unwrap_or(true); // Default to true if not specified let mut rdr = ReaderBuilder::new().from_path(csv_path).unwrap(); let headers = rdr.headers().unwrap().clone(); rdr.records().par_bridge().for_each(|result| { let record = result.unwrap(); let subject_name = record.get(headers.iter().position(|h| h == subject_name_column).unwrap()).unwrap(); let session_date = record.get(headers.iter().position(|h| h == session_date_column).unwrap()).unwrap(); let dicom_type = record.get(headers.iter().position(|h| h == dicom_type_column).unwrap()).unwrap(); let current_path = record.get(headers.iter().position(|h| h == current_path_column).unwrap()).unwrap(); // Add 'sub-' and 'ses-' prefixes let new_path = format!("{}/sub-{}/ses-{}/{}/", root_name, subject_name, session_date, dicom_type); fs::create_dir_all(&new_path).unwrap(); // Option to copy or move let destination_path = Path::new(&new_path).join(Path::new(current_path).file_name().unwrap()); if should_copy { copy(current_path, &destination_path).unwrap(); } else { fs::rename(current_path, destination_path).unwrap(); } }); Ok(()) }
The function performs the following steps:
- Reads the CSV file using the
csv
crate. - Iterates over each record (row) in the CSV file in parallel using
rayon
. - For each record:
- Extracts the values for
subject_name
,session_date
,dicom_type
, andcurrent_path
. - Constructs a new path following the BIDS format:
{root_name}/sub-{subject_name}/ses-{session_date}/{dicom_type}/
. - Creates the necessary directories for the new path.
- Determines whether to copy or move the file based on the
copy_files
flag. - Copies or moves the DICOM file to the new path, preserving the original file name.
- Extracts the values for
Integration with Python: [Source]
The #[pymodule]
section defines a Rust module named dicom_reorganizer
that can be imported and used in Python. It adds the reorganize_dicoms
function to the module, allowing it to be called from Python.
#[pymodule]
fn dicom_reorganizer(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(reorganize_dicoms, m)?)?;
Ok(())
}
To use this code in Python, you would need to:
- Compile the Rust code into a Python package or library.
- Import the
dicom_reorganizer
module in your Python code. - Call the
reorganize_dicoms
function, providing the required arguments.
These stepd explained throughly in the next section.