Showing posts with label medical-image-processing. Show all posts
Showing posts with label medical-image-processing. Show all posts

Friday, January 21, 2022

Modify Dicom file metadata using dcm4che in Java

How to modify Dicom file metadata using dcm4che.

Please follow our previous tutorials on dcm4che.

Read the Dicom header information using dcm4che in Java

Read Dicom file metadata using dcm4che in Java

Let's create a sample java class ModifyMetadata.java to modify the available metadata in the given Dicom file.

 public static void main(String[] args) {
        String inputDicomPath = "path/to/dicom/N2D_0001.dcm";
        String outputDicomPath = "output/path/to/dicom/N2D_0001.dcm";
        try {
            modifyMetadata(inputDicomPath, outputDicomPath);
        } catch (IOException e) {
            System.out.println("Error due to: "+e.getMessage());
        }
    }
 private static void modifyMetadata(String inputDicomPath, String outputDicomPath) throws IOException {
        File file = new File(inputDicomPath);
        DicomInputStream dis = new DicomInputStream(file);
        Attributes attributes = dis.readDataset();
        if (attributes.contains(Tag.PatientID))
            attributes.setString(Tag.PatientID, VR.LO, "L500400");
        if (attributes.contains(Tag.PatientName))
            attributes.setString(Tag.PatientName, VR.PN, "Test name");
        DicomOutputStream dos = new DicomOutputStream(new File(outputDicomPath));
        attributes.writeTo(dos);
        dis.close();
        dos.close();
    }

Here we are using the dcm4che standard library classes. Please follow our previous tutorial to set up dcm4che jar files. We have created modifyMetadata() method which accepts two arguments one for input Dicom image path and another is output Dicom image path where we are writing the file after modification.

DicomInputStream will read the file. We are reading all the available data set to get the attributes and try to modify the patient ID and the patient name.

After modification, DicomOutputStream will write the modified attributes to the output path. If we open the image and see, the name and patient id are changed. We can modify any available metadata similar to the above example. For Tag and VR follow the Dicom tag library


The overall code implementation looks as below

package dicom.dcm4che;

import org.dcm4che3.data.Attributes;
import org.dcm4che3.data.Tag;
import org.dcm4che3.data.VR;
import org.dcm4che3.io.DicomInputStream;
import org.dcm4che3.io.DicomOutputStream;

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

public class ModifyMetadata {

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

    private static void modifyMetadata(String inputDicomPath, String outputDicomPath) throws IOException {
        File file = new File(inputDicomPath);
        DicomInputStream dis = new DicomInputStream(file);
        Attributes attributes = dis.readDataset();
        if (attributes.contains(Tag.PatientID))
            attributes.setString(Tag.PatientID, VR.LO, "L500400");
        if (attributes.contains(Tag.PatientName))
            attributes.setString(Tag.PatientName, VR.PN, "Test name");
        DicomOutputStream dos = new DicomOutputStream(new File(outputDicomPath));
        attributes.writeTo(dos);
        dis.close();
        dos.close();
    }
}
Share:

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:

Read the Dicom header information using dcm4che in Java

In this tutorial, we are going to learn how to get the Dicom file header information using dcm4che.

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.

For Dicom standard information please visit Dicom Library.

Before start writing code we need to use a couple of jar files. Download all the Dicom library files from the bundle. This bundle contains a lot of jar files we will use only the desired one.

Extract the downloaded file, go to the lib folder and grab two jar files. dcm4che-core-5.25.1.jar and another is slf4j-api-1.7.32.jar, the verison might be different at the time of implementation.

Now, 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:

<dependency>
          <groupId>com.dcm4che</groupId>
          <artifactId>dcm4che</artifactId>
          <version>20220117</version>
          <scope>system</scope>
          <systemPath>${basedir}/libs/dcm4che-core-5.25.1.jar</systemPath>
      </dependency>
<dependency>
          <groupId>com.slf4j</groupId>
          <artifactId>slf4j</artifactId>
          <version>20220217</version>
          <scope>system</scope>
          <systemPath>${basedir}/libs/slf4j-api-1.7.32.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')
}

Let's create the java class ReadHeaderInfo.java to read the header information

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

Basically, we are using the Dicom-core classes from the jar file to read the file information. We are providing the sample Dicom file and reading the Tag Address and VR available in that file. 

DicomInputStream is used to read the file. dis.readDataset() read all the tags available in that file and finally, we are getting Tag Address and VR and outputting the values.

Output:

