First of all I want to thank all of you visitors! This post shows how we can use dcm4che2 toolkit for performing image processing. Most of articles and tutorials on the web present only pixel data accessing and manipulation, but not Dicom to Dicom image processing. Here we will manipulate an original Dicom image and then save it as a new Dicom processed image. You're supposed to know basic Java programming, the Eclipse environment and some Dicom stuff.
Lets start. Open your Eclipse IDE and choose File > New > Java Project. Name it myDicomImageProcessing. The next step is to create a new class, so right-click the src package and select New > Class. Enter DicomImageProcessing for class name and select the main method option. You'll get something like this:
public class DicomImageProcessing {
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
I encourage you to have a look at my last post Converting DICOM to JPEG because there are some repeated code here which there is no need to be explained again. Inside the main's body let's code the following line:
File sourceFile = new File("c:/original.dcm");
This will be our original Dicom file. Next we will open this file and get its pixel data:
try {
Iteratoriter = ImageIO.getImageReadersByFormatName("DICOM");
ImageReader reader = (ImageReader) iter.next();
DicomImageReadParam param = (DicomImageReadParam) reader.getDefaultReadParam();
ImageInputStream iis = ImageIO.createImageInputStream(sourceFile);
reader.setInput(iis, false);
Raster raster = reader.readRaster(0, param);
Our
ImageReader
is able to return a complete Raster
from our Dicom image. According to Java documentation a Raster
represents values for pixels occupying a particular rectangular area (read pixel array). Then, if our raster object is null we got some errors opening the file, so we may display an error message:
if (raster == null) {
System.out.println("Error: couldn't read Dicom image!");
return;
}
iis.close();
Ok, we read the file and our raster object holds all pixel data information. Now comes the image processing tour. For this example I chose Java
ConvolveOp
class for performing blurring, embossing and sharpening operations. It implements a convolution from the source to the destination.Convolution using a convolution kernel is a spatial operation that computes the output pixel from an input pixel by multiplying the kernel with the surround of the input pixel. This allows the output pixel to be affected by the immediate neighborhood in a way that can be mathematically specified with a kernel.
Great, we also need to use the
Kernel
class. This class defines a matrix that describes how a specified pixel and its surrounding pixels affect the value computed for the pixel's position in the output image of a filtering operation.Now let's create a new kernel for applying an emboss filter to our Dicom image:
float[] emboss = new float[] { -2,0,0, 0,1,0, 0,0,2 };
Kernel kernel = new Kernel(3, 3, emboss);
See that our kernel is a simple matrix. You can change this values further and check the results, you are the man :) Next let's apply the filter through our
ConvolveOp
class.
ConvolveOp op = new ConvolveOp(kernel);
Raster newRaster = op.filter(raster, null);
Note that, we just pass our kernel as a parameter and create a new
ConvolveOp
object. The filter(src,dst)
method can return a BufferedImage
or a new Raster
object containing all the manipulated pixel data. So we have to choose the second option. See that we set null to the raster destination parameter, this force the creation of a new Raster
as a result. That's it! Our Dicom image was processed!In order to save a new Dicom file that contains our processed image, we have to do the following:
1) Extract the array element from the raster DataBuffer;
2) Create a Dicom object without pixel data;
3) Add to the Dicom object the pixel data extracted from the DataBuffer;
4) Write the modified Dicom object to a file;
So let's go! In this example I use an 16Bit MR Dicom image and its raster holds a
DataBufferUShort
object, so we have 16Bit pixels stored on short type arrays. Depending on the file you may get a DataBufferByte
object inside the raster and you'll have to adapt my example code. To extract the array just code the following lines:
DataBufferUShort buffer = (DataBufferUShort) newRaster.getDataBuffer();
short[] pixelData = buffer.getData();
The next step is to create a copy of our Dicom file without pixel data. This can be done by calling the
getDicomObject()
method from the DicomStreamMetaData
class.
DicomStreamMetaData dsmd = (DicomStreamMetaData) reader.getStreamMetadata();
DicomObject dicom = dsmd.getDicomObject();
Allright, we got the Dicom object! All we have to do so is to add our modified pixel data inside this object. We need to access the
PixelData
tag and insert our pixelData
short array like the code below:
dicom.putShorts(Tag.PixelData, dicom.vrOf(Tag.PixelData), pixelData);
Finally, lets save our new Dicom file containing the processed image:
File f = new File("C:/processed.dcm");
FileOutputStream fos = new FileOutputStream(f);
BufferedOutputStream bos = new BufferedOutputStream(fos);
DicomOutputStream dos = new DicomOutputStream(bos);
dos.writeDicomFile(dicom);
dos.close();
And, if we get any errors let's display a simple message:
} catch(Exception e) {
System.out.println("Error: couldn't read dicom image! "+ e.getMessage());
return;
}
}
It should work! I successfully opened the processed.dcm file on ImageJ. In addition, you may want to test other processing kernels and save different sets of processed images. You can try the following:
float[] blurring = new float[] { 1f/9f,1f/9f,1f/9f, 1f/9f,1f/9f,1f/9f, 1f/9f,1f/9f,1f/9f };
float[] sharpening = new float[] { -1,-1,-1, -1,9,-1, -1,-1,-1 };
If you have any problems running my examples just let me know!
Best regards,
Samuel.
42 comments:
Found code very use full for use in my final year project. Thanks for all your time and help Samcus.
Sorry to say i am not able to get DicomImageReadParam and DicomStreamMetaData classes.
Can u please tell me where i will get those classes, right now i am using dcm4che2.0.17
Hello Anil,
Thanks for visiting!
Please check if you have the package "org.dcm4che2.imageio.plugins.dcm". The classes you need belong to this package.
Any questions, just let me know.
Regards..
Hey Samuel,
Just what I was looking for... some very useful examples to get started with the DCM4CHE DICOM toolkit.
Currently refreshing a bit my Java knowledge (learned Java but haven't touched it in 5 years).
Have just installed the Eclipse IDE and will try get going with this tomorrow.
Thanks !!
Hans
hey sam, you have a great wealth of info available. i am trying to implement the code you have there however i get the following error when the program runs.
log4j:WARN No appenders could be found for logger (org.dcm4che3.image.LookupTable).
log4j:WARN Please initialize the log4j system properly
Thanks for any help you can provide
Hello Anonymous,
This is not an error, but a warning telling you that log4j was not properly configured. Your program should run, however you'll not be albe to see the log info provided by log4j labrary. Try to add log4j to you Java Build Path.
Regards,
Samuel.
Hi Sam,
First, thanks for making this tutorial page available. I have a greyscale BufferedImage which I would like to save as a dicom file.
I am quite new to Dicom and I have followed your tutorial on converting jpg->dicom. My problem is when I come to setting up the transfer syntax since I dont have encapsulated data:
dicom.initFileMetaInformation(UID.JPEGBaseline1);
dos.writeHeader(Tag.PixelData, VR.OB, -1);
dos.writeHeader(Tag.Item, null, 0);
int jpgLen = (int) jpgSource.length();
dos.writeHeader(Tag.Item, null, (jpgLen+1)&~1);
How do i modify the preceding lines to describe an array of greyscale pixeldata? I have tried the following without success:
dicom.initFileMetaInformation(UID.ImplicitVRLittleEndian);
dos.setTransferSyntax(TransferSyntax.ImplicitVRLittleEndian);
dos.writeHeader(Tag.Item, null, 0);
dos.writeHeader(Tag.SequenceDelimitationItem, null, 0);
dicom.putBytes(Tag.PixelData, dicom.vrOf(Tag.PixelData), pixelData);
Thank you in advance for advice
Hello Anonymous,
Try to follow my Dicom Image Processing tutorial. Then try to create your own Dicom file with compatible header for BitsStored, PhotometricInterpretation, SamplesPerPixel, and so on. Finally create a new grayscale array to fill in PixelData tag.
Regards :)
hi sam!
thanks for answering my mail that fast! i checked this tutorial now, very helpful!
now i would like to insert some data into tags that are not predefined and not accessable over the Tag.xxx notation. somehow i can't find the correct syntax for getting to tags by their number. do you have any clue how to solve this problem or maybe where to get information?
the dcm4che classdefinitions are not really helpful to me :(
cheers ;)
Hi Samuel,
Thank you for the very helpful guides. Would this processing tutorial also allow for adjusting the Window Level when displaying images? If so, is it possible for you to provide guidance on accomplishing that?
For example, I know I want to display "lung" levels, at about -500 level and 1500 window (a preset I've seen in Santesoft's Free Viewer), but I am lost in actually implementing it.
Hi Sam, I am having a problem with using this code: DicomImageReadParam param = (DicomImageReadParam)reader.getDefaultReadParam();
occasionally it throws this exception:
Exception in thread java.lang.ClassCastException: org.dcm4cheri.imageio.plugins.DcmImageReadParamImpl cannot be cast to org.dcm4che2.imageio.plugins.dcm.DicomImageReadParam
at dicomwithpixspace.LoadImageApp.main(LoadImageApp.java:123)
any ideas? thanks in advance
Keith
one question, how get the information of pacient, and the coordinate z from image thanks
Thank you for telling me how to add "dcm4che" to Eclipse.
Abder-Rahman
hi, i run it but i have this pb how i resolde it?
log4j:WARN No appenders could be found for logger (org.dcm4che2.imageioimpl.plugins.dcm.DicomImageReader).
log4j:WARN Please initialize the log4j system properly.
Error: couldn't read dicom image! No Image Reader of class com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReader available for format:jpeg
Hello Samuel I am trying to implement this example, but the code return the next error.
"Error: couldn't read dicom image! java.awt.image.DataBufferByte cannot be cast to java.awt.image.DataBufferUShort"
I still looking to try to understand the DataBufferUShort but havent found any solution, also looking for the DataBufferByte that you mention in the step by step guide.
I will appreciatte any help
Thank you very much...
HI I'm Selva, I used your source and chage the JPEG image to DICOM. When i retrieve to display the dicom image in my text it was not displaying.
Kindly Can anyone help me to solve this problem.
Your Code is more useful for me. I downloaded the Dicom Viewer Software.
I used your jar file in my project but the compress image is not displaying in the panel. But it shown in Preview. I didn't used XML file. It need use ah? If means Where i need to put the XML File.
hi I'm prabhu
please add the source file also in your blog for dimcom image processing and all.
Hey, kann someone tel me how to create a DICOM image and than save it in a DICOM file with the dcm4che api?
I downloaded the program and there is a .war file. Whwt the fuch is this .war? And how I can execute the program?
Hi,
A WAR file is a web application to be deployed into a web server or Servlet container. I recommend you have a look at JBoss or Tomcat to learn how to run the program.
Best,
Samuel.
Than this file is no good for me. Is there a version, which I can execute on a normal client? Or just the sourcecode, because the snipets hear are not realy helpful for understending DICOM.
Hi all !
I got next error, what is that ?
Multiple markers at this line
- imagereader cannot be resolved to a type
- The type HTMLDocument.Iterator is not generic; it cannot be parameterized with arguments
Hi Samuel
I have seen very good articles on dicom image processing using dcm4che and java
If you can share any code samples for dicom image compression(lossy & lossless) and decompression, It will be very helpful
Thanks
First of all thanks for this nice explanation.
But I have encountered a problem as explained below:
Iterator iter = ImageIO.getImageReadersByFormatName("DICOM");
I always get no value in the "iter" variable .It always gives false for "iter.next();"
Can you suggest me any solution or cause behind this problem.
Thanks in advance.
Hi,
You need JAI ImageIO and dcm4che-imageio* libraries in order to process your images. Check your classpath and see if you have them.
Regards,
Samuel.
Thanks you for this great article.I would like to ask you -Is there an easy way ,how to recognize a text inside a picture?I expect that dcm4che2 has no such a functionality.
OCR software is necessary for this task,isn't?
Thank you
Hi Tomas,
I think you need something like a CAPTCHA reader/decoder. Try to look for it, there is a lot of examples in the Web.
Regards,
Samuel.
Hello Sir,
I knew that, this program is very useful for created a dicom file which can be viewed in any dicom viewer,
I fallowed every steps given above but i got some exception i.e.
Error 2: couldn't read dicom image! java.awt.image.DataBufferByte cannot be cast to java.awt.image.DataBufferUShort
java.lang.ClassCastException: java.awt.image.DataBufferByte cannot be cast to java.awt.image.DataBufferUShort
at DicomImageProcessing.main(DicomImageProcessing.java:38)
.
.
it indicated to the fallowing lines in program i.e.
DataBufferUShort buffer = (DataBufferUShort) newRaster.getDataBuffer
();
short[] pixelData = buffer.getData();
DicomStreamMetaData dsmd = (DicomStreamMetaData) reader.getStreamMetad
ata();
DicomObject dicom = dsmd.getDicomObject();
dicom.putShorts(Tag.PixelData, dicom.vrOf(Tag.PixelData), pixelData);
Above lines give an error, now i added some other code as,
DataBufferByte buffer = (DataBufferByte) newRaster.getDataBuffer();
byte[] pixelData = buffer.getData();
DicomStreamMetaData dsmd = (DicomStreamMetaData) reader.getStreamMetad
ata();
DicomObject dicom = dsmd.getDicomObject();
dicom.putBytes(Tag.PixelData, dicom.vrOf(Tag.PixelData), pixelData);
Now, the code is running well, but the out put file i.e. processed.dcm cann't be viewed on ImageJ viewer,
it gives error like,
"cann't be open Compressed dicom image"
Please Help Me Sir regarding this problem,
Thanking you Sir.
Hello Maneesh,
I see you managed to solve the problem using a byte buffer. It's right in your case :)
See that a byte buffer usually means compressed images like JPEG. ImageJ does not support compressed DICOM images, that's why you get that error.
Try to use another viewer like Sante DICOM Viewer or use another tool to decompress your file, such as: dcm2dcm (dcm4che toolkit) and dcmdjpeg (offis dcmtk).
Regards,
Samuel.
Thanks Sir,
But i want to create such a dicom file which can be viewed by any dicom viewer,
I have used dcm2dcm (dcm4che) toolkit, but with this i couldn't success to view the dicom file on ImageJ viewer.
Sorry for delay,
Hi sam, thank you for the tutorial.
could you give some example on how to create a new dicom file with existing dicom tag value.
thank you very much.
Hello,
I got error, it is not accepting DicomStreamMetaData
DicomOutputStream in following code
DicomStreamMetaData dsmd = (DicomStreamMetaData) reader.getStreamMetadata();
DcmObject dicom = dsmd.getDicomObject();
dicom.putShorts(Tag.PixelData, ((Object) dicom).vrOf(Tag.PixelData), pixelData);
File f = new File("C:/processed.dcm");
FileOutputStream fos = new FileOutputStream(f);
BufferedOutputStream bos = new BufferedOutputStream(fos);
DicomOutputStream dos = new DicomOutputStream(bos);
plz help..
Very informative tutorial. Thank you very much.
I want to add private tag in dicom which is having binary data using dcm4chee.please any one can share the snippet to do so.
Thanks
Kiran
Hi Samuel, I have my code as:
DicomInputStream dicomInputStream = new DicomInputStream(dicomFile);
DicomObject dicomObject = dicomInputStream.readDicomObject();
I am getting the dicomObject as above. Can you please help me out to save the dicom object as jpeg?
Hi Samuel, I want to display the dicom images in my web application. What are the steps to do it? I mean do I have to convert the dicom images to jpeg and display or is there any other way?
when I display my processed image after applying the emboss filter, it contains lot of dots. Is it normal or do I have any option to remove the noise?
Post a Comment