0
# I/O Operations
1
2
Comprehensive file format support for reading and writing medical images, meshes, transforms, and metadata with automatic format detection, extensive codec support, and preservation of spatial and temporal information. ITK provides high-level convenience functions and detailed control over I/O operations for research and clinical applications.
3
4
## Capabilities
5
6
### High-Level I/O Functions
7
8
Convenient functions for common I/O operations with automatic format detection and sensible defaults.
9
10
```python { .api }
11
# Image I/O
12
def imread(filename: str, pixel_type=None, fallback_only: bool = False) -> Image:
13
"""
14
Read image from file with automatic format detection.
15
16
Parameters:
17
- filename: Path to image file
18
- pixel_type: Override automatic pixel type detection (e.g., itk.F, itk.UC)
19
- fallback_only: Use only fallback I/O (for unsupported formats)
20
21
Returns:
22
- ITK Image object with preserved metadata
23
24
Supported formats: DICOM, NIFTI, Analyze, MetaImage, NRRD, VTK, PNG, JPEG, TIFF, BMP, GE, Siemens, and many more
25
"""
26
27
def imwrite(image: Image, filename: str, compression: bool = False,
28
use_streaming: bool = False, compression_level: int = None) -> None:
29
"""
30
Write image to file with format determined by extension.
31
32
Parameters:
33
- image: ITK Image to write
34
- filename: Output file path (extension determines format)
35
- compression: Enable compression (format-dependent)
36
- use_streaming: Enable streaming for large images
37
- compression_level: Compression level (0-9 for some formats)
38
"""
39
40
# Mesh I/O
41
def meshread(filename: str) -> Mesh:
42
"""
43
Read mesh from file.
44
45
Parameters:
46
- filename: Path to mesh file
47
48
Returns:
49
- ITK Mesh object
50
51
Supported formats: VTK, STL, PLY, OBJ, OFF, BYU
52
"""
53
54
def meshwrite(mesh: Mesh, filename: str, binary: bool = True) -> None:
55
"""
56
Write mesh to file.
57
58
Parameters:
59
- mesh: ITK Mesh to write
60
- filename: Output file path
61
- binary: Use binary format when available
62
"""
63
64
# Transform I/O
65
def transformread(filename: str) -> Transform:
66
"""Read spatial transform from file."""
67
68
def transformwrite(transform: Transform, filename: str) -> None:
69
"""Write spatial transform to file."""
70
```
71
72
### Medical Image Formats
73
74
Specialized support for medical imaging formats with metadata preservation.
75
76
```python { .api }
77
# DICOM support
78
class GDCMImageIO:
79
"""
80
DICOM image I/O using GDCM library.
81
"""
82
def SetLoadSequences(self, load: bool) -> None: ...
83
def SetLoadPrivateTags(self, load: bool) -> None: ...
84
def SetKeepOriginalUID(self, keep: bool) -> None: ...
85
def SetUIDPrefix(self, prefix: str) -> None: ...
86
def SetStudyInstanceUID(self, uid: str) -> None: ...
87
def SetSeriesInstanceUID(self, uid: str) -> None: ...
88
def SetFrameOfReferenceInstanceUID(self, uid: str) -> None: ...
89
90
# Metadata access
91
def GetPatientName(self) -> str: ...
92
def GetPatientID(self) -> str: ...
93
def GetPatientSex(self) -> str: ...
94
def GetPatientAge(self) -> str: ...
95
def GetStudyID(self) -> str: ...
96
def GetStudyDescription(self) -> str: ...
97
def GetSeriesDescription(self) -> str: ...
98
def GetModality(self) -> str: ...
99
def GetManufacturer(self) -> str: ...
100
def GetInstitution(self) -> str: ...
101
def GetPixelSpacing(self) -> tuple[float, float]: ...
102
def GetSliceThickness(self) -> float: ...
103
def GetRescaleSlope(self) -> float: ...
104
def GetRescaleIntercept(self) -> float: ...
105
106
# NIFTI support
107
class NiftiImageIO:
108
"""
109
NIFTI-1/NIFTI-2 neuroimaging format support.
110
"""
111
def SetLegacyAnalyze75Mode(self, mode: bool) -> None: ...
112
def GetLegacyAnalyze75Mode(self) -> bool: ...
113
def GetQFormCodeName(self) -> str: ...
114
def GetSFormCodeName(self) -> str: ...
115
def GetNiftiImageOrientation(self) -> str: ...
116
117
# MetaImage support
118
class MetaImageIO:
119
"""
120
MetaImage format with extensive metadata support.
121
"""
122
def GetDefaultDoublePrecision(self) -> int: ...
123
def SetDefaultDoublePrecision(self, precision: int) -> None: ...
124
def SetDataFileName(self, filename: str) -> None: ...
125
126
# NRRD support
127
class NrrdImageIO:
128
"""
129
Nearly Raw Raster Data format support.
130
"""
131
def SetFileType(self, file_type: int) -> None: ...
132
def GetFileType(self) -> int: ...
133
```
134
135
### Image Series I/O
136
137
Reading and writing image series and time-varying datasets.
138
139
```python { .api }
140
# DICOM series
141
class GDCMSeriesFileNames:
142
"""
143
Generate filenames for DICOM series reading.
144
"""
145
def SetDirectory(self, directory: str) -> None: ...
146
def SetUseSeriesDetails(self, use: bool) -> None: ...
147
def SetRecursive(self, recursive: bool) -> None: ...
148
def GetSeriesUIDs(self) -> list[str]: ...
149
def GetFileNames(self, series_uid: str) -> list[str]: ...
150
def GetSeriesDescription(self, series_uid: str) -> str: ...
151
152
class ImageSeriesReader[TOutputImage]:
153
"""
154
Read image series into volume.
155
"""
156
def SetFileNames(self, filenames: list[str]) -> None: ...
157
def SetImageIO(self, io: ImageIOBase) -> None: ...
158
def SetMetaDataDictionaryArrayUpdate(self, update: bool) -> None: ...
159
def GetOutput(self) -> TOutputImage: ...
160
def GetMetaDataDictionaryArray(self) -> list[MetaDataDictionary]: ...
161
162
class ImageSeriesWriter[TInputImage]:
163
"""
164
Write volume as image series.
165
"""
166
def SetInput(self, image: TInputImage) -> None: ...
167
def SetFileNames(self, filenames: list[str]) -> None: ...
168
def SetImageIO(self, io: ImageIOBase) -> None: ...
169
def SetMetaDataDictionaryArray(self, array: list[MetaDataDictionary]) -> None: ...
170
def Write(self) -> None: ...
171
172
# Numeric series (for time series data)
173
class NumericSeriesFileNames:
174
"""Generate filenames for numeric series."""
175
def SetSeriesFormat(self, format: str) -> None: ...
176
def SetStartIndex(self, start: int) -> None: ...
177
def SetEndIndex(self, end: int) -> None: ...
178
def SetIncrementIndex(self, increment: int) -> None: ...
179
def GetFileNames(self) -> list[str]: ...
180
```
181
182
### Format-Specific Readers and Writers
183
184
Detailed control over specific file formats and their parameters.
185
186
```python { .api }
187
# Generic image file reader
188
class ImageFileReader[TOutputImage]:
189
"""
190
Generic image file reader with format auto-detection.
191
"""
192
def SetFileName(self, filename: str) -> None: ...
193
def GetFileName(self) -> str: ...
194
def SetImageIO(self, io: ImageIOBase) -> None: ...
195
def GetImageIO(self) -> ImageIOBase: ...
196
def SetGlobalWarningDisplay(self, display: bool) -> None: ...
197
def GetOutput(self) -> TOutputImage: ...
198
def GetMetaDataDictionary(self) -> MetaDataDictionary: ...
199
def Update(self) -> None: ...
200
201
# Generic image file writer
202
class ImageFileWriter[TInputImage]:
203
"""
204
Generic image file writer with format auto-detection.
205
"""
206
def SetFileName(self, filename: str) -> None: ...
207
def GetFileName(self) -> str: ...
208
def SetInput(self, image: TInputImage) -> None: ...
209
def SetImageIO(self, io: ImageIOBase) -> None: ...
210
def GetImageIO(self) -> ImageIOBase: ...
211
def SetUseCompression(self, compression: bool) -> None: ...
212
def GetUseCompression(self) -> bool: ...
213
def SetUseInputMetaDataDictionary(self, use: bool) -> None: ...
214
def Write(self) -> None: ...
215
216
# PNG-specific I/O
217
class PNGImageIO:
218
"""PNG format with compression control."""
219
def SetCompressionLevel(self, level: int) -> None: ...
220
def GetCompressionLevel(self) -> int: ...
221
222
# JPEG-specific I/O
223
class JPEGImageIO:
224
"""JPEG format with quality control."""
225
def SetQuality(self, quality: int) -> None: ... # 0-100
226
def GetQuality(self) -> int: ...
227
def SetProgressive(self, progressive: bool) -> None: ...
228
229
# TIFF-specific I/O
230
class TIFFImageIO:
231
"""TIFF format with compression options."""
232
def SetCompression(self, compression: int) -> None: ...
233
def GetCompression(self) -> int: ...
234
# Compression types: NoCompression, PackBits, JPEG, Deflate, LZW
235
```
236
237
### Streaming I/O
238
239
Efficient handling of large datasets that don't fit in memory.
240
241
```python { .api }
242
class StreamingImageFilter[TInputImage, TOutputImage]:
243
"""
244
Stream large images through processing pipeline.
245
"""
246
def SetNumberOfStreamDivisions(self, divisions: int) -> None: ...
247
def GetNumberOfStreamDivisions(self) -> int: ...
248
249
class ImageFileReader[TOutputImage]:
250
"""Extended reader with streaming support."""
251
def SetUseStreaming(self, streaming: bool) -> None: ...
252
def GetUseStreaming(self) -> bool: ...
253
254
class ImageFileWriter[TInputImage]:
255
"""Extended writer with streaming support."""
256
def SetUseStreaming(self, streaming: bool) -> None: ...
257
def GetUseStreaming(self) -> bool: ...
258
def SetNumberOfStreamDivisions(self, divisions: int) -> None: ...
259
```
260
261
### Metadata Handling
262
263
Access and manipulation of image metadata and DICOM tags.
264
265
```python { .api }
266
class MetaDataDictionary:
267
"""
268
Container for image metadata.
269
"""
270
def HasKey(self, key: str) -> bool: ...
271
def GetKeys(self) -> list[str]: ...
272
def Get(self, key: str) -> MetaDataObjectBase: ...
273
def Set(self, key: str, value: MetaDataObjectBase) -> None: ...
274
275
# DICOM metadata access
276
def get_dicom_tag_value(image: Image, tag: str) -> str:
277
"""
278
Extract DICOM tag value from image metadata.
279
280
Parameters:
281
- image: ITK Image with DICOM metadata
282
- tag: DICOM tag in format "group|element" (e.g., "0010|0010" for patient name)
283
284
Returns:
285
- Tag value as string
286
"""
287
288
def set_dicom_tag_value(image: Image, tag: str, value: str) -> None:
289
"""Set DICOM tag value in image metadata."""
290
```
291
292
## Usage Examples
293
294
### Basic File I/O Operations
295
296
```python
297
import itk
298
299
# Simple image reading and writing
300
image = itk.imread('input.nii.gz')
301
processed_image = itk.median_image_filter(image, radius=2)
302
itk.imwrite(processed_image, 'output.nii.gz', compression=True)
303
304
# Read with specific pixel type
305
float_image = itk.imread('data.mhd', pixel_type=itk.F)
306
307
# Mesh I/O
308
mesh = itk.meshread('surface.vtk')
309
processed_mesh = itk.smooth_mesh_filter(mesh, iterations=10)
310
itk.meshwrite(processed_mesh, 'smoothed_surface.stl', binary=True)
311
```
312
313
### DICOM Series Processing
314
315
```python
316
import itk
317
import os
318
319
def read_dicom_series(directory_path):
320
"""Read DICOM series from directory."""
321
322
# Generate file names for DICOM series
323
series_file_names = itk.GDCMSeriesFileNames.New()
324
series_file_names.SetDirectory(directory_path)
325
series_file_names.SetUseSeriesDetails(True)
326
series_file_names.SetRecursive(False)
327
328
# Get all series UIDs in directory
329
series_uids = series_file_names.GetSeriesUIDs()
330
print(f"Found {len(series_uids)} DICOM series")
331
332
images = []
333
for series_uid in series_uids:
334
print(f"Reading series: {series_uid}")
335
336
# Get file names for this series
337
file_names = series_file_names.GetFileNames(series_uid)
338
series_description = series_file_names.GetSeriesDescription(series_uid)
339
print(f" Description: {series_description}")
340
print(f" Number of files: {len(file_names)}")
341
342
# Read series
343
reader = itk.ImageSeriesReader[itk.Image[itk.SS, 3]].New()
344
reader.SetFileNames(file_names)
345
reader.SetImageIO(itk.GDCMImageIO.New())
346
reader.Update()
347
348
image = reader.GetOutput()
349
images.append((series_uid, series_description, image))
350
351
# Access metadata
352
meta_dict = reader.GetMetaDataDictionaryArray()[0] # First slice metadata
353
print(f" Image size: {image.GetLargestPossibleRegion().GetSize()}")
354
print(f" Pixel spacing: {image.GetSpacing()}")
355
356
return images
357
358
# Usage
359
dicom_images = read_dicom_series('/path/to/dicom/directory')
360
361
# Process first series
362
if dicom_images:
363
series_uid, description, image = dicom_images[0]
364
365
# Convert to float for processing
366
float_image = itk.cast_image_filter(image, itk.Image[itk.F, 3])
367
368
# Apply processing
369
filtered = itk.gaussian_blur_image_filter(float_image, variance=1.0)
370
371
# Save as NIFTI
372
itk.imwrite(filtered, f'{description.replace(" ", "_")}.nii.gz')
373
```
374
375
### DICOM Metadata Extraction
376
377
```python
378
import itk
379
380
def extract_dicom_metadata(dicom_file):
381
"""Extract comprehensive DICOM metadata."""
382
383
# Read DICOM file
384
reader = itk.ImageFileReader[itk.Image[itk.SS, 3]].New()
385
reader.SetFileName(dicom_file)
386
reader.SetImageIO(itk.GDCMImageIO.New())
387
reader.Update()
388
389
image = reader.GetOutput()
390
io = reader.GetImageIO()
391
392
# Patient information
393
metadata = {
394
'patient_name': io.GetPatientName(),
395
'patient_id': io.GetPatientID(),
396
'patient_age': io.GetPatientAge(),
397
'patient_sex': io.GetPatientSex(),
398
399
# Study information
400
'study_id': io.GetStudyID(),
401
'study_description': io.GetStudyDescription(),
402
'series_description': io.GetSeriesDescription(),
403
404
# Acquisition parameters
405
'modality': io.GetModality(),
406
'manufacturer': io.GetManufacturer(),
407
'institution': io.GetInstitution(),
408
409
# Image parameters
410
'pixel_spacing': io.GetPixelSpacing(),
411
'slice_thickness': io.GetSliceThickness(),
412
'rescale_slope': io.GetRescaleSlope(),
413
'rescale_intercept': io.GetRescaleIntercept(),
414
415
# Image properties
416
'dimensions': image.GetLargestPossibleRegion().GetSize(),
417
'origin': image.GetOrigin(),
418
'direction': image.GetDirection()
419
}
420
421
return metadata, image
422
423
# Usage
424
metadata, image = extract_dicom_metadata('patient_scan.dcm')
425
print(f"Patient: {metadata['patient_name']}")
426
print(f"Study: {metadata['study_description']}")
427
print(f"Modality: {metadata['modality']}")
428
print(f"Image size: {metadata['dimensions']}")
429
```
430
431
### Multi-Format Batch Processing
432
433
```python
434
import itk
435
import os
436
import glob
437
438
def batch_convert_images(input_directory, output_directory,
439
input_pattern="*.dcm", output_format="nii.gz",
440
processing_function=None):
441
"""
442
Batch convert images between formats with optional processing.
443
"""
444
445
# Create output directory
446
os.makedirs(output_directory, exist_ok=True)
447
448
# Find input files
449
input_files = glob.glob(os.path.join(input_directory, input_pattern))
450
print(f"Found {len(input_files)} files to process")
451
452
for input_file in input_files:
453
try:
454
print(f"Processing: {os.path.basename(input_file)}")
455
456
# Read image
457
image = itk.imread(input_file)
458
459
# Apply processing if specified
460
if processing_function:
461
image = processing_function(image)
462
463
# Generate output filename
464
base_name = os.path.splitext(os.path.basename(input_file))[0]
465
output_file = os.path.join(output_directory, f"{base_name}.{output_format}")
466
467
# Write image
468
itk.imwrite(image, output_file, compression=True)
469
print(f" Saved: {os.path.basename(output_file)}")
470
471
except Exception as e:
472
print(f" Error processing {input_file}: {e}")
473
474
# Example processing function
475
def enhance_contrast(image):
476
"""Example processing: enhance contrast using histogram equalization."""
477
# Convert to float
478
float_image = itk.cast_image_filter(image, itk.Image[itk.F, 3])
479
480
# Apply histogram equalization
481
enhanced = itk.adaptive_histogram_equalization_image_filter(
482
float_image,
483
radius=[5, 5, 1] # 2D enhancement for each slice
484
)
485
486
# Convert back to original type
487
result = itk.cast_image_filter(enhanced, type(image))
488
return result
489
490
# Usage
491
batch_convert_images(
492
input_directory='/path/to/dicom/files',
493
output_directory='/path/to/nifti/output',
494
input_pattern='*.dcm',
495
output_format='nii.gz',
496
processing_function=enhance_contrast
497
)
498
```
499
500
### Large Image Streaming
501
502
```python
503
import itk
504
505
def process_large_image_streaming(input_file, output_file,
506
processing_filter, num_divisions=10):
507
"""
508
Process large image using streaming to manage memory usage.
509
"""
510
511
# Set up streaming reader
512
reader = itk.ImageFileReader[itk.Image[itk.F, 3]].New()
513
reader.SetFileName(input_file)
514
reader.SetUseStreaming(True)
515
516
# Set up processing filter
517
processing_filter.SetInput(reader.GetOutput())
518
519
# Set up streaming writer
520
writer = itk.ImageFileWriter[itk.Image[itk.F, 3]].New()
521
writer.SetFileName(output_file)
522
writer.SetInput(processing_filter.GetOutput())
523
writer.SetUseStreaming(True)
524
writer.SetNumberOfStreamDivisions(num_divisions)
525
526
# Process image in streams
527
print(f"Processing {input_file} using {num_divisions} stream divisions...")
528
writer.Write()
529
print(f"Saved processed image to {output_file}")
530
531
# Example: Apply Gaussian smoothing to large image
532
large_image_file = 'very_large_image.nii.gz'
533
output_file = 'smoothed_large_image.nii.gz'
534
535
# Create Gaussian filter
536
gaussian_filter = itk.GaussianImageFilter[itk.Image[itk.F, 3], itk.Image[itk.F, 3]].New()
537
gaussian_filter.SetVariance(2.0)
538
539
# Process with streaming
540
process_large_image_streaming(
541
large_image_file,
542
output_file,
543
gaussian_filter,
544
num_divisions=20
545
)
546
```
547
548
### Format-Specific Optimizations
549
550
```python
551
import itk
552
553
def save_with_format_optimization(image, filename):
554
"""Save image with format-specific optimizations."""
555
556
file_extension = filename.lower().split('.')[-1]
557
558
if file_extension == 'png':
559
# PNG: Use compression
560
writer = itk.ImageFileWriter[type(image)].New()
561
writer.SetFileName(filename)
562
writer.SetInput(image)
563
564
png_io = itk.PNGImageIO.New()
565
png_io.SetCompressionLevel(9) # Maximum compression
566
writer.SetImageIO(png_io)
567
writer.Write()
568
569
elif file_extension == 'jpg' or file_extension == 'jpeg':
570
# JPEG: Set quality
571
writer = itk.ImageFileWriter[type(image)].New()
572
writer.SetFileName(filename)
573
writer.SetInput(image)
574
575
jpeg_io = itk.JPEGImageIO.New()
576
jpeg_io.SetQuality(95) # High quality
577
jpeg_io.SetProgressive(False)
578
writer.SetImageIO(jpeg_io)
579
writer.Write()
580
581
elif file_extension == 'tif' or file_extension == 'tiff':
582
# TIFF: Use LZW compression
583
writer = itk.ImageFileWriter[type(image)].New()
584
writer.SetFileName(filename)
585
writer.SetInput(image)
586
587
tiff_io = itk.TIFFImageIO.New()
588
tiff_io.SetCompression(itk.TIFFImageIO.LZW)
589
writer.SetImageIO(tiff_io)
590
writer.Write()
591
592
else:
593
# Default: Use generic writer with compression
594
itk.imwrite(image, filename, compression=True)
595
596
# Usage
597
image = itk.imread('input.nii.gz')
598
save_with_format_optimization(image, 'optimized_output.png')
599
```