Total tag found in the given dicom file: 54
Tag Address: (0008,0008) VR: CS
Tag Address: (0008,0016) VR: UI
Tag Address: (0008,0018) VR: UI
Tag Address: (0008,0020) VR: DA
Tag Address: (0008,0021) VR: DA
Tag Address: (0008,0022) VR: DA
Tag Address: (0008,0023) VR: DA
Tag Address: (0008,0030) VR: TM
Tag Address: (0008,0031) VR: TM
Tag Address: (0008,0032) VR: TM
Tag Address: (0008,0033) VR: TM
Tag Address: (0008,0050) VR: SH
Tag Address: (0008,0060) VR: CS
Tag Address: (0008,0070) VR: LO
Tag Address: (0008,0080) VR: LO
Tag Address: (0008,0090) VR: PN
Tag Address: (0008,1030) VR: LO
Tag Address: (0008,103E) VR: LO
Tag Address: (0008,1090) VR: LO
Tag Address: (0010,0010) VR: PN
Tag Address: (0010,0020) VR: LO
Tag Address: (0010,0030) VR: DA
Tag Address: (0010,0040) VR: CS
Tag Address: (0010,1000) VR: LO
Tag Address: (0010,1010) VR: AS
Tag Address: (0010,1030) VR: DS
Tag Address: (0010,21C0) VR: US
Tag Address: (0018,0050) VR: DS
Tag Address: (0018,0088) VR: DS
Tag Address: (0018,1020) VR: LO
Tag Address: (0018,1030) VR: LO
Tag Address: (0020,000D) VR: UI
Tag Address: (0020,000E) VR: UI
Tag Address: (0020,0010) VR: SH
Tag Address: (0020,0011) VR: IS
Tag Address: (0020,0012) VR: IS
Tag Address: (0020,0013) VR: IS
Tag Address: (0020,0020) VR: CS
Tag Address: (0020,0032) VR: DS
Tag Address: (0020,0037) VR: DS
Tag Address: (0020,0052) VR: UI
Tag Address: (0028,0002) VR: US
Tag Address: (0028,0004) VR: CS
Tag Address: (0028,0010) VR: US
Tag Address: (0028,0011) VR: US
Tag Address: (0028,0030) VR: DS
Tag Address: (0028,0100) VR: US
Tag Address: (0028,0101) VR: US
Tag Address: (0028,0102) VR: US
Tag Address: (0028,0103) VR: US
Tag Address: (0028,1052) VR: DS
Tag Address: (0028,1053) VR: DS
Tag Address: (0028,1054) VR: LO
Tag Address: (7FE0,0010) VR: OW

