Chapter 2: DICOS I/O Functions
In Chapter 1: DICOS Data Types (CT, DX, TDR), we learned about the different types of security scanning data that pyDICOS helps us manage. Now, let’s explore how to easily read and write these DICOS files without worrying about their specific types.
The Problem: Working with Different File Types
Imagine you’re working at an airport where different scanning machines produce various file types. Some produce CT scans, others X-ray images, and you also receive threat detection reports. Without pyDICOS, you’d need to:
- Figure out what type of file you’re dealing with
- Choose the correct loader for that file type
- Use that specific loader to open the file
That’s a lot of work just to open a file! This is where pyDICOS I/O functions come to the rescue.
Universal File Handlers: dcsread
and dcswrite
pyDICOS provides two simple functions that handle all the complexity for you:
dcsread
: Reads any DICOS file and automatically figures out its typedcswrite
: Saves any DICOS object to disk
Think of these as your “universal remote controls” for DICOS files - one tool that works with all types.
Reading DICOS Files with dcsread
The dcsread
function is like a smart assistant that:
- Examines a file
- Determines if it’s CT, DX, or TDR
- Uses the appropriate loader
- Returns the loaded object
Here’s a simple example:
from pydicos import dcsread
import matplotlib.pyplot as plt
# Let dcsread figure out the file type automatically
scan = dcsread("security_scan.dcs")
# Check what type of scan we got
if hasattr(scan, 'get_volume_data'):
# It's a CT scan
volume = scan.get_volume_data()
plt.imshow(volume[0][50], cmap='gray') # Show slice 50
plt.title("CT Slice")
elif hasattr(scan, 'get_image_data'):
# It's a DX (X-ray) scan
image = scan.get_image_data()
plt.imshow(image, cmap='gray')
plt.title("X-ray Image")
else:
# It's a TDR (threat report)
print("Detected threats:", len(scan.get_data()["PTOs"]))
plt.show()
In this example, we didn’t need to know what type of file we were opening beforehand. The dcsread
function figured it out and returned the appropriate object, which we could then work with.
Writing DICOS Files with dcswrite
Saving DICOS objects is just as easy with dcswrite
. No matter what type of DICOS object you have, this function saves it to disk:
from pydicos import dcsread, dcswrite
import numpy as np
# Read an existing CT scan
ct_scan = dcsread("baggage_scan.ct")
# Modify some data (for example, adding a filter)
volume_data = ct_scan.get_volume_data()
filtered_data = np.clip(volume_data * 1.2, 0, 65535) # Brighten and clip
ct_scan.set_volume_data(filtered_data)
# Save the modified scan
dcswrite(ct_scan, "enhanced_baggage_scan.ct")
print("Modified scan saved successfully!")
In this example, we:
- Read a CT scan
- Applied a simple brightness adjustment
- Saved it to a new file using
dcswrite
A Complete Example: Processing Different File Types
Let’s see a more practical example where we need to process a folder of different DICOS files:
from pydicos import dcsread, dcswrite
import os
import matplotlib.pyplot as plt
# Process all DICOS files in a directory
scan_directory = "security_scans/"
for filename in os.listdir(scan_directory):
if filename.endswith((".ct", ".dx", ".tdr")):
file_path = os.path.join(scan_directory, filename)
try:
# Let dcsread handle the file type automatically
scan = dcsread(file_path)
# Create a filename for the processed output
output_path = os.path.join(scan_directory, "processed_" + filename)
# Process based on type (simplified example)
if hasattr(scan, 'get_volume_data'):
print(f"Processing CT scan: {filename}")
# Save with a different filename
dcswrite(scan, output_path)
elif hasattr(scan, 'get_image_data'):
print(f"Processing X-ray image: {filename}")
# Save with a different filename
dcswrite(scan, output_path)
else:
print(f"Found threat report: {filename}")
# Just copy the TDR file
dcswrite(scan, output_path)
except Exception as e:
print(f"Error processing {filename}: {e}")
This script processes a whole directory of different DICOS files, and we never have to worry about their specific types!
Under the Hood: How DICOS I/O Functions Work
Let’s peek behind the curtain to understand how these functions work:
sequenceDiagram
participant User as Your Code
participant IOFunc as dcsread
participant Loaders as CT/DX/TDR Loaders
participant File as DICOS File
participant Object as DICOS Object
User->>IOFunc: dcsread("scan.dcs")
IOFunc->>Loaders: Try CTLoader
Loaders->>File: Try to read file
alt If CT file works
File-->>Loaders: Success
Loaders-->>IOFunc: Return CT object
else If CT fails
File-->>Loaders: Error
IOFunc->>Loaders: Try DXLoader
Loaders->>File: Try to read file
alt If DX file works
File-->>Loaders: Success
Loaders-->>IOFunc: Return DX object
else If DX fails
File-->>Loaders: Error
IOFunc->>Loaders: Try TDRLoader
Loaders->>File: Try to read file
alt If TDR file works
File-->>Loaders: Success
Loaders-->>IOFunc: Return TDR object
else If everything fails
File-->>Loaders: Error
Loaders-->>IOFunc: Error
IOFunc-->>User: Raise ValueError
end
end
end
IOFunc-->>User: Return appropriate object
When you call dcsread
, it tries each loader (CT, DX, TDR) one after another until one succeeds. It’s like trying different keys until one unlocks the door.
If we look at the actual implementation in pydicos/_dicosio.py
:
def dcsread(
filename: Union[str, Path],
dcs: Optional[Union[CTLoader, DXLoader, TDRLoader]] = None
) -> Union[CTLoader, DXLoader, TDRLoader]:
"""Read a DICOS file."""
if dcs is not None:
dcs.read(str(filename))
return dcs
for DCSLoader in [CTLoader, DXLoader, TDRLoader]:
try:
dcs_loader = DCSLoader()
dcs_loader.read(str(filename))
return dcs_loader
except:
logging.debug(f"Loading failed with {DCSLoader}")
pass
raise ValueError(f"Invalid DICOS file: {filename}")
You can see the function:
- First checks if you provided a specific loader (
dcs
parameter) - If not, it tries each loader in sequence (CT, DX, TDR)
- Returns the first one that works
- If all fail, it raises an error
Similarly, dcswrite
is straightforward - it just calls the write
method on whichever DICOS object you give it:
def dcswrite(dcs: Union[CTLoader, DXLoader, TDRLoader], filename: Union[str, Path]):
"""Write a DICOS file."""
dcs.write(str(filename))
Advanced Usage: Pre-specifying the File Type
Sometimes you already know what type of file you’re working with. In these cases, you can provide a pre-created loader to dcsread
:
from pydicos import dcsread, CTLoader
# Create a CT loader specifically
ct_loader = CTLoader()
# Use it with dcsread (this skips trying the other loaders)
scan = dcsread("baggage_scan.ct", dcs=ct_loader)
# Now work with the CT data
volume = scan.get_volume_data()
This approach is slightly more efficient since dcsread
doesn’t have to try different loaders, but it’s only useful when you’re certain about the file type.
Common Pitfalls and Solutions
Handling Unsupported Files
Sometimes you might try to read a file that isn’t a valid DICOS file. Let’s handle this gracefully:
from pydicos import dcsread
import os
def safe_read_dicos(filepath):
try:
return dcsread(filepath)
except ValueError as e:
print(f"Error: {filepath} is not a valid DICOS file")
return None
except Exception as e:
print(f"Unexpected error reading {filepath}: {e}")
return None
# Example usage
scans_folder = "mixed_files/"
for filename in os.listdir(scans_folder):
filepath = os.path.join(scans_folder, filename)
scan = safe_read_dicos(filepath)
if scan:
print(f"Successfully loaded {filename}")
# Process the scan...
This wrapper function gives you a safe way to try reading files that might not be valid DICOS files.
Summary
In this chapter, we learned about pyDICOS I/O functions:
dcsread
: A universal function that automatically detects and reads any DICOS file typedcswrite
: A simple function to save any DICOS object to disk
These functions hide all the complexity of working with different DICOS file formats, allowing you to focus on your actual work rather than file handling details.
In the next chapter, Network Communication, we’ll explore how pyDICOS helps you transmit DICOS data over networks, which is essential for integrated security screening systems where machines need to share scan information.
Generated by AI Codebase Knowledge Builder