extract_metadata.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #!/usr/bin/env python3
  2. """
  3. Extract and display DICOM metadata in a readable format.
  4. Usage:
  5. python extract_metadata.py file.dcm
  6. python extract_metadata.py file.dcm --output metadata.txt
  7. python extract_metadata.py file.dcm --format json --output metadata.json
  8. """
  9. import argparse
  10. import sys
  11. import json
  12. from pathlib import Path
  13. try:
  14. import pydicom
  15. except ImportError:
  16. print("Error: pydicom is not installed. Install it with: pip install pydicom")
  17. sys.exit(1)
  18. def format_value(value):
  19. """Format DICOM values for display."""
  20. if isinstance(value, bytes):
  21. try:
  22. return value.decode('utf-8', errors='ignore')
  23. except:
  24. return str(value)
  25. elif isinstance(value, pydicom.multival.MultiValue):
  26. return ', '.join(str(v) for v in value)
  27. elif isinstance(value, pydicom.sequence.Sequence):
  28. return f"Sequence with {len(value)} item(s)"
  29. else:
  30. return str(value)
  31. def extract_metadata_text(ds, show_sequences=False):
  32. """Extract metadata as formatted text."""
  33. lines = []
  34. lines.append("=" * 80)
  35. lines.append("DICOM Metadata")
  36. lines.append("=" * 80)
  37. # File Meta Information
  38. if hasattr(ds, 'file_meta'):
  39. lines.append("\n[File Meta Information]")
  40. for elem in ds.file_meta:
  41. lines.append(f"{elem.name:40s} {format_value(elem.value)}")
  42. # Patient Information
  43. lines.append("\n[Patient Information]")
  44. patient_tags = ['PatientName', 'PatientID', 'PatientBirthDate',
  45. 'PatientSex', 'PatientAge', 'PatientWeight']
  46. for tag in patient_tags:
  47. if hasattr(ds, tag):
  48. value = getattr(ds, tag)
  49. lines.append(f"{tag:40s} {format_value(value)}")
  50. # Study Information
  51. lines.append("\n[Study Information]")
  52. study_tags = ['StudyInstanceUID', 'StudyDate', 'StudyTime',
  53. 'StudyDescription', 'AccessionNumber', 'StudyID']
  54. for tag in study_tags:
  55. if hasattr(ds, tag):
  56. value = getattr(ds, tag)
  57. lines.append(f"{tag:40s} {format_value(value)}")
  58. # Series Information
  59. lines.append("\n[Series Information]")
  60. series_tags = ['SeriesInstanceUID', 'SeriesNumber', 'SeriesDescription',
  61. 'Modality', 'SeriesDate', 'SeriesTime']
  62. for tag in series_tags:
  63. if hasattr(ds, tag):
  64. value = getattr(ds, tag)
  65. lines.append(f"{tag:40s} {format_value(value)}")
  66. # Image Information
  67. lines.append("\n[Image Information]")
  68. image_tags = ['SOPInstanceUID', 'InstanceNumber', 'ImageType',
  69. 'Rows', 'Columns', 'BitsAllocated', 'BitsStored',
  70. 'PhotometricInterpretation', 'SamplesPerPixel',
  71. 'PixelSpacing', 'SliceThickness', 'ImagePositionPatient',
  72. 'ImageOrientationPatient', 'WindowCenter', 'WindowWidth']
  73. for tag in image_tags:
  74. if hasattr(ds, tag):
  75. value = getattr(ds, tag)
  76. lines.append(f"{tag:40s} {format_value(value)}")
  77. # All other elements
  78. if show_sequences:
  79. lines.append("\n[All Elements]")
  80. for elem in ds:
  81. if elem.VR != 'SQ': # Skip sequences for brevity
  82. lines.append(f"{elem.name:40s} {format_value(elem.value)}")
  83. else:
  84. lines.append(f"{elem.name:40s} {format_value(elem.value)}")
  85. return '\n'.join(lines)
  86. def extract_metadata_json(ds):
  87. """Extract metadata as JSON."""
  88. metadata = {}
  89. # File Meta Information
  90. if hasattr(ds, 'file_meta'):
  91. metadata['file_meta'] = {}
  92. for elem in ds.file_meta:
  93. metadata['file_meta'][elem.keyword] = format_value(elem.value)
  94. # All data elements (excluding sequences for simplicity)
  95. metadata['dataset'] = {}
  96. for elem in ds:
  97. if elem.VR != 'SQ':
  98. metadata['dataset'][elem.keyword] = format_value(elem.value)
  99. return json.dumps(metadata, indent=2)
  100. def main():
  101. parser = argparse.ArgumentParser(
  102. description='Extract and display DICOM metadata',
  103. formatter_class=argparse.RawDescriptionHelpFormatter,
  104. epilog="""
  105. Examples:
  106. python extract_metadata.py file.dcm
  107. python extract_metadata.py file.dcm --output metadata.txt
  108. python extract_metadata.py file.dcm --format json --output metadata.json
  109. python extract_metadata.py file.dcm --show-sequences
  110. """
  111. )
  112. parser.add_argument('input', type=str, help='Input DICOM file')
  113. parser.add_argument('--output', '-o', type=str, help='Output file (default: print to console)')
  114. parser.add_argument('--format', type=str, choices=['text', 'json'], default='text',
  115. help='Output format (default: text)')
  116. parser.add_argument('--show-sequences', action='store_true',
  117. help='Include all data elements including sequences')
  118. args = parser.parse_args()
  119. # Validate input file exists
  120. input_path = Path(args.input)
  121. if not input_path.exists():
  122. print(f"Error: Input file '{args.input}' not found")
  123. sys.exit(1)
  124. try:
  125. # Read DICOM file
  126. ds = pydicom.dcmread(args.input)
  127. # Extract metadata
  128. if args.format == 'json':
  129. output = extract_metadata_json(ds)
  130. else:
  131. output = extract_metadata_text(ds, args.show_sequences)
  132. # Write or print output
  133. if args.output:
  134. with open(args.output, 'w') as f:
  135. f.write(output)
  136. print(f"✓ Metadata extracted to: {args.output}")
  137. else:
  138. print(output)
  139. except Exception as e:
  140. print(f"✗ Error: {e}")
  141. sys.exit(1)
  142. if __name__ == '__main__':
  143. main()