Extracting the header information is important to visualize the Dicom file information.

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 ReadHeaderInfo {

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

    private static void readHeader(String inputPath) throws IOException {
        File file = new File(inputPath);
        DicomInputStream dis = new DicomInputStream(file);
        Attributes attributes = dis.readDataset();
        int[] tags = attributes.tags();
        System.out.println("Total tag found in the given dicom file: "+tags.length);
        for (int tag: tags) {
            String tagAddress = TagUtils.toString(tag);
            String vr = attributes.getVR(tag).toString();
            System.out.println("Tag Address: " + tagAddress + " VR: " + vr);
        }
        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:

Sunday, January 16, 2022

Update the Dicom image metadata using Java

In this tutorial, we are going to learn how we can update the Dicom image metadata for the Dicom file.

We are using the SimpleITK library for this. SimpleITK library is very handy while working on medical image manipulation, processing, and analysis. Please follow our previous tutorial before starting this tutorial.

Simple Itk Installation for Java Application.

Read the Dicom Image metadata using Java

Let's create a sample java class ModifyMetaData.java. Create a main method that runs the update metadata code.

public static void main(String[] args) {
        String dcmImagePath = "input_dicom_image_path/N2D_0001.dcm";
        String metaDataKeyToUpdate = "0010|0020"; // Patient Id
        String metaDataValueToUpdate = "02L3000";
        String outputDcmPath = "output_dicom_image_path/output.dcm";
        try {
            ImageFileReader imageFileReader = getDcmImageFileReader(dcmImagePath);
            Image image = imageFileReader.execute(); // Read image
            updateMetaData(image, metaDataKeyToUpdate, metaDataValueToUpdate);
            writeImage(image, outputDcmPath);
        } catch (Exception e) {
            System.out.println("Error due to: " + e.getMessage());
        }
    }

Here, we are defining the input Dicom image path, metadata key to update. The metadata tag must be in the format of 0010|0020. Metadata value to update and the output Dicom image path to save the update Dicom image.

First, we are reading the Dicom image then we are updating the image with the tag value for the tag. Here we are using the patient Id tag to update. Please visit the Dicom library for the universal Dicom tag and its description.

Let's implement the method used in the main method.

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

This method reads the Dicom image using the SimpleItk library.

private static void updateMetaData(Image image, String metaDataKey, String metaDataValue) {
        image.setMetaData(metaDataKey, metaDataValue);
    }

Here, we are simply updating the patient id provided with the value

private static void writeImage(Image image, String outputImagePath) {
        SimpleITK.writeImage(image, outputImagePath);
    }

Here, we are writing the updated Dicom image to the output file path. If we verify the file then the Dicom image, the Patient Id value is changed.

The overall code implementation looks as below:

package simpleitk;

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

public class ModifyMetaData {

    public static void main(String[] args) {
        String dcmImagePath = "input_dicom_image_path/N2D_0001.dcm";
        String metaDataKeyToUpdate = "0010|0020"; // Patient Id
        String metaDataValueToUpdate = "02L3000";
        String outputDcmPath = "output_dicom_image_path/output.dcm";
        try {
            ImageFileReader imageFileReader = getDcmImageFileReader(dcmImagePath);
            Image image = imageFileReader.execute(); // Read image
            updateMetaData(image, metaDataKeyToUpdate, metaDataValueToUpdate);
            writeImage(image, outputDcmPath);
        } catch (Exception e) {
            System.out.println("Error due to: " + e.getMessage());
        }
    }

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

    private static void updateMetaData(Image image, String metaDataKey, String metaDataValue) {
        image.setMetaData(metaDataKey, metaDataValue);
    }

    private static void writeImage(Image image, String outputImagePath) {
        SimpleITK.writeImage(image, outputImagePath);
    }
}
Share:

Friday, January 7, 2022

Install SimpleITK on Linux/Ubuntu for Java Application

In this tutorial, we are going to learn how to install SimpleITK which is very handy for medical image analysis.

SimpleITK is a simplified programming interface to the algorithms and data structures of the Insight Toolkit (ITK). It supports bindings for multiple programming languages including C++, Python, R, Java, C#, Lua, Ruby, and TCL. These bindings enable scientists to develop image analysis workflows in the programming language they are most familiar with. The toolkit supports more than 15 different image file formats, provides over 280 image analysis filters, and implements a unified interface to the ITK intensity-based registration framework. you can check out official documentation from here.

For the windows system, we can find the prebuilt library where we can simply download and install it. But for Linux os, we need to build by ourselves.

Installation:

Download SimpleItk: 

Clone the SimpleITK from the github.  We can select the desired version from release and download or clone it.


git clone https://github.com/SimpleITK/SimpleITK.git

Now change to the SimpleITK directory:

cd SimpleITK

Install Cmake:

sudo apt-get  install cmake
Install Java:
sudo apt install openjdk-8-jdk

Build SimpleITK

mkdir SimpleITK-build
cd SimpleITK-build
sudo cmake ../SuperBuild

The SuperBuild generates make files that take care of downloading and building ITK. Now start the build

make -j4

Note: Be careful not to run out of memory during the build. We need 4GB of memory per core. For example, if we compile with 4 cores (e.g. make -j4) we need a machine with at least 16GB of RAM.

It will take some time. After the installation, you can find the .so library file which we are going to use. Also, you can find the .jar file for java under the created build folder.

First, we need to load the ITK .jar file in our project and .so file by providing the JVM argument as
Djava.library.path=/path/to/SimpleITKRuntime
Where, /path/to/SimpleITKRuntime is the directory that contains the .so file. Otherwise, you will get the following error
Exception in thread "main" java.lang.UnsatisfiedLinkError: no SimpleITKJava in java.library.path
	at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1860)
	at java.lang.Runtime.loadLibrary0(Runtime.java:871)
	at java.lang.System.loadLibrary(System.java:1124)
	at org.itk.simple.SimpleITKJNI.<clinit>(SimpleITKJNI.java:226)
	at org.itk.simple.SimpleITK.readImage(SimpleITK.java:475)
	at simpleitk.SimpleItkTest.main(SimpleItkTest.java:8)

Run the sample Java example

package simpleitk;

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

public class SimpleItkTest {
    public static void main(String[] args) {
		String inputImagePath = "/path/to/image";
		String outputImagePath = "/path/to/output/image";
        Image image = SimpleITK.readImage(inputImagePath);
        SimpleITK.writeImage(image, outputImagePath);
    }
}

This is a sample example for reading and writing images using simpleITK library.

Note if we are using the Gradle project, then we can add the .so library path as below

bootRun {
    jvmArgs('-Djava.library.path=/opt/SimpleItk/')
}
Where, /opt/SimpleItk/ is the directory which contains the .so file.

Share: