Showing posts with label read dicom metadata. Show all posts
Showing posts with label read dicom metadata. Show all posts

Friday, January 21, 2022

Read Dicom file meatadata using dcm4che in Java

How to read Dicom file metadata using dcm4che in Java.

dcm4che is a collection of open-source applications and utilities for the healthcare enterprise application for processing, manipulating, and analysis of medical images.

Please follow the tutorial for setting the dcm4che in our java application.

Let's create a java class DicomMetadataReader.java to read the available metadata in the given Dicom file.

public static void main(String[] args) {
        String inputDicomFilePath = "path/to/dicom/N2D_0001.dcm";
        try {
            readMetadata(inputDicomFilePath);
        } catch (IOException e) {
            System.out.println("Error due to: "+e.getMessage());
        }
    }
private static void readMetadata(String dicomFilePath) throws IOException {
        File file = new File(dicomFilePath);
        DicomInputStream dis = new DicomInputStream(file);
        Attributes attributes = dis.readDataset();
        int[] tags = attributes.tags();
        System.out.println("Total tag found in dicom file: "+tags.length);
        for (int tag: tags) {
            String tagAddress = TagUtils.toString(tag);
            String tagValue = attributes.getString(tag);
            System.out.println("Tag Address: " + tagAddress + " Value: " + tagValue);
        }
        dis.close();
    }

Here, we are using standard classes from the dcm4che core library jar file. DicomInputStream will read the file. We are reading the available dataset of the file and getting tags. After that, we are looping through the available tags and get the tag address and corresponding tag value.

The sample Output:

Total tag found in dicom file: 54
Tag Address: (0008,0008) Value: DERIVED
Tag Address: (0008,0016) Value: 1.2.840.10008.5.1.4.1.1.4
Tag Address: (0008,0018) Value: 1.2.826.0.1.3680043.2.1143.1590429688519720198888333603882344634
Tag Address: (0008,0020) Value: 20130717
Tag Address: (0008,0021) Value: 20130717
Tag Address: (0008,0022) Value: 20130717
Tag Address: (0008,0023) Value: 20130717
Tag Address: (0008,0030) Value: 141500
Tag Address: (0008,0031) Value: 142035.93000
Tag Address: (0008,0032) Value: 132518
Tag Address: (0008,0033) Value: 142035.93
Tag Address: (0008,0050) Value: null
Tag Address: (0008,0060) Value: MR
Tag Address: (0008,0070) Value: BIOLAB
Tag Address: (0008,0080) Value: null
Tag Address: (0008,0090) Value: null
Tag Address: (0008,1030) Value: Hanke_Stadler^0024_transrep
Tag Address: (0008,103E) Value: anat-T1w
Tag Address: (0008,1090) Value: nifti2dicom
Tag Address: (0010,0010) Value: Jane_Doe
Tag Address: (0010,0020) Value: 02
Tag Address: (0010,0030) Value: 19660101
Tag Address: (0010,0040) Value: F
Tag Address: (0010,1000) Value: null
Tag Address: (0010,1010) Value: 42
Tag Address: (0010,1030) Value: 75
Tag Address: (0010,21C0) Value: 4
Tag Address: (0018,0050) Value: 0.666666686534882
Tag Address: (0018,0088) Value: 0.666666686534882
Tag Address: (0018,1020) Value: 0.4.11
Tag Address: (0018,1030) Value: anat-T1w
Tag Address: (0020,000D) Value: 1.2.826.0.1.3680043.2.1143.2592092611698916978113112155415165916
Tag Address: (0020,000E) Value: 1.2.826.0.1.3680043.2.1143.515404396022363061013111326823367652
Tag Address: (0020,0010) Value: 433724515
Tag Address: (0020,0011) Value: 401
Tag Address: (0020,0012) Value: 1
Tag Address: (0020,0013) Value: 1
Tag Address: (0020,0020) Value: L
Tag Address: (0020,0032) Value: -91.4495864331908
Tag Address: (0020,0037) Value: 0.999032176441525
Tag Address: (0020,0052) Value: 1.2.826.0.1.3680043.2.1143.6856184167807409206647724161920598374
Tag Address: (0028,0002) Value: 1
Tag Address: (0028,0004) Value: MONOCHROME2
Tag Address: (0028,0010) Value: 384
Tag Address: (0028,0011) Value: 274
Tag Address: (0028,0030) Value: 0.666666686534882
Tag Address: (0028,0100) Value: 16
Tag Address: (0028,0101) Value: 16
Tag Address: (0028,0102) Value: 15
Tag Address: (0028,0103) Value: 1
Tag Address: (0028,1052) Value: 0
Tag Address: (0028,1053) Value: 1
Tag Address: (0028,1054) Value: US
Tag Address: (7FE0,0010) Value: 0

