Using Python for Medical Images

KaliCharan
8 min readJul 31, 2021

--

If you are just getting started to explore Medical images for machine learning, this is like the “Hello World” of Medical Imaging. I am hoping this article will help you get started.

Medical Imaging formats

Medical Images are different from the normal photographs. Hence they come in a different format too. The most popular format is DICOM.

What is DICOM?

DICOM stands for Digital Imaging and Communications in Medicine. It is a global standard for managing and transferring medical images. For example, If you right clicked and viewed the properties of a jpg file on your desktop it would show you properties like the date, camera, dimensions etc. as the description of the image.

Similarly DICOM is a file type that packs the image as well as its data together. So if you process the file you will see that it has properties like, the patient, age, modality etc. stored as data in the file. The file format is “*.dcm”. So whenever you see a file like “1.2.840.113619.2.55.3.2831216128.32632.1118949199.255.1.dcm” understand that it is a medical image of DICOM format.

Where to download the DICOM files?

It is not easy to find medical image data as it contains details on the personal information like name, age, sex etc. Hence unless these details are removed, one cannot access the medical images for analysis purpose. So please make sure that the images that you are working on have all personal identification details removed before you get your hands on it.

One good place will be the Google Dataset Search engine. Once you are here search for “DICOM Files”. You can select any of the results and download a zip of DICOM images. These images are already de-identified so you can access them without any hassle.

What Python libraries do I install?

You will need to install pydicom and matplotlib for this exercise. So go ahead and pip install pydicom and pip install matplotlib to get started.

Create a new Python file and import the libraries as shown.

import pydicom
import matplotlib.pyplot as plt

Make sure have unzipped the downloaded DICOM files and have the path handy. Now use the dcmread method to read the contents of your DICOM file. This method returns a dataset containing all the attributes of the DICOM file.

ds = pydicom.dcmread("1.2.840.113619.2.55.3.dcm")

Let us now print the dataset to see what all information is contained within a DICOM file.

print(ds)

DICOM metadata

As per the Registry of DICOM Standards A DICOM file has more than 3700 fields. So sometimes it is a mess if you print them all. But just to give you a view, this is what the output will look like.

Dataset.file_meta -------------------------------
(0002, 0000) File Meta Information Group Length UL: 200
(0002, 0001) File Meta Information Version OB: b'\x01\x00'
(0002, 0002) Media Storage SOP Class UID UI: CT Image Storage
(0002, 0003) Media Storage SOP Instance UID UI: 1.2.840.113619.2.55.3.2831216128.32632.1118949199.255.1
(0002, 0010) Transfer Syntax UID UI: Implicit VR Little Endian
(0002, 0012) Implementation Class UID UI: 1.2.804.114118.3
(0002, 0013) Implementation Version Name SH: 'eFilm'
(0002, 0016) Source Application Entity Title AE: ''
-------------------------------------------------
(0008, 0005) Specific Character Set CS: 'ISO_IR 100'
(0008, 0008) Image Type CS: ['ORIGINAL', 'PRIMARY', 'AXIAL']
(0008, 0012) Instance Creation Date DA: '20050618'
(0008, 0013) Instance Creation Time TM: '104258'
(0008, 0016) SOP Class UID UI: CT Image Storage
(0008, 0018) SOP Instance UID UI: 1.2.840.113619.2.55.3.2831216128.32632.1118949199.255.1
(0008, 0020) Study Date DA: '20050618'
(0008, 0021) Series Date DA: '20050618'
(0008, 0022) Acquisition Date DA: '20050618'
(0008, 0023) Content Date DA: '20050618'
(0008, 0030) Study Time TM: '103855'
(0008, 0031) Series Time TM: '104240'
(0008, 0032) Acquisition Time TM: '104255'
(0008, 0033) Content Time TM: '104258'
(0008, 0050) Accession Number SH: ''
(0008, 0060) Modality CS: 'CT'
(0008, 0070) Manufacturer LO: 'GE MEDICAL SYSTEMS'
(0008, 0080) Institution Name LO: 'OBleness Memorial Hospital'
(0008, 0090) Referring Physician's Name PN: ''
(0008, 1010) Station Name SH: 'OMEX_OC0'
(0008, 1030) Study Description LO: ''
(0008, 103e) Series Description LO: ''
(0008, 1060) Name of Physician(s) Reading Study PN: ''
(0008, 1070) Operators' Name PN: ''
(0008, 1090) Manufacturer's Model Name LO: 'LightSpeed Ultra'
(0008, 1140) Referenced Image Sequence 1 item(s) ----
(0008, 0000) Group Length UL: 98
(0008, 1150) Referenced SOP Class UID UI: CT Image Storage
(0008, 1155) Referenced SOP Instance UID UI: 1.2.840.113619.2.55.3.2831216128.32632.1118949199.253.2
---------
(0009, 0000) Private Creator UN: b'b\x00\x00\x00'
(0009, 0010) Private tag data LO: 'GEMS_IDEN_01'
(0009, 1001) [Full fidelity] UN: b'CT_LIGHTSPEED '
(0009, 1002) [Suite id] UN: b'OMEX'
(0009, 1004) [Product id] UN: b'LightSpeed Ultr '
(0009, 1027) [Image actual date] UN: b'\xa0\xfa\xb3B'
(0009, 10e3) [Equipment UID] UN: None
(0010, 0000) Group Length UL: 72
(0010, 0010) Patient's Name PN: 'THERIZINO'
(0010, 0020) Patient ID LO: '6-18-2005'
(0010, 0030) Patient's Birth Date DA: ''
(0010, 0040) Patient's Sex CS: ''
(0010, 1010) Patient's Age AS: '000Y'
(0010, 21b0) Additional Patient History LT: ''
(0018, 0000) Group Length UL: 292
(0018, 0022) Scan Options CS: 'HELICAL MODE'
(0018, 0050) Slice Thickness DS: "0.625"
(0018, 0060) KVP DS: "120.0"
(0018, 0090) Data Collection Diameter DS: "250.0"
(0018, 1020) Software Versions LO: 'LightSpeedverrel'
(0018, 1030) Protocol Name LO: '8.6 DINO'
(0018, 1100) Reconstruction Diameter DS: "157.0"
(0018, 1110) Distance Source to Detector DS: "949.075012"
(0018, 1111) Distance Source to Patient DS: "541.0"
(0018, 1120) Gantry/Detector Tilt DS: "0.0"
(0018, 1130) Table Height DS: "168.554993"
(0018, 1140) Rotation Direction CS: 'CW'
(0018, 1150) Exposure Time IS: "1320"
(0018, 1151) X-Ray Tube Current IS: "100"
(0018, 1152) Exposure IS: "50"
(0018, 1170) Generator Power IS: "24000"
(0018, 1190) Focal Spot(s) DS: "0.7"
(0018, 1210) Convolution Kernel SH: 'BONE'
(0018, 5100) Patient Position CS: 'FFS'
(0019, 0000) Private Creator UN: b'$\x01\x00\x00'
(0019, 0010) Private tag data LO: 'GEMS_ACQU_01'
(0019, 1002) [Detector Channel] UN: b'\x90\x03\x00\x00'
(0019, 1003) [Cell number at Theta] UN: b'389.750000'
(0019, 1004) [Cell spacing] UN: b'1.023900'
(0019, 100f) [Horiz. Frame of ref.] UN: b'1687.642944 '
(0019, 1011) [Series contrast] UN: b'\x00\x00'
(0019, 1018) [First scan ras] UN: b'S '
(0019, 101a) [Last scan ras] UN: b'S '
(0019, 1023) [Table Speed [mm/rotation]] UN: b'1.250000'
(0019, 1024) [Mid Scan Time [sec]] UN: b'0.659553'
(0019, 1025) [Mid scan flag] UN: b'\x01\x00'
(0019, 1026) [Tube Azimuth [degree]] UN: b'e\x01\x00\x00'
(0019, 1027) [Rotation Speed [msec]] UN: b'1.000000'
(0019, 102c) [Number of triggers] UN: b':L\x00\x00'
(0019, 102e) [Angle of first view] UN: b'0.000000'
(0019, 102f) [Trigger frequency] UN: b'984.000000'
(0019, 1039) [SFOV Type] UN: b'\x02\x00'
(0019, 1042) [Segment Number] UN: b'\x00\x00'
(0019, 1043) [Total Segments Required] UN: b'\x00\x00'
(0019, 1047) [View compression factor] UN: b'\x01\x00'
(0019, 1052) [Recon post proc. Flag] UN: b'\x01\x00'
(0019, 106a) [Dependent on #views processed] UN: b'\x03\x00'
(0020, 0000) Group Length UL: 366
(0020, 000d) Study Instance UID UI: 1.2.840.113619.2.55.3.2831216128.32632.1118949199.248
(0020, 000e) Series Instance UID UI: 1.2.840.113619.2.55.3.2831216128.32632.1118949199.254
(0020, 0010) Study ID SH: '1227'
(0020, 0011) Series Number IS: "2"
(0020, 0012) Acquisition Number IS: "1"
(0020, 0013) Instance Number IS: "1"
(0020, 0032) Image Position (Patient) DS: [-78.500000, -78.500000, 66.000000]
(0020, 0037) Image Orientation (Patient) DS: [1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000]
(0020, 0052) Frame of Reference UID UI: 1.2.840.113619.2.55.3.2831216128.32632.1118949199.250.16876.0
(0020, 1040) Position Reference Indicator LO: 'IC'
(0020, 1041) Slice Location DS: "66.0"
(0021, 0000) Private Creator UN: b'T\x00\x00\x00'
(0021, 0010) Private tag data LO: 'GEMS_RELA_01'
(0021, 1003) [Series from which Prescribed] UN: b'\x02\x00'
(0021, 1035) [Series from which prescribed] UN: b'\x01\x00'
(0021, 1036) [Image from which prescribed] UN: b'\x02\x00'
(0021, 1091) [Biopsy position] UN: b'\x00\x00'
(0021, 1092) [Biopsy T location] UN: b'\x00\x00\x00\x00'
(0021, 1093) [Biopsy ref location] UN: b'\x00\x00\x00\x00'
(0023, 0000) Private Creator UN: b'$\x00\x00\x00'
(0023, 0010) Private tag data LO: 'GEMS_STDY_01'
(0023, 1070) [Start time(secs) in first axial] UN: b'\x00\x00\xc0\xab\xfe\xac\xd0A'
(0027, 0000) Private Creator UN: b'\xb6\x00\x00\x00'
(0027, 0010) Private tag data LO: 'GEMS_IMAG_01'
(0027, 1010) [Scout Type] UN: b'\x00\x00'
(0027, 101c) [Vma mamp] UN: b'\x00\x00\x00\x00'
(0027, 101e) [Vma mod] UN: b'\x00\x00\x00\x00'
(0027, 101f) [Vma clip] UN: b'\x07\x00\x00\x00'
(0027, 1020) [Smart scan ON/OFF flag] UN: b'\x01\x00'
(0027, 1035) [Plane Type] UN: b'\x02\x00'
(0027, 1042) [Center R coord of plane image] UN: b'\x00\x00\x00\x00'
(0027, 1043) [Center A coord of plane image] UN: b'\x00\x00\x00\x00'
(0027, 1044) [Center S coord of plane image] UN: b'\x00\x00\x84B'
(0027, 1045) [Normal R coord] UN: b'\x00\x00\x00\x00'
(0027, 1046) [Normal A coord] UN: b'\x00\x00\x00\x00'
(0027, 1047) [Normal S coord] UN: b'\x00\x00\x80\xbf'
(0027, 1050) [Scan Start Location] UN: b'\x00\x00\x00\x00'
(0027, 1051) [Scan End Location] UN: b'\x00\x00\x00\x00'
(0028, 0000) Group Length UL: 184
(0028, 0002) Samples per Pixel US: 1
(0028, 0004) Photometric Interpretation CS: 'MONOCHROME2'
(0028, 0010) Rows US: 512
(0028, 0011) Columns US: 512
(0028, 0030) Pixel Spacing DS: [0.306641, 0.306641]
(0028, 0100) Bits Allocated US: 16
(0028, 0101) Bits Stored US: 16
(0028, 0102) High Bit US: 15
(0028, 0103) Pixel Representation US: 1
(0028, 0120) Pixel Padding Value SS: -2000
(0028, 1050) Window Center DS: "450.0"
(0028, 1051) Window Width DS: "3000.0"
(0028, 1052) Rescale Intercept DS: "-1024.0"
(0028, 1053) Rescale Slope DS: "1.0"
(0028, 1054) Rescale Type LO: 'HU'
(0040, 0000) Group Length UL: 52
(0040, 0244) Performed Procedure Step Start Date DA: '20050618'
(0040, 0245) Performed Procedure Step Start Time TM: '103855'
(0040, 0253) Performed Procedure Step ID SH: 'PPS ID 1227'
(0043, 0000) Private Creator UN: b'4\x01\x00\x00'
(0043, 0010) Private tag data LO: 'GEMS_PARM_01'
(0043, 1010) [Window value] UN: b'\xb8\x0b'
(0043, 1012) [X-ray chain] UN: b'c\x00c\x00c\x00'
(0043, 1016) [Number of overranges] UN: b'\x00\x00'
(0043, 101e) [Delta Start Time [msec]] UN: b'0.000000'
(0043, 101f) [Max overranges in a view] UN: b'\x00\x00\x00\x00'
(0043, 1021) [Corrected after glow terms] UN: b'\x00\x00'
(0043, 1025) [Reference channels] UN: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
(0043, 1026) [No views ref chans blocked] UN: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
(0043, 1027) [Scan Pitch Ratio] UN: b'1:1 '
(0043, 1028) [Unique image iden] UN: b'00'
(0043, 102b) [Private Scan Options] UN: b'\x02\x00\x00\x00\x01\x00\x00\x00'
(0043, 1031) [Recon Center Coordinates] UN: Array of 18 elements
(0043, 1040) [Trigger on position] UN: b"\xa33'C"
(0043, 1041) [Degree of rotation] UN: b'6\x17\xdfE'
(0043, 1042) [DAS trigger source] UN: b'\x00\x00\x00\x00'
(0043, 1043) [DAS fpa gain] UN: b'\x00\x00\x00\x00'
(0043, 1044) [DAS output source] UN: b'\x00\x00\x00\x00'
(0043, 1045) [DAS ad input] UN: b'\x00\x00\x00\x00'
(0043, 1046) [DAS cal mode] UN: b'\x00\x00\x00\x00'
(0043, 104d) [Start scan to X-ray on delay] UN: b'\x00\x00\x00\x00'
(0043, 104e) [Duration of X-ray on] UN: b'k\xa4\x9eA'
(0045, 0000) Private Creator UN: b'4\x01\x00\x00'
(0045, 0010) Private tag data LO: 'GEMS_HELIOS_01'
(0045, 1001) [Number of Macro Rows in Detector] UN: b'\x02\x00'
(0045, 1002) [Macro width at ISO Center] UN: b'\x00\x00\xa0?'
(0045, 1003) [DAS type] UN: b'\x0b\x00'
(0045, 1004) [DAS gain] UN: b'\x05\x00'
(0045, 1006) [Table Direction] UN: b'OUT OF GANTRY '
(0045, 1007) [Z smoothing Factor] UN: b'\x00\x00\x00\x00'
(0045, 1008) [View Weighting Mode] UN: b'\x00\x00'
(0045, 1009) [Sigma Row number] UN: b'\x00\x00'
(0045, 100a) [Minimum DAS value] UN: b'\x00\x00\x00\x00'
(0045, 100b) [Maximum Offset Value] UN: b'\x00\x00\x00\x00'
(0045, 100c) [Number of Views shifted] UN: b'\x00\x00'
(0045, 100d) [Z tracking Flag] UN: b'\x00\x00'
(0045, 100e) [Mean Z error] UN: b'\x00\x00\x00\x00'
(0045, 100f) [Z tracking Error] UN: b'\x00\x00\x00\x00'
(0045, 1010) [Start View 2A] UN: b'\x00\x00'
(0045, 1011) [Number of Views 2A] UN: b'\x00\x00'
(0045, 1012) [Start View 1A] UN: b'\x00\x00'
(0045, 1013) [Sigma Mode] UN: b'\x00\x00'
(0045, 1014) [Number of Views 1A] UN: b'\x00\x00'
(0045, 1015) [Start View 2B] UN: b'\x00\x00'
(0045, 1016) [Number Views 2B] UN: b'\x00\x00'
(0045, 1017) [Start View 1B] UN: b'\x00\x00'
(0045, 1018) [Number of Views 1B] UN: b'\x00\x00'
(0045, 1021) [Iterbone Flag] UN: b'\x01\x00'
(0045, 1022) [Perisstaltic Flag] UN: b'\x00\x00'
(0045, 1032) [TemporalResolution] UN: b'\xc2\xf9\xa8?'
(7fe0, 0000) Group Length UL: 524296
(7fe0, 0010) Pixel Data OW: Array of 524288 elements

alternatively you can print individual fields like shown below

print(ds.PatientName)

Viewing the images

Viewing a DICOM image is straight forward. Use the matplotlib plt method to show the pixel_array which is an numpy.ndarray.

plt.imshow(ds.pixel_array, cmap=plt.cm.bone)plt.show()

That's all for now, this is like a “hello world” of working with medical images. I will try to follow up with more soon.

--

--

KaliCharan

MedicalImaging, AI for healthcare, Deeplearning expert