Please follow the Dicom standard library for tag and its description.

The overall code implementation looks as below:

package dicom.dcm4che;

import org.dcm4che3.data.Attributes;
import org.dcm4che3.io.DicomInputStream;
import org.dcm4che3.util.TagUtils;

import java.io.File;
import java.io.IOException;

public class DicomMetadataReader {

    public static void main(String[] args) {
        String inputDicomFilePath = "path/to/dicom/N2D_0001.dcm";
        try {
            readMetadata(inputDicomFilePath);
        } catch (IOException e) {
            System.out.println("Error due to: "+e.getMessage());
        }
    }

    private static void readMetadata(String dicomFilePath) throws IOException {
        File file = new File(dicomFilePath);
        DicomInputStream dis = new DicomInputStream(file);
        Attributes attributes = dis.readDataset();
        int[] tags = attributes.tags();
        System.out.println("Total tag found in dicom file: "+tags.length);
        for (int tag: tags) {
            String tagAddress = TagUtils.toString(tag);
            String tagValue = attributes.getString(tag);
            System.out.println("Tag Address: " + tagAddress + " Value: " + tagValue);
        }
        dis.close();
    }
}
Share:

Monday, January 17, 2022

Read Dicom Image metadata using PixelMed in Java

In this tutorial, we are going to learn how to get Dicom image metadata using PixelMed toolkit using Java.

DICOM (Digital Imaging and Communications in Medicine) is the ubiquitous standard in the radiology and cardiology imaging industry for the exchange and management of images and image-related information.

DICOM is also used in other images related medical fields, such as pathology, endoscopy, dentistry, ophthalmology, and dermatology.

PixelMed Java DICOM Toolkit is a stand-alone DICOM toolkit that implements code for reading and creating DICOM data, DICOM network and file support, a database of DICOM objects, support for display of directories, images, reports, and spectra, and DICOM object validation.

The toolkit is an implementation, which does not depend on any other DICOM tools. This is the freely available pure Java tools for compression and XML and database support.

Download the .jar file from PixelMed Jar. Create a folder called libs inside the project directory and add the jar file and load it from the Ide.

Loading Jar file in Maven Project:

Add the following system dependency inside pom.xml file.

<dependency>
           <groupId>com.pixelmed</groupId>
           <artifactId>pixelmed</artifactId>
           <version>20220117</version>
           <scope>system</scope>
           <systemPath>${basedir}/libs/pixelmed.jar</systemPath>
       </dependency>

Note: use the downloaded jar file name.

Loading Jar in Gradle Project:

Add the following inside dependencies in build.gradle file.

dependencies {
//other dependencies
 
compile fileTree(dir: 'libs', include: '*.jar')
}

Now, let's create a sample java class called ReadMetaDataPixelMed.java and create the main method to execute the code.

    private static AttributeList attributeList = new AttributeList();
public static void main(String[] args) {
        String dcmFilePath = "/path_to_dicom_image/N2D_0001.dcm";
        try {
            readAttributes(dcmFilePath);
            Map<String, String> metaData = readMetadata();
            for (Map.Entry<String, String> entry :metaData.entrySet()) {
                System.out.println(entry.getKey()+" : "+entry.getValue());
            }
        }catch (Exception e) {
            System.out.println("Error due to: "+e.getMessage());
        }
    }

Create the methods used inside it.

private static void readAttributes(String dcmFilePath) throws DicomException, IOException {
        attributeList.read(new File(dcmFilePath));
    }

readAttributes method read the attributes or tag of the Dicom image. For Dicom library Tags and their description please visit Dicom Library.

 private static Map<String, String> readMetadata() throws DicomException {
        Map<String, String> metaData = new LinkedHashMap<>();
        metaData.put("Patient Name", getTagInformation(TagFromName.PatientName));
        metaData.put("Patient ID", getTagInformation(TagFromName.PatientID));
        metaData.put("Transfer Syntax", getTagInformation(TagFromName.TransferSyntaxUID));
        metaData.put("SOP Class", getTagInformation(TagFromName.SOPClassUID));
        metaData.put("Modality", getTagInformation(TagFromName.Modality));
        metaData.put("Samples Per Pixel", getTagInformation(TagFromName.SamplesPerPixel));
        metaData.put("Photometric Interpretation", getTagInformation(TagFromName.PhotometricInterpretation));
        metaData.put("Pixel Spacing", getTagInformation(TagFromName.PixelSpacing));
        metaData.put("Bits Allocated", getTagInformation(TagFromName.BitsAllocated));
        metaData.put("Bits Stored", getTagInformation(TagFromName.BitsStored));
        metaData.put("High Bit", getTagInformation(TagFromName.HighBit));
        SourceImage img = new com.pixelmed.display.SourceImage(attributeList);
        metaData.put("Number of frames", String.valueOf(img.getNumberOfFrames()));
        metaData.put("Width", String.valueOf(img.getWidth()));
        metaData.put("Height", String.valueOf(img.getHeight()));
        metaData.put("Is Grayscale", String.valueOf(img.isGrayscale()));
        metaData.put("Pixel Data present", String.valueOf(!getTagInformation(TagFromName.PixelData).isEmpty()));
        return metaData;
    }

Here, we are reading some sample metadata. For more metadata lists please visit TagFromName.java class and use the desired one.

private static String getTagInformation(AttributeTag tag) {
        return Attribute.getDelimitedStringValuesOrDefault(attributeList, tag, "NOT FOUND");
    }

If the attribute is found then this method returns the value of that attribute if not found then return NOT FOUND text.

Output:

Patient Name : Jane_Doe
Patient ID : 02
Transfer Syntax : 1.2.840.10008.1.2
SOP Class : 1.2.840.10008.5.1.4.1.1.4
Modality : MR
Samples Per Pixel : 1
Photometric Interpretation : MONOCHROME2
Pixel Spacing : 0.666666686534882\0.699987828731537
Bits Allocated : 16
Bits Stored : 16
High Bit : 15
Number of frames : 1
Width : 274
Height : 384
Is Grayscale : true
Pixel Data present : true

The overall code implementation looks like below:

package dicom;

import com.pixelmed.dicom.*;
import com.pixelmed.display.SourceImage;

import java.io.File;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

public class ReadMetaDataPixelMed {

    private static AttributeList attributeList = new AttributeList();

    public static void main(String[] args) {
        String dcmFilePath = "/path_to_dicom_image/N2D_0001.dcm";
        try {
            readAttributes(dcmFilePath);
            Map<String, String> metaData = readMetadata();
            for (Map.Entry<String, String> entry :metaData.entrySet()) {
                System.out.println(entry.getKey()+" : "+entry.getValue());
            }
        }catch (Exception e) {
            System.out.println("Error due to: "+e.getMessage());
        }
    }

    private static void readAttributes(String dcmFilePath) throws DicomException, IOException {
        attributeList.read(new File(dcmFilePath));
    }

    private static Map<String, String> readMetadata() throws DicomException {
        Map<String, String> metaData = new LinkedHashMap<>();
        metaData.put("Patient Name", getTagInformation(TagFromName.PatientName));
        metaData.put("Patient ID", getTagInformation(TagFromName.PatientID));
        metaData.put("Transfer Syntax", getTagInformation(TagFromName.TransferSyntaxUID));
        metaData.put("SOP Class", getTagInformation(TagFromName.SOPClassUID));
        metaData.put("Modality", getTagInformation(TagFromName.Modality));
        metaData.put("Samples Per Pixel", getTagInformation(TagFromName.SamplesPerPixel));
        metaData.put("Photometric Interpretation", getTagInformation(TagFromName.PhotometricInterpretation));
        metaData.put("Pixel Spacing", getTagInformation(TagFromName.PixelSpacing));
        metaData.put("Bits Allocated", getTagInformation(TagFromName.BitsAllocated));
        metaData.put("Bits Stored", getTagInformation(TagFromName.BitsStored));
        metaData.put("High Bit", getTagInformation(TagFromName.HighBit));
        SourceImage img = new com.pixelmed.display.SourceImage(attributeList);
        metaData.put("Number of frames", String.valueOf(img.getNumberOfFrames()));
        metaData.put("Width", String.valueOf(img.getWidth()));
        metaData.put("Height", String.valueOf(img.getHeight()));
        metaData.put("Is Grayscale", String.valueOf(img.isGrayscale()));
        metaData.put("Pixel Data present", String.valueOf(!getTagInformation(TagFromName.PixelData).isEmpty()));
        return metaData;
    }

    private static String getTagInformation(AttributeTag tag) {
        return Attribute.getDelimitedStringValuesOrDefault(attributeList, tag, "NOT FOUND");
    }
}
Share:

Saturday, January 8, 2022

Read the Dicom Image metadata using Java

In this tutorial, we are going to learn how we can read Dicom image metadata. 

A Dicom metadata generally contains:

  •  A tag that identifies the attribute, usually in the format (XXXX,XXXX) with hexadecimal numbers.
  • A DICOM Value Representation (VR) that describes the data type and format of the attribute value

We are using SimpleITK library to extract metadata. The library is very handy when used for medical Image analysis. So, please refer SimpleITK library installation from this tutorail.

Once installed and load the library, let's write some Java code that reads metadata. Create a Java file called DicomReader.java

Read the Dicom file using SimpleITK:

import org.itk.simple.ImageFileReader;
public static ImageFileReader getDcmImageFileReader(String imagePath) {
        ImageFileReader imageFileReader = new ImageFileReader();
        imageFileReader.setImageIO("GDCMImageIO");
        imageFileReader.setFileName(imagePath);
        return imageFileReader;
    }
This will read the Dicom file. This example uses the standard SimpleITK native library.

Let's create an actual method that read the metadata from the Dicom Image file

import org.itk.simple.VectorString;
import java.util.LinkedHashMap;
import java.util.Map;
public static Map<String, String> readMetadata(ImageFileReader imageFileReader) {
        Map<String, String> metaData = new LinkedHashMap<>();
        imageFileReader.loadPrivateTagsOn();
        imageFileReader.readImageInformation();
        VectorString metaDataKeys = imageFileReader.getMetaDataKeys(); // get metadata keys
        long metaDataKeySize = metaDataKeys.size();
        System.out.println("Total meta data found: " + metaDataKeySize);
        for (int metaDataKeyIndex = 0; metaDataKeyIndex < metaDataKeySize; metaDataKeyIndex++) {
            String metaDataKey = metaDataKeys.get(metaDataKeyIndex);
            String metaDataValue = imageFileReader.getMetaData(metaDataKey);
            System.out.println("Key: " + metaDataKey + " Value: " + metaDataValue);
            metaData.put(metaDataKey, metaDataValue);
        }
        return metaData;
    }
Here, we are passing the ImageFileReader object, which is obtained from the previous method. And it will extract the metadata and loop through the metadata keys and print key values. pair in the console.

Here is the sample GitHub repo for getting sample test Dicom. Let's add the main method to run the code

 public static void main(String[] args) {
        String imagePath = "path_to_dicom/N2D_0001.dcm";
        try {
            ImageFileReader imageFileReader = getDcmImageFileReader(imagePath);
            Map<String, String> metadata = readMetadata(imageFileReader);
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }
    }

The output of the above example will be similar to like this:

Total meta data found: 53
Key: 0008|0008 Value: DERIVED\SECONDARY 
Key: 0008|0016 Value: 1.2.840.10008.5.1.4.1.1.4
Key: 0008|0018 Value: 1.2.826.0.1.3680043.2.1143.1590429688519720198888333603882344634
Key: 0008|0020 Value: 20130717
Key: 0008|0021 Value: 20130717
Key: 0008|0022 Value: 20130717
Key: 0008|0023 Value: 20130717
Key: 0008|0030 Value: 141500
Key: 0008|0031 Value: 142035.93000
Key: 0008|0032 Value: 132518
Key: 0008|0033 Value: 142035.93 
Key: 0008|0050 Value: 
Key: 0008|0060 Value: MR
Key: 0008|0070 Value: BIOLAB
Key: 0008|0080 Value: 
Key: 0008|0090 Value: 
Key: 0008|1030 Value: Hanke_Stadler^0024_transrep 
Key: 0008|103e Value: anat-T1w
Key: 0008|1090 Value: nifti2dicom 
Key: 0010|0010 Value: Jane_Doe
Key: 0010|0020 Value: 02
Key: 0010|0030 Value: 19660101
Key: 0010|0040 Value: F 
Key: 0010|1000 Value: 
Key: 0010|1010 Value: 42
Key: 0010|1030 Value: 75
Key: 0010|21c0 Value: 4
Key: 0018|0050 Value: 0.666666686534882 
Key: 0018|0088 Value: 0.666666686534882 
Key: 0018|1020 Value: 0.4.11
Key: 0018|1030 Value: anat-T1w
Key: 0020|000d Value: 1.2.826.0.1.3680043.2.1143.2592092611698916978113112155415165916
Key: 0020|000e Value: 1.2.826.0.1.3680043.2.1143.515404396022363061013111326823367652
Key: 0020|0010 Value: 433724515 
Key: 0020|0011 Value: 401 
Key: 0020|0012 Value: 1 
Key: 0020|0013 Value: 1 
Key: 0020|0020 Value: L\R 
Key: 0020|0032 Value: -91.4495864331908\-160.06035870244\-142.505487236053
Key: 0020|0037 Value: 0.999032176441525\-0.0217883751691557\0.0382096472372976\0.026519476938784\0.991413870277297\-0.128043957939
Key: 0020|0052 Value: 1.2.826.0.1.3680043.2.1143.6856184167807409206647724161920598374
Key: 0028|0002 Value: 1
Key: 0028|0004 Value: MONOCHROME2 
Key: 0028|0010 Value: 384
Key: 0028|0011 Value: 274
Key: 0028|0030 Value: 0.666666686534882\0.699987828731537 
Key: 0028|0100 Value: 16
Key: 0028|0101 Value: 16
Key: 0028|0102 Value: 15
Key: 0028|0103 Value: 1
Key: 0028|1052 Value: 0 
Key: 0028|1053 Value: 1 
Key: 0028|1054 Value: US

In the above output, the key is the standard metadata key and the corresponding values are the metadata value of Dicom. 

You can find the standard Dicom tags from DICOM Tags. For e.g metadata key 0008|0008 denotes name as Image Type. Please check the link to get all the information on these keys.

The sample Dicom file used here is:


Convert the Dicom into png or jpg using SimpleITK:

Let's write the method which will convert the Dicom to PNG or JPG

 public static void convert(ImageFileReader imageFileReader, String outputImagePath) {
        Image image = imageFileReader.execute();
        SimpleITK.writeImage(image, outputImagePath);
    }
 public static void main(String[] args) {
        String imagePath = "input_path/N2D_0001.dcm";
        String outputImagePath = "output_path/test.png";
        try {
            ImageFileReader imageFileReader = getDcmImageFileReader(imagePath);
            Map<String, String> metadata = readMetadata(imageFileReader);
            convert(imageFileReader, outputImagePath);
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }
    }

The overall implementation looks as below:

package simpleitk;

import org.itk.simple.Image;
import org.itk.simple.ImageFileReader;
import org.itk.simple.SimpleITK;
import org.itk.simple.VectorString;

import java.util.LinkedHashMap;
import java.util.Map;

public class DicomReader {
    public static void main(String[] args) {
        String imagePath = "input_path/N2D_0001.dcm";
        String outputImagePath = "output_path/test.png";
        try {
            ImageFileReader imageFileReader = getDcmImageFileReader(imagePath);
            Map<String, String> metadata = readMetadata(imageFileReader);
            convert(imageFileReader, outputImagePath);
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }
    }

    public static ImageFileReader getDcmImageFileReader(String imagePath) {
        ImageFileReader imageFileReader = new ImageFileReader();
        imageFileReader.setImageIO("GDCMImageIO");
        imageFileReader.setFileName(imagePath);
        return imageFileReader;
    }

    public static Map<String, String> readMetadata(ImageFileReader imageFileReader) {
        Map<String, String> metaData = new LinkedHashMap<>();
        imageFileReader.loadPrivateTagsOn();
        imageFileReader.readImageInformation();
        VectorString metaDataKeys = imageFileReader.getMetaDataKeys();
        long metaDataKeySize = metaDataKeys.size();
        System.out.println("Total meta data found: " + metaDataKeySize);
        for (int metaDataKeyIndex = 0; metaDataKeyIndex < metaDataKeySize; metaDataKeyIndex++) {
            String metaDataKey = metaDataKeys.get(metaDataKeyIndex);
            String metaDataValue = imageFileReader.getMetaData(metaDataKey);
            System.out.println("Key: " + metaDataKey + " Value: " + metaDataValue);
            metaData.put(metaDataKey, metaDataValue);
        }
        return metaData;
    }

    public static void convert(ImageFileReader imageFileReader, String outputImagePath) {
        Image image = imageFileReader.execute();
        SimpleITK.writeImage(image, outputImagePath);
    }
}

For SimpleITK tutorial, please refer to these docs.

Share: