<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;D08DRHY4eSp7ImA9WhRaFE0.&quot;"><id>tag:blogger.com,1999:blog-7177607294183739662</id><updated>2012-02-16T07:24:35.831-08:00</updated><category term="toolkit" /><category term="samucs" /><category term="dicom" /><category term="cad" /><category term="java" /><category term="web" /><category term="jpeg" /><category term="convert" /><category term="header" /><category term="programming" /><category term="information" /><category term="flv" /><category term="tag" /><category term="pacs" /><category term="youtube" /><category term="game" /><category term="viewer" /><category term="create" /><category term="oracle" /><category term="dcm4chee" /><category term="playback" /><category term="multiframe" /><category term="print" /><category term="download" /><category term="integration" /><category term="dcm4che" /><category term="opengl" /><category term="video" /><category term="generate" /><title>samucs-dev</title><subtitle type="html">sharing knowledge...</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://samucs.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://samucs.blogspot.com/" /><author><name>Samuel Covas Salomão</name><uri>http://www.blogger.com/profile/16148621879398945798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="22" height="32" src="http://4.bp.blogspot.com/_cf7FMZ7swNk/Sbr0Wr6hmaI/AAAAAAAAAFE/xFhE3D7G1y4/S220/black.JPG" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>12</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/Samucs-dev" /><feedburner:info uri="samucs-dev" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;D0cNQ3o8fyp7ImA9WhdSGEs.&quot;"><id>tag:blogger.com,1999:blog-7177607294183739662.post-1124176285058417055</id><published>2011-02-23T04:04:00.000-08:00</published><updated>2011-07-28T07:58:12.477-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-28T07:58:12.477-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="create" /><category scheme="http://www.blogger.com/atom/ns#" term="generate" /><category scheme="http://www.blogger.com/atom/ns#" term="multiframe" /><category scheme="http://www.blogger.com/atom/ns#" term="dicom" /><category scheme="http://www.blogger.com/atom/ns#" term="dcm4che" /><title>Creating DICOM Multiframe files (MPEG to DICOM) using dcm4che 2</title><content type="html">Hi There!&lt;br /&gt;&lt;br /&gt;Long break, uh? Well, dear visitors, I have received a lot of emails asking about multiframe DICOM files. This time we will see an approach on how to build such files. A multiframe DICOM file usually has the meaning of a video file. You can open it in a DICOM viewer and then playback its frames. &lt;br /&gt;&lt;br /&gt;To achieve such behavior we will need to know how to extract image frames from a MPEG-2 video file. &lt;a href="http://www.ffmpeg.org"&gt;FFMPEG&lt;/a&gt; program is a wonderful tool and complete, cross-platform solution to record, convert and stream audio and video. Also you can get Windows versions of FFMPEG &lt;a href="http://ffmpeg.zeranoe.com/builds/"&gt;here&lt;/a&gt; or &lt;a href="http://ffmpeg.arrozcru.org/autobuilds/ffmpeg/mingw32/static"&gt;here&lt;/a&gt;. Once your download is done unpack the FFMPEG file to you root directory and type the following command in your command prompt window:&lt;br /&gt;&lt;br /&gt;C:\ffmpeg\bin&gt; ffmpeg -i yourvideo.mpg -r 30 -s 320x240 -f image2 c:/temp/images%05d.png&lt;br /&gt;&lt;br /&gt;According to FFMPEG documentation we are trying an input file (-i) called yourvideo.mpg to extract and save 30 image frames per second (-r). Each extracted image will have 320 pixels width and 240 pixels height (-s). Finally, each frame is saved as PNG images to the Windows Temp directory (-f). Below you can see an example of a successful FFMPEG output to our command.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-J1O8KI4_xDA/TjFfycT9s5I/AAAAAAAAAGw/EubsBl4cRhw/s1600/ffmpeg.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 264px;" src="http://2.bp.blogspot.com/-J1O8KI4_xDA/TjFfycT9s5I/AAAAAAAAAGw/EubsBl4cRhw/s320/ffmpeg.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5634389929015227282" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Check your Temp directory to see your extracted frames. Depending your video length you will get thousands of frames :) Now all we need to do is to loop through all PNG frames, read and encode them as DICOM frames. Using the dcm4che toolkit, the following Java class does the trick. Please, read the comments in the source code to understand what is going on.&lt;br /&gt;&lt;br /&gt;Happy coding!&lt;br /&gt;&lt;br /&gt;Samuel.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;package com.samucsdev.util;&lt;br /&gt;&lt;br /&gt;import java.awt.image.BufferedImage;&lt;br /&gt;import java.io.File;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;&lt;br /&gt;import javax.imageio.IIOImage;&lt;br /&gt;import javax.imageio.ImageIO;&lt;br /&gt;import javax.imageio.ImageWriter;&lt;br /&gt;import javax.imageio.stream.FileImageOutputStream;&lt;br /&gt;&lt;br /&gt;import org.dcm4che2.data.BasicDicomObject;&lt;br /&gt;import org.dcm4che2.data.DicomObject;&lt;br /&gt;import org.dcm4che2.data.Tag;&lt;br /&gt;import org.dcm4che2.data.UID;&lt;br /&gt;import org.dcm4che2.data.VR;&lt;br /&gt;import org.dcm4che2.imageio.plugins.dcm.DicomStreamMetaData;&lt;br /&gt;import org.dcm4che2.imageioimpl.plugins.dcm.DicomImageWriterSpi;&lt;br /&gt;import org.dcm4che2.util.UIDUtils;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * MPEG-2 to DICOM Multiframe.&lt;br /&gt; * &lt;br /&gt; * @author Samuel Covas Salomao (samucs@gmail.com)&lt;br /&gt; */&lt;br /&gt;public class Mpeg2Dicom {&lt;br /&gt; &lt;br /&gt;    /**&lt;br /&gt;     * Class constructor.&lt;br /&gt;     */&lt;br /&gt;    public Mpeg2Dicom() {&lt;br /&gt;  &lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Create the DICOM multiframe file header.&lt;br /&gt;     * &lt;br /&gt;     * @param sampleFrame&lt;br /&gt;     *            a sample BufferedImage to get image information.&lt;br /&gt;     * @param numberOfFrames&lt;br /&gt;     *            the number of frames of this multiframe DICOM file.&lt;br /&gt;     */&lt;br /&gt;    public DicomObject createDicomHeader(BufferedImage sampleFrame, int numberOfFrames) {&lt;br /&gt;&lt;br /&gt;        // Get some image information from the sample image:&lt;br /&gt;        // All frames should have the same information so we will get it only once.&lt;br /&gt;        int colorComponents = sampleFrame.getColorModel().getNumColorComponents();&lt;br /&gt;        int bitsPerPixel = sampleFrame.getColorModel().getPixelSize();&lt;br /&gt;        int bitsAllocated = (bitsPerPixel / colorComponents);&lt;br /&gt;        int samplesPerPixel = colorComponents;&lt;br /&gt;  &lt;br /&gt;        // The DICOM object that will hold our frames&lt;br /&gt;        DicomObject dicom = new BasicDicomObject();&lt;br /&gt;  &lt;br /&gt;        // Add patient related information to the DICOM dataset&lt;br /&gt;        dicom.putString(Tag.PatientName, null, "SAMUCS^DEV");&lt;br /&gt;        dicom.putString(Tag.PatientID, null, "1234ID");&lt;br /&gt;        dicom.putDate(Tag.PatientBirthDate, null, new java.util.Date());&lt;br /&gt;        dicom.putString(Tag.PatientSex, null, "M");&lt;br /&gt;  &lt;br /&gt;        // Add study related information to the DICOM dataset&lt;br /&gt;        dicom.putString(Tag.AccessionNumber, null, "1234AC");&lt;br /&gt;        dicom.putString(Tag.StudyID, null, "1");&lt;br /&gt;        dicom.putString(Tag.StudyDescription, null, "MULTIFRAME STUDY");&lt;br /&gt;        dicom.putDate(Tag.StudyDate, null, new java.util.Date());&lt;br /&gt;        dicom.putDate(Tag.StudyTime, null, new java.util.Date());&lt;br /&gt;&lt;br /&gt;        // Add series related information to the DICOM dataset&lt;br /&gt;        dicom.putInt(Tag.SeriesNumber, null, 1);&lt;br /&gt;        dicom.putDate(Tag.SeriesDate, null, new java.util.Date());&lt;br /&gt;        dicom.putDate(Tag.SeriesTime, null, new java.util.Date());&lt;br /&gt;        dicom.putString(Tag.SeriesDescription, null, "MULTIFRAME SERIES");&lt;br /&gt;        dicom.putString(Tag.Modality, null, "SC"); // secondary capture&lt;br /&gt;&lt;br /&gt;        // Add image related information to the DICOM dataset&lt;br /&gt;        dicom.putInt(Tag.InstanceNumber, null, 1);&lt;br /&gt;        dicom.putInt(Tag.SamplesPerPixel, null, samplesPerPixel);&lt;br /&gt;        dicom.putString(Tag.PhotometricInterpretation, VR.CS, "YBR_FULL_422");&lt;br /&gt;        dicom.putInt(Tag.Rows, null, sampleFrame.getHeight());&lt;br /&gt;        dicom.putInt(Tag.Columns, null, sampleFrame.getWidth());&lt;br /&gt;        dicom.putInt(Tag.BitsAllocated, null, bitsAllocated);&lt;br /&gt;        dicom.putInt(Tag.BitsStored, null, bitsAllocated);&lt;br /&gt;        dicom.putInt(Tag.HighBit, null, bitsAllocated-1);&lt;br /&gt;        dicom.putInt(Tag.PixelRepresentation, null, 0);&lt;br /&gt;&lt;br /&gt;        // Add the unique identifiers&lt;br /&gt;        dicom.putString(Tag.SOPClassUID, null, UID.SecondaryCaptureImageStorage);&lt;br /&gt;        dicom.putString(Tag.StudyInstanceUID, null, UIDUtils.createUID());&lt;br /&gt;        dicom.putString(Tag.SeriesInstanceUID, null, UIDUtils.createUID());&lt;br /&gt;        dicom.putString(Tag.SOPInstanceUID, VR.UI, UIDUtils.createUID());&lt;br /&gt;&lt;br /&gt;        //Start of multiframe information:&lt;br /&gt;        dicom.putInt(Tag.StartTrim, null, 1);                   // Start at frame 1&lt;br /&gt;        dicom.putInt(Tag.StopTrim, null, numberOfFrames);       // Stop at frame N&lt;br /&gt;        dicom.putString(Tag.FrameTime, null, "33.33");          // Milliseconds (30 frames per second)&lt;br /&gt;        dicom.putString(Tag.FrameDelay, null, "0.0");           // No frame dalay&lt;br /&gt;        dicom.putInt(Tag.NumberOfFrames, null, numberOfFrames); // The number of frames&lt;br /&gt;        dicom.putInt(Tag.RecommendedDisplayFrameRate, null, 3);  &lt;br /&gt;        dicom.putInt(Tag.FrameIncrementPointer, null, Tag.FrameTime);&lt;br /&gt;        //End of multiframe information.&lt;br /&gt;&lt;br /&gt;        // Add the default character set&lt;br /&gt;        dicom.putString(Tag.SpecificCharacterSet, VR.CS, "ISO_IR 100");&lt;br /&gt;&lt;br /&gt;        // Init the meta information with JPEG Lossless transfer syntax&lt;br /&gt;        dicom.initFileMetaInformation(UID.JPEGLossless);&lt;br /&gt;  &lt;br /&gt;        return dicom;&lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;    /**&lt;br /&gt;     * Encode the extracted FFMPEG frames to DICOM Sequence instances.&lt;br /&gt;     * &lt;br /&gt;     * @param frames&lt;br /&gt;     *            array of files as input (PNG images).&lt;br /&gt;     * @param dest&lt;br /&gt;     *            the destination directory to save the multiframe DICOM file.&lt;br /&gt;     */&lt;br /&gt;     public void encodeMultiframe(File[] frames, File dest) &lt;br /&gt;     throws IOException {&lt;br /&gt;        // Status message&lt;br /&gt;        System.out.println("Creating Multiframe File...");&lt;br /&gt;  &lt;br /&gt;        // Create DICOM image writer instance and set its output&lt;br /&gt;        ImageWriter writer = new DicomImageWriterSpi().createWriterInstance();&lt;br /&gt;        FileImageOutputStream output = new FileImageOutputStream(dest);&lt;br /&gt;        writer.setOutput(output);&lt;br /&gt;  &lt;br /&gt;        // Get an image sample from the array of images&lt;br /&gt;        BufferedImage sample = ImageIO.read(frames[0]);&lt;br /&gt;  &lt;br /&gt;        // Create a new dataset (header/metadata) for our DICOM image writer&lt;br /&gt;        DicomObject ds = this.createDicomHeader(sample, frames.length);&lt;br /&gt;&lt;br /&gt;        // Set the metadata to our DICOM image writer and prepare to encode the multiframe sequence&lt;br /&gt;        DicomStreamMetaData writeMeta = (DicomStreamMetaData) writer.getDefaultStreamMetadata(null);&lt;br /&gt;        writeMeta.setDicomObject(ds);&lt;br /&gt;        writer.prepareWriteSequence(writeMeta);&lt;br /&gt;  &lt;br /&gt;        // Status message&lt;br /&gt;        System.out.println("Start of Write Sequence...");&lt;br /&gt;  &lt;br /&gt;        // For each extracted FFMPEG images...&lt;br /&gt;        for (int i = 0; i &lt; frames.length; i++) {&lt;br /&gt;   &lt;br /&gt;            // Status message&lt;br /&gt;            System.out.println("Encoding frame # "+ (i+1));&lt;br /&gt;   &lt;br /&gt;            // Read the PNG file to a BufferedImage object&lt;br /&gt;            BufferedImage frame = ImageIO.read(frames[i]);&lt;br /&gt;   &lt;br /&gt;            // Create a new IIOImage to be saved to the DICOM multiframe sequence&lt;br /&gt;            IIOImage iioimage = new IIOImage(frame, null, null);&lt;br /&gt;   &lt;br /&gt;            // Write our image to the DICOM multiframe sequence&lt;br /&gt;            writer.writeToSequence(iioimage, null);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        // Status message&lt;br /&gt;        System.out.println("End of Write Sequence.");&lt;br /&gt;&lt;br /&gt;        // Our multiframe file was created. End the sequence and close the output stream.&lt;br /&gt;        writer.endWriteSequence();&lt;br /&gt;        output.close();&lt;br /&gt;&lt;br /&gt;        // Status message&lt;br /&gt;        System.out.println("Multiframe File Created.");&lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;    /**&lt;br /&gt;     * Run the program.&lt;br /&gt;     * &lt;br /&gt;     * @param args&lt;br /&gt;     *            program arguments.&lt;br /&gt;     */&lt;br /&gt;    public static void main(String[] args) {  &lt;br /&gt;        try {&lt;br /&gt;            // Create an instance of our class&lt;br /&gt;            Mpeg2Dicom f = new Mpeg2Dicom();&lt;br /&gt;   &lt;br /&gt;            // Create the array of files for the extracted FFMPEG images&lt;br /&gt;            File[] frames = new File("C:/temp/input").listFiles();&lt;br /&gt;   &lt;br /&gt;            // Create the DICOM multiframe file&lt;br /&gt;            f.encodeMultiframe(frames, new File("C:/temp/output/multiframe.dcm"));&lt;br /&gt;   &lt;br /&gt;        } catch (Exception e) {&lt;br /&gt;            // Print exceptions&lt;br /&gt;            e.printStackTrace();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-6UNxcMEgRHk/TjFj_fHGCEI/AAAAAAAAAG4/SXiwn5oLES0/s1600/viewer.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 190px;" src="http://3.bp.blogspot.com/-6UNxcMEgRHk/TjFj_fHGCEI/AAAAAAAAAG4/SXiwn5oLES0/s320/viewer.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5634394551151364162" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7177607294183739662-1124176285058417055?l=samucs.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/q2svPQ0kX-WU5cFlv_kDRcpFqNw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/q2svPQ0kX-WU5cFlv_kDRcpFqNw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/q2svPQ0kX-WU5cFlv_kDRcpFqNw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/q2svPQ0kX-WU5cFlv_kDRcpFqNw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Samucs-dev/~4/5fxEDa3RfF0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://samucs.blogspot.com/feeds/1124176285058417055/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=7177607294183739662&amp;postID=1124176285058417055" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/1124176285058417055?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/1124176285058417055?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Samucs-dev/~3/5fxEDa3RfF0/creating-dicom-multiframe-files-mpeg-to.html" title="Creating DICOM Multiframe files (MPEG to DICOM) using dcm4che 2" /><author><name>Samuel Covas Salomão</name><uri>http://www.blogger.com/profile/16148621879398945798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="22" height="32" src="http://4.bp.blogspot.com/_cf7FMZ7swNk/Sbr0Wr6hmaI/AAAAAAAAAFE/xFhE3D7G1y4/S220/black.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-J1O8KI4_xDA/TjFfycT9s5I/AAAAAAAAAGw/EubsBl4cRhw/s72-c/ffmpeg.jpg" height="72" width="72" /><thr:total>5</thr:total><feedburner:origLink>http://samucs.blogspot.com/2011/02/creating-dicom-multiframe-files-mpeg-to.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQGR3Y8fSp7ImA9WhdSGEs.&quot;"><id>tag:blogger.com,1999:blog-7177607294183739662.post-1256371695043004769</id><published>2010-01-06T16:52:00.001-08:00</published><updated>2011-07-28T08:18:46.875-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-28T08:18:46.875-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="playback" /><category scheme="http://www.blogger.com/atom/ns#" term="samucs" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="multiframe" /><category scheme="http://www.blogger.com/atom/ns#" term="viewer" /><category scheme="http://www.blogger.com/atom/ns#" term="dicom" /><category scheme="http://www.blogger.com/atom/ns#" term="dcm4che" /><title>DICOM Multiframe playback using dcm4che 2</title><content type="html">Hello visitors,&lt;br /&gt;&lt;br /&gt;First of all I'd like to thank you all for every email, tips, comments and mainly the valuable knowledge we have been sharing since I started this simple blog. This time I want to write a tutorial that takes a multiframe DICOM image and then playback it frame by frame. The final result is a Swing Java application where we can watch such file as it was a video file. If you feel it sounds nice so let's go!&lt;br /&gt;&lt;br /&gt;If it's your first time here, please I strongly recommend that you read my &lt;a href="http://samucs.blogspot.com/2008/03/converting-dicom-to-jpeg-using-dcm4che.html"&gt;DICOM to JPEG Conversion&lt;/a&gt; post so you can learn how to setup &lt;a href="http://www.eclipse.org"&gt;Eclipse&lt;/a&gt; and &lt;a href="http://www.dcm4che.org"&gt;dcm4che toolkit&lt;/a&gt;. Then come back to this post and continue to this example tutorial. Let's start! Open your Eclipse IDE and choose &lt;code&gt;File &gt; New &gt; Java Project&lt;/code&gt;. Name it &lt;code&gt;DicomExamples&lt;/code&gt;. The next step is to create a new class, so right-click the &lt;code&gt;src&lt;/code&gt; package and select &lt;code&gt;New &gt; Class&lt;/code&gt;. Enter &lt;code&gt;DicomMultiframePlayer&lt;/code&gt; for class name and select the main method option. You'll get something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;public class DicomMultiframePlayer {  &lt;br /&gt;   public static void main(String[] args) {  &lt;br /&gt;      // TODO Auto-generated method stub  &lt;br /&gt;   }   &lt;br /&gt;}  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To make this tutorial easy to understand I will first build the Java Swing Graphic User Interface (GUI). In order to get a Java Swing application our class must be a &lt;code&gt;JFrame&lt;/code&gt; class instance. Then since it's a Desktop program we need to provide some interaction to the user. We can do this by creating some &lt;code&gt;JButton&lt;/code&gt; components where the user can open and playback the DICOM file. Thus, we should think how to control the playback, here we will use a specific Java &lt;code&gt;Thread&lt;/code&gt;. Finally to accomplish all these requirements we must change our code a little.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;public class DicomMultiframePlayer extends JFrame &lt;br /&gt;implements ActionListener, Runnable {&lt;br /&gt;&lt;br /&gt;   /**&lt;br /&gt;    * Class constructor.&lt;br /&gt;    */&lt;br /&gt;   public DicomMultiframePlayer() {&lt;br /&gt;      // TODO Auto-generated method stub   &lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   /**&lt;br /&gt;    * This class implements the Runnable interface.&lt;br /&gt;    * It will handle thread execution.&lt;br /&gt;    */&lt;br /&gt;   @Override&lt;br /&gt;   public void run() {&lt;br /&gt;      // TODO Auto-generated method stub  &lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   /**&lt;br /&gt;    * This class implements the ActionListener interface.&lt;br /&gt;    * It will handle action events performed by buttons.&lt;br /&gt;    * @param e ActionEvent object source. &lt;br /&gt;    */&lt;br /&gt;   @Override&lt;br /&gt;   public void actionPerformed(ActionEvent e) {&lt;br /&gt;      // TODO Auto-generated method stub  &lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   /**&lt;br /&gt;    * This is a private class to render images onto a JPanel component.&lt;br /&gt;    */&lt;br /&gt;   private class ImagePanel extends JPanel {&lt;br /&gt;      // TODO Auto-generated method stub     &lt;br /&gt;   };&lt;br /&gt;&lt;br /&gt;   /**&lt;br /&gt;    * Run the program.&lt;br /&gt;    * @param args Program arguments.&lt;br /&gt;    */&lt;br /&gt;   public static void main(String[] args) {  &lt;br /&gt;      new DicomMultiframePlayer();&lt;br /&gt;   }   &lt;br /&gt;}  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As you can see our simple class now has additional Java interfaces implementations: &lt;code&gt;ActionListener&lt;/code&gt; and &lt;code&gt;Runnable&lt;/code&gt;. The first will handle &lt;code&gt;JButton&lt;/code&gt; actions and the second handles Java thread execution. Also, I started to code a private class that will be responsible for rendering our images onto a &lt;code&gt;JPanel&lt;/code&gt; component. For now our GUI class needs some Swing components and new class attributes, so let's declare them.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   // These Swing components will be our file chooser&lt;br /&gt;   private JLabel fileLabel;&lt;br /&gt;   private JTextField fileField;&lt;br /&gt;   private JButton btnChoose;&lt;br /&gt;&lt;br /&gt;   // These Swing components will be our playback controls&lt;br /&gt;   private JButton btnPlay;&lt;br /&gt;   private JButton btnPause;&lt;br /&gt;   private JButton btnStop;&lt;br /&gt;   private JButton btnExit;&lt;br /&gt;&lt;br /&gt;   // This vector stores all image frames for playback &lt;br /&gt;   private Vector&amp;lt;BufferedImage&amp;gt; images;&lt;br /&gt;&lt;br /&gt;   // This is a Swing JPanel control for image display &lt;br /&gt;   private ImagePanel imagePanel;&lt;br /&gt;&lt;br /&gt;   // Used for simple playback control &lt;br /&gt;   private boolean stop;&lt;br /&gt;   private int currentFrame;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The next step is to instantiate evey class attribute inside the class constructor. But before that let's code a helper method for &lt;code&gt;JButton&lt;/code&gt; creation. Since we have more than 3 buttons it's useful to code a creation method, this way we save several lines of code. I called this method &lt;code&gt;createJButton()&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   /**&lt;br /&gt;    * Create a new Java Swing JButton.&lt;br /&gt;    * @param width button width.&lt;br /&gt;    * @param height button height.&lt;br /&gt;    * @param text button text.&lt;br /&gt;    * @return a new JButton.&lt;br /&gt;    */&lt;br /&gt;   private JButton createJButton(int width, int height, String text) {&lt;br /&gt;      JButton b = new JButton(text);&lt;br /&gt;      b.setMinimumSize(new Dimension(width, height));&lt;br /&gt;      b.setMaximumSize(new Dimension(width, height));&lt;br /&gt;      b.setPreferredSize(new Dimension(width, height));&lt;br /&gt;      &lt;br /&gt;      // button action will be handled by 'this' class &lt;br /&gt;      b.addActionListener(this);&lt;br /&gt;      return b;&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then let's instantiate our class members and attributes inside the class constructor as follows:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   // Call the parent constructor and pass the window frame title.&lt;br /&gt;   // Tell the application to terminate when the user close the window.&lt;br /&gt;   // Configure a new BorderLyout for our application frame.&lt;br /&gt;   super("XA Player using dcm4che - by samucs-dev");&lt;br /&gt;   this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);&lt;br /&gt;   this.getContentPane().setLayout(new BorderLayout());&lt;br /&gt;&lt;br /&gt;   // Initialize our frame vector.&lt;br /&gt;   // Create our panel to render Dicom images.&lt;br /&gt;   images = new Vector&amp;lt;BufferedImage&amp;gt;();&lt;br /&gt;   imagePanel = new ImagePanel();&lt;br /&gt;&lt;br /&gt;   // Configure the file chooser component.&lt;br /&gt;   fileLabel = new JLabel("File:");&lt;br /&gt;   fileField = new JTextField(30);&lt;br /&gt;   btnChoose = this.createJButton(25, 25, "...");&lt;br /&gt;  &lt;br /&gt;   // Configure our JButton components for playback control.&lt;br /&gt;   btnPlay = this.createJButton(80,25,"Play");&lt;br /&gt;   btnPause = this.createJButton(80,25,"Pause");&lt;br /&gt;   btnStop = this.createJButton(80,25,"Stop");  &lt;br /&gt;   btnExit = this.createJButton(80,25,"Exit");&lt;br /&gt;   btnPause.setEnabled(false);&lt;br /&gt;   btnStop.setEnabled(false);&lt;br /&gt; &lt;br /&gt;   // Add the file chooser to the top of the frame window.&lt;br /&gt;   JPanel panelNorth = new JPanel();&lt;br /&gt;   panelNorth.add(fileLabel);&lt;br /&gt;   panelNorth.add(fileField);&lt;br /&gt;   panelNorth.add(btnChoose);&lt;br /&gt;   this.getContentPane().add(panelNorth, BorderLayout.NORTH);&lt;br /&gt;&lt;br /&gt;   // Add the image render panel to the center of the frame window.&lt;br /&gt;   this.getContentPane().add(imagePanel, BorderLayout.CENTER);&lt;br /&gt;&lt;br /&gt;   // Add the buttons to the bottom of the frame window.&lt;br /&gt;   JPanel panelSouth = new JPanel();&lt;br /&gt;   panelSouth.add(btnPlay);&lt;br /&gt;   panelSouth.add(btnPause);&lt;br /&gt;   panelSouth.add(btnStop);&lt;br /&gt;   panelSouth.add(btnExit);  &lt;br /&gt;   this.getContentPane().add(panelSouth, BorderLayout.SOUTH);  &lt;br /&gt;&lt;br /&gt;   // Configure frame window size and then show it.&lt;br /&gt;   this.setSize(new Dimension(500,500));&lt;br /&gt;   this.setLocationRelativeTo(null);&lt;br /&gt;   this.setVisible(true);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Well, that was a lot of code. Don't be afraind this is Java GUI done by hand :) Your reward to get here is to execute the program and see your great job! Right click the &lt;code&gt;DicomMultiframePlayer&lt;/code&gt; class and choose &lt;code&gt;Run As &gt; Java Application&lt;/code&gt;. You will see something like the picture below.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cf7FMZ7swNk/S3C2aWNxQlI/AAAAAAAAAGI/nK6rEFd476s/s1600-h/swing-frame.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 320px;" src="http://1.bp.blogspot.com/_cf7FMZ7swNk/S3C2aWNxQlI/AAAAAAAAAGI/nK6rEFd476s/s320/swing-frame.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5436045313992376914" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The GUI is almost done. Now we must implement the &lt;code&gt;ImagePanel&lt;/code&gt; class. This is a key part for us to playback the multiframe Dicom file. The &lt;code&gt;ImagePanel&lt;/code&gt; class extends the Swing &lt;code&gt;JPanel&lt;/code&gt; component. This way we can use its &lt;code&gt;paint()&lt;/code&gt; method for rendering our images and then display it to the user through the main GUI. We have to implement it as a private class for our application as follows:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   private class ImagePanel extends JPanel {&lt;br /&gt;      // The image to be rendered onto the panel. */&lt;br /&gt;      private BufferedImage image;&lt;br /&gt;      // Class constructor. */&lt;br /&gt;      public ImagePanel() {&lt;br /&gt;         super();&lt;br /&gt;         this.setPreferredSize(new Dimension(1024,1024));&lt;br /&gt;         this.setBackground(Color.black);   &lt;br /&gt;      }&lt;br /&gt;      // Set the image to be rendered. */&lt;br /&gt;      public void setImage(BufferedImage image) {&lt;br /&gt;         this.image = image;&lt;br /&gt;         this.updateUI();&lt;br /&gt;      }&lt;br /&gt;      // Render the image. */&lt;br /&gt;      @Override&lt;br /&gt;      public void paint(Graphics g) {&lt;br /&gt;         if (this.image != null) {&lt;br /&gt;            g.drawImage(this.image, 0, 0, image.getWidth(), image.getHeight(), null);&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;   };&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That's it! Our GUI is done! Now all we have to do is to code a method for opening our DICOM file and implement the &lt;code&gt;ActionListener&lt;/code&gt; and &lt;code&gt;Runnable&lt;/code&gt; interfaces. First let's see how &lt;code&gt;openFile()&lt;/code&gt; method shoulde be. That's where we use the amazing dcm4che toolkit for extracting DICOM image frames.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   private void openFile(File file) {&lt;br /&gt;      // Clear the image vector */&lt;br /&gt;      images.clear();&lt;br /&gt;      try {&lt;br /&gt;         // Here we get a new image reader for our Dicom file. */&lt;br /&gt;         System.out.println("Reading DICOM image...");   &lt;br /&gt;         ImageReader reader = new DicomImageReaderSpi().createReaderInstance();&lt;br /&gt;         FileImageInputStream input = new FileImageInputStream(file);&lt;br /&gt;         reader.setInput(input);&lt;br /&gt;&lt;br /&gt;         // Just to show the number of frames. */&lt;br /&gt;         int numFrames = reader.getNumImages(true);&lt;br /&gt;         System.out.println("DICOM image has "+ numFrames +" frames...");&lt;br /&gt; &lt;br /&gt;         // For each frame we read its image and then add it to the image vector. */&lt;br /&gt;         System.out.println("Extracting frames...");&lt;br /&gt;         for (int i=0; i &lt; numFrames; i++) {&lt;br /&gt;            BufferedImage img = reader.read(i);&lt;br /&gt;            images.add(img);&lt;br /&gt;            System.out.println(" &gt; Frame "+ (i+1));&lt;br /&gt;         }   &lt;br /&gt;         // That's it we read all frames. */&lt;br /&gt;         System.out.println("Finished.");&lt;br /&gt;      } catch(Exception e) {&lt;br /&gt;         e.printStackTrace();&lt;br /&gt;         imagePanel.setImage(null);&lt;br /&gt;         return;&lt;br /&gt;      }&lt;br /&gt;      // This is the first playback control. &lt;br /&gt;      // After reading we always display the first frame. */&lt;br /&gt;      stop = false;&lt;br /&gt;      currentFrame = 0;&lt;br /&gt;      imagePanel.setImage(images.get(0));&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now the &lt;code&gt;actionPerformed()&lt;/code&gt; method implemented from the &lt;code&gt;ActionListener&lt;/code&gt; interface handles all action events from our control buttons. The code below shows how this should be. See that depending on the button that was pressed other buttons become disabled. This is just to certify the final user will use the GUI properly.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public void actionPerformed(ActionEvent e) {  &lt;br /&gt;      // The user is opening a file. */&lt;br /&gt;      if (e.getSource().equals(btnChoose)) {&lt;br /&gt;         JFileChooser chooser = new JFileChooser();&lt;br /&gt;         int action = chooser.showOpenDialog(this);&lt;br /&gt;         switch(action) {&lt;br /&gt;            case JFileChooser.APPROVE_OPTION:&lt;br /&gt;               this.openFile(chooser.getSelectedFile());&lt;br /&gt;               break;&lt;br /&gt;            case JFileChooser.CANCEL_OPTION:&lt;br /&gt;               return; &lt;br /&gt;         }&lt;br /&gt;      }  &lt;br /&gt;      // Start playback of Dicom frames. */&lt;br /&gt;      if (e.getSource().equals(btnPlay)) {&lt;br /&gt;         btnPlay.setEnabled(false);&lt;br /&gt;         btnPause.setEnabled(true);&lt;br /&gt;         btnStop.setEnabled(true);&lt;br /&gt;         stop = false;&lt;br /&gt;         new Thread(this).start();   &lt;br /&gt;      }&lt;br /&gt;      // Pause playback. */&lt;br /&gt;      if (e.getSource().equals(btnPause)) {&lt;br /&gt;         btnPlay.setEnabled(true);&lt;br /&gt;         btnPause.setEnabled(false);&lt;br /&gt;         btnStop.setEnabled(true);&lt;br /&gt;         stop = false;&lt;br /&gt;      }&lt;br /&gt;      // Stop. Return to the first frame (0). */&lt;br /&gt;      if (e.getSource().equals(btnStop)) {&lt;br /&gt;         btnPlay.setEnabled(true);&lt;br /&gt;         btnPause.setEnabled(false);&lt;br /&gt;         btnStop.setEnabled(false);&lt;br /&gt;         stop = true;&lt;br /&gt;         currentFrame = 0;&lt;br /&gt;         imagePanel.setImage(images.get(0));   &lt;br /&gt;      }&lt;br /&gt;      // Exit the application. */&lt;br /&gt;      if (e.getSource().equals(btnExit)) {&lt;br /&gt;         System.exit(0);&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Finally we have the implementation of Runnable interface through the &lt;code&gt;run()&lt;/code&gt; method. That's where we handle the playback and give the user the illusion of watching a video file. The &lt;code&gt;run()&lt;/code&gt; method is an infinite loop and it is always checking if it has to stop. If the stop flag is false so it increments the frame number and update the display image causing the application to playback the DICOM file.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public void run() {&lt;br /&gt;      while(true) {&lt;br /&gt;         if (!btnPlay.isEnabled()) {    &lt;br /&gt;            // Check if it has to stop. */&lt;br /&gt;            if (stop) break;    &lt;br /&gt;            // Increment the current frame and update the display image. */&lt;br /&gt;            currentFrame++;&lt;br /&gt;            if (currentFrame == images.size())&lt;br /&gt;               currentFrame = 0;&lt;br /&gt;            imagePanel.setImage(&lt;br /&gt;               images.get(currentFrame));    &lt;br /&gt;            // Cause our thread to sleep 70 milliseconds. */&lt;br /&gt;            // Increase this value to slow playback speed. */&lt;br /&gt;            1try {&lt;br /&gt;               Thread.sleep(70);&lt;br /&gt;            } catch (InterruptedException e) {&lt;br /&gt;               e.printStackTrace();&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Mission accomplished! I hope you have enjoyed all this tutorial. This is a simple application and I expect you to develop it as you wish. Please, get the &lt;a href="http://samucs.googlepages.com/DicomMultiframePlayer.txt"&gt;complete source code&lt;/a&gt; and an &lt;a href="http://samucs.googlepages.com/4.dcm"&gt;example multiframe DICOM image&lt;/a&gt; to test yourself. Many thanks to Marcio Colunas from University of Aveiro, Portugal, who gave me the permission to use the multiframe image. See you on the next post!&lt;br /&gt;&lt;br /&gt;Kinldy regards,&lt;br /&gt;&lt;br /&gt;Samuel.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cf7FMZ7swNk/S3FQEfBiibI/AAAAAAAAAGQ/wSj8ao3Xdv0/s1600-h/swing-dicom-player.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 320px;" src="http://3.bp.blogspot.com/_cf7FMZ7swNk/S3FQEfBiibI/AAAAAAAAAGQ/wSj8ao3Xdv0/s320/swing-dicom-player.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5436214263190555058" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7177607294183739662-1256371695043004769?l=samucs.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/CNO_MhCEneN2JSN71auCDKPSG44/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/CNO_MhCEneN2JSN71auCDKPSG44/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/CNO_MhCEneN2JSN71auCDKPSG44/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/CNO_MhCEneN2JSN71auCDKPSG44/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Samucs-dev/~4/NS0sW2OJUdI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://samucs.blogspot.com/feeds/1256371695043004769/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=7177607294183739662&amp;postID=1256371695043004769" title="18 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/1256371695043004769?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/1256371695043004769?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Samucs-dev/~3/NS0sW2OJUdI/dicom-multiframe-playback-using-dcm4che.html" title="DICOM Multiframe playback using dcm4che 2" /><author><name>Samuel Covas Salomão</name><uri>http://www.blogger.com/profile/16148621879398945798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="22" height="32" src="http://4.bp.blogspot.com/_cf7FMZ7swNk/Sbr0Wr6hmaI/AAAAAAAAAFE/xFhE3D7G1y4/S220/black.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_cf7FMZ7swNk/S3C2aWNxQlI/AAAAAAAAAGI/nK6rEFd476s/s72-c/swing-frame.jpg" height="72" width="72" /><thr:total>18</thr:total><feedburner:origLink>http://samucs.blogspot.com/2010/01/dicom-multiframe-playback-using-dcm4che.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkMBQns-fip7ImA9WxNSGEw.&quot;"><id>tag:blogger.com,1999:blog-7177607294183739662.post-925293236064181533</id><published>2009-09-01T07:06:00.000-07:00</published><updated>2009-09-01T08:20:53.556-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-01T08:20:53.556-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="cad" /><category scheme="http://www.blogger.com/atom/ns#" term="integration" /><category scheme="http://www.blogger.com/atom/ns#" term="pacs" /><category scheme="http://www.blogger.com/atom/ns#" term="dicom" /><category scheme="http://www.blogger.com/atom/ns#" term="dcm4che" /><title>CAD-PACS Integration</title><content type="html">Hello,&lt;br /&gt;&lt;br /&gt;We have published a promising study on the latest Computer Assisted Radiology and Surgery - 24th International Congress and Exhibition in Berlin, Germany. The study presents an open framework that uses dcm4che toolkit for integrating Computer-Aided Diagnosis (CAD) to Picture Archiving and Communication Systems (PACS). It's worth reading! Access &lt;b&gt;AuntMinnie.com&lt;/b&gt; for full text and details.&lt;br /&gt;&lt;br /&gt;The Brazilian Team (Univesity of São Paulo-USP):&lt;br /&gt;   &lt;br /&gt;   - Paulo Mazzoncini de Azevedo Marques;&lt;br /&gt;   - Samuel Covas Salomão;&lt;br /&gt;   - Agma Juci Machado Traina;&lt;br /&gt;   - Marcelo Ponciano da Silva;&lt;br /&gt;   - Alessandra Alaniz Macedo;&lt;br /&gt;   - Hugo Cesar Pessotti.&lt;br /&gt;&lt;br /&gt;&lt;div style="background:white;border:1px solid blue;"&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://www.auntminnie.com/index.asp?sec=def&amp;amp;wf=1236" target="_blank"&gt;&lt;img src="http://www.auntminnie.com/images/logos/am_ea_logo.gif" border="0"&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;&lt;a href="mailto:samucs@gmail.com" target="_blank"&gt;samucs@gmail.com&lt;/a&gt; wrote:&lt;/b&gt; It's worth reading!&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight: bold; font-family: arial,helvetica,sans-serif; font-size: 18px;"&gt;Brazilian team marries lung CAD with PACS&lt;/span&gt;&lt;br&gt;&lt;br /&gt;Nearly all computer-aided detection (CAD) systems in clinical use today have a major shortcoming: the need to transfer image data to a separate workstation to run CAD software, with CAD data remaining separate from the PACS images radiologists read in their normal workflow. Researchers from São Paulo may have the answer.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;a href="http://www.auntminnie.com/redirect/redirect.asp?ItemID=86986&amp;amp;wf=1236" target="_blank"&gt;Click here to read more&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Kindly regards,&lt;br /&gt;&lt;br /&gt;Samuel.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7177607294183739662-925293236064181533?l=samucs.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/dD30oXmVY-7VWlJOwqOzQRsD8kw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/dD30oXmVY-7VWlJOwqOzQRsD8kw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/dD30oXmVY-7VWlJOwqOzQRsD8kw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/dD30oXmVY-7VWlJOwqOzQRsD8kw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Samucs-dev/~4/8dubjZ_pCd8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://samucs.blogspot.com/feeds/925293236064181533/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=7177607294183739662&amp;postID=925293236064181533" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/925293236064181533?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/925293236064181533?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Samucs-dev/~3/8dubjZ_pCd8/cad-pacs-integration.html" title="CAD-PACS Integration" /><author><name>Samuel Covas Salomão</name><uri>http://www.blogger.com/profile/16148621879398945798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="22" height="32" src="http://4.bp.blogspot.com/_cf7FMZ7swNk/Sbr0Wr6hmaI/AAAAAAAAAFE/xFhE3D7G1y4/S220/black.JPG" /></author><thr:total>2</thr:total><feedburner:origLink>http://samucs.blogspot.com/2009/09/cad-pacs-integration.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0QFR3c7fyp7ImA9WxVbEUg.&quot;"><id>tag:blogger.com,1999:blog-7177607294183739662.post-2991101661560821496</id><published>2009-03-26T15:30:00.000-07:00</published><updated>2009-03-27T06:08:36.907-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-27T06:08:36.907-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="samucs" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="pacs" /><category scheme="http://www.blogger.com/atom/ns#" term="viewer" /><category scheme="http://www.blogger.com/atom/ns#" term="web" /><category scheme="http://www.blogger.com/atom/ns#" term="dicom" /><category scheme="http://www.blogger.com/atom/ns#" term="dcm4che" /><title>SAMUCS Web DICOM Viewer</title><content type="html">Hello Visitors,&lt;br /&gt;&lt;br /&gt;I present you the &lt;b&gt;Samucs Web DICOM Viewer&lt;/b&gt; approach. This is a software designed for DICOM image visualization. Since it's a web based program it runs entirely inside your web browser and also makes use of the power of Ajax and Java technologies that increase performance and portability, enhancing flawlessly the user experience.&lt;br /&gt;&lt;br /&gt;It's the result of several days of hard work. Here I post the first version of the application for testing and feedback. In addition this software uses the powerful &lt;a href="http://www.dcm4che.org"&gt;dcm4che toolkit&lt;/a&gt; - a collection of open source applications and utilities for the healthcare enterprise. These applications have been also developed in the Java programming, supporting deployment on JDK 1.4 and up.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Features&lt;/b&gt; included in this version:&lt;br /&gt;- Remote AE title setup (PACS communication);&lt;br /&gt;- Perform queries on Study, Series and Instance levels;&lt;br /&gt;- Query by filter;&lt;br /&gt;- Query and retrieve images for visualization (C-GET, C-MOVE);&lt;br /&gt;- DICOM header viewer;&lt;br /&gt;- Tools for zooming and image adjustments;&lt;br /&gt;- Different layout views; &lt;br /&gt;&lt;br /&gt;To start viewing images right now, first &lt;a href="http://samucs.googlepages.com/samucs-web.rar"&gt;download Samucs Web DICOM Viewer&lt;/a&gt;. Then extract the &lt;code&gt;samucs-web.rar&lt;/code&gt; to get a WAR file that must be deployed to a Web Server. So download the great Web Server &lt;a href="http://tomcat.apache.org/"&gt;Apache Tomcat&lt;/a&gt;. Also, the Java Runtime Environment (JRE) should be running properly on your computer. This application was tested only on Windows Vista environment using Internet Explorer 7 and Firefox 3.0, JRE 6 and Tomcat 6. I strongly recommend Firefox. Linux users I'll try this OS soon :)&lt;br /&gt;&lt;br /&gt;The Tomcat install is quite intuitive, just follow the instructions and be sure to set port 8080 for Http. In the end you'll be asked to run Tomcat. Then open your web browser and access &lt;code&gt;http://localhost:8080&lt;/code&gt;. If everything is ok you'll see the Tomcat management page. Then click the link &lt;code&gt;Tomcat Manager&lt;/code&gt; on the top left corner below the Cat and enter the username and password saved during the installation. Now you are able to deploy the Web application to the server. Scroll down the page until you find the box &lt;code&gt;WAR file to deploy&lt;/code&gt; and then select the downloaded WAR file. Finally click the button &lt;code&gt;Deploy&lt;/code&gt;. It may be necessary to restart Tomcat before running the application.&lt;br /&gt;&lt;br /&gt;That's it! Access &lt;code&gt;http://localhost:8080/samucs-web&lt;/code&gt; to begin the new DICOM visualization experience. The default username and password is &lt;code&gt;samucs/samucs&lt;/code&gt;. I appreciate your feedback.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Screenshots:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cf7FMZ7swNk/ScxJuZpDeyI/AAAAAAAAAFk/aBKtyOihxeY/s1600-h/screen1.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 154px;" src="http://3.bp.blogspot.com/_cf7FMZ7swNk/ScxJuZpDeyI/AAAAAAAAAFk/aBKtyOihxeY/s320/screen1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5317706321523604258" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cf7FMZ7swNk/ScxJ4aCk7mI/AAAAAAAAAFs/D83KvYBdvaY/s1600-h/screen2.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 154px;" src="http://4.bp.blogspot.com/_cf7FMZ7swNk/ScxJ4aCk7mI/AAAAAAAAAFs/D83KvYBdvaY/s320/screen2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5317706493429345890" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Enjoy :) &lt;br /&gt;&lt;br /&gt;Kindly regards,&lt;br /&gt;&lt;br /&gt;Samuel.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7177607294183739662-2991101661560821496?l=samucs.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/6aRAz-YLUYkOEEfaPbLKhW2100w/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6aRAz-YLUYkOEEfaPbLKhW2100w/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/6aRAz-YLUYkOEEfaPbLKhW2100w/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6aRAz-YLUYkOEEfaPbLKhW2100w/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Samucs-dev/~4/uKehNv-gyrE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://samucs.blogspot.com/feeds/2991101661560821496/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=7177607294183739662&amp;postID=2991101661560821496" title="14 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/2991101661560821496?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/2991101661560821496?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Samucs-dev/~3/uKehNv-gyrE/samucs-web-dicom-viewer.html" title="SAMUCS Web DICOM Viewer" /><author><name>Samuel Covas Salomão</name><uri>http://www.blogger.com/profile/16148621879398945798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="22" height="32" src="http://4.bp.blogspot.com/_cf7FMZ7swNk/Sbr0Wr6hmaI/AAAAAAAAAFE/xFhE3D7G1y4/S220/black.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_cf7FMZ7swNk/ScxJuZpDeyI/AAAAAAAAAFk/aBKtyOihxeY/s72-c/screen1.jpg" height="72" width="72" /><thr:total>14</thr:total><feedburner:origLink>http://samucs.blogspot.com/2009/03/samucs-web-dicom-viewer.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMGR3w7eSp7ImA9WhdSGEs.&quot;"><id>tag:blogger.com,1999:blog-7177607294183739662.post-6616692225957018540</id><published>2009-03-17T07:46:00.000-07:00</published><updated>2011-07-28T08:20:26.201-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-28T08:20:26.201-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tag" /><category scheme="http://www.blogger.com/atom/ns#" term="information" /><category scheme="http://www.blogger.com/atom/ns#" term="header" /><category scheme="http://www.blogger.com/atom/ns#" term="print" /><category scheme="http://www.blogger.com/atom/ns#" term="dicom" /><category scheme="http://www.blogger.com/atom/ns#" term="dcm4che" /><title>Listing DICOM Header information with dcm4che 2</title><content type="html">Hi All,&lt;br /&gt;&lt;br /&gt;Some readers have asked me questions regarding how to access DICOM header information by DICOM Tag parameters. On this post I present you a quick tutorial on how to list all header information, including the Tag value, VR (value representation), Tag description, and the values of each field using the great dcm4che 2 toolkit.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;(0008,0005) [CS] Specific Character Set [ISO_IR 100]&lt;br /&gt;(0008,0008) [CS] Image Type [ORIGINAL]&lt;br /&gt;(0008,0016) [UI] SOP Class UID [1.2.840.10008.5.1.4.1.1.2]&lt;br /&gt;(0008,0020) [DA] Study Date [20040827]&lt;br /&gt;(0008,0021) [DA] Series Date [20040827]&lt;br /&gt;(0008,0022) [DA] Acquisition Date [20040827]&lt;br /&gt;(0008,0023) [DA] Content Date [20040827]&lt;br /&gt;(0008,0030) [TM] Study Time [100357.953000]&lt;br /&gt;(0008,0031) [TM] Series Time [100607.062000]&lt;br /&gt;(0008,0032) [TM] Acquisition Time [100622.688476]&lt;br /&gt;(0008,0033) [TM] Content Time [100622.688476]&lt;br /&gt;(0008,0050) [SH] Accession Number [null]&lt;br /&gt;(0008,0060) [CS] Modality [CT]&lt;br /&gt;(0008,0070) [LO] Manufacturer [SIEMENS]&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Like the previous posts, we start coding a simple class with the default constructor. Let's name it &lt;code&gt;ListDicomHeader&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;public class ListDicomHeader {&lt;br /&gt;&lt;br /&gt;   public ListDicomHeader() {&lt;br /&gt;      // TODO Auto-generated method stub&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   public static void main(String[] args) {&lt;br /&gt;      // TODO Auto-generated method stub&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The next step is to code the method responsible for extracting the header info. Note that this method is recursive. This is done because some DICOM files bring encoded Items that may hold other DICOM objects denoted by de value representation SQ. So, we are handling also sequence information with this code. The method is written as follows:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;public void listHeader(DicomObject object) {&lt;br /&gt;   Iterator&lt;DicomElement&gt; iter = object.datasetIterator();&lt;br /&gt;   while(iter.hasNext()) {&lt;br /&gt;      DicomElement element = iter.next();&lt;br /&gt;      int tag = element.tag();&lt;br /&gt;      try {&lt;br /&gt;         String tagName = object.nameOf(tag);&lt;br /&gt;         String tagAddr = TagUtils.toString(tag);&lt;br /&gt;         String tagVR = object.vrOf(tag).toString();&lt;br /&gt;         if (tagVR.equals("SQ")) {&lt;br /&gt;            if (element.hasItems()) {&lt;br /&gt;               System.out.println(tagAddr +" ["+  tagVR +"] "+ tagName);&lt;br /&gt;               listHeader(element.getDicomObject());&lt;br /&gt;               continue;&lt;br /&gt;            }&lt;br /&gt;         }    &lt;br /&gt;         String tagValue = object.getString(tag);    &lt;br /&gt;         System.out.println(tagAddr +" ["+ tagVR +"] "+ tagName +" ["+ tagValue+"]");&lt;br /&gt;      } catch (Exception e) {&lt;br /&gt;         e.printStackTrace();&lt;br /&gt;      }&lt;br /&gt;   }  &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Looking at the code, first we get an iterator to go through our DICOM dataset. Then we code a while loop to get each DICOM element present in the header. At each iteration a new &lt;code&gt;DicomElement&lt;/code&gt; is kept so we can access its values. The &lt;code&gt;tag&lt;/code&gt; variable holds the current Tag value. From then on there are some useful functions that may help us a lot. We can use the &lt;code&gt;nameOf&lt;/code&gt; method from &lt;code&gt;DicomObject&lt;/code&gt; class to get the Tag description as a &lt;code&gt;String&lt;/code&gt;. I also suggest you to have a look at the &lt;code&gt;TagUtils&lt;/code&gt; class for other great functions. The &lt;code&gt;vrOf&lt;/code&gt; function will return the value representation to the current element. &lt;br /&gt;&lt;br /&gt;Then comes the recursive part. We test the VR to see if it's a sequence (SQ), if so then we check if this element has any Items. Then if the answer is true we get the new object and call the &lt;code&gt;listHeader&lt;/code&gt; function again, starting the recursive loop. Each iteration then prints out the desired information.&lt;br /&gt;&lt;br /&gt;Finally, to test this program we must a &lt;code&gt;main&lt;/code&gt; method for this class. The method may be written as follows:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;public static void main(String[] args) {&lt;br /&gt;   DicomObject object = null;  &lt;br /&gt;   try {&lt;br /&gt;      DicomInputStream dis = new DicomInputStream(new File("c:/image.dcm"));&lt;br /&gt;      object = dis.readDicomObject();&lt;br /&gt;      dis.close();&lt;br /&gt;   } catch (Exception e) {&lt;br /&gt;      System.out.println(e.getMessage());&lt;br /&gt;      System.exit(0);&lt;br /&gt;   }&lt;br /&gt;   ListDicomHeader list = new ListDicomHeader();&lt;br /&gt;   list.listHeader(object);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's it! Now we have a lot of information from our DICOM file header! Enjoy :)&lt;br /&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;Samuel.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7177607294183739662-6616692225957018540?l=samucs.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/WE6jtZQELjj2YYsCgxIUT0vi2U0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WE6jtZQELjj2YYsCgxIUT0vi2U0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/WE6jtZQELjj2YYsCgxIUT0vi2U0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WE6jtZQELjj2YYsCgxIUT0vi2U0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Samucs-dev/~4/J_fHqIAelrU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://samucs.blogspot.com/feeds/6616692225957018540/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=7177607294183739662&amp;postID=6616692225957018540" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/6616692225957018540?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/6616692225957018540?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Samucs-dev/~3/J_fHqIAelrU/listing-dicom-header-information-with.html" title="Listing DICOM Header information with dcm4che 2" /><author><name>Samuel Covas Salomão</name><uri>http://www.blogger.com/profile/16148621879398945798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="22" height="32" src="http://4.bp.blogspot.com/_cf7FMZ7swNk/Sbr0Wr6hmaI/AAAAAAAAAFE/xFhE3D7G1y4/S220/black.JPG" /></author><thr:total>6</thr:total><feedburner:origLink>http://samucs.blogspot.com/2009/03/listing-dicom-header-information-with.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEIARnw8fSp7ImA9WhdSGEs.&quot;"><id>tag:blogger.com,1999:blog-7177607294183739662.post-6910278671217988347</id><published>2008-12-09T15:34:00.000-08:00</published><updated>2011-07-28T08:22:27.275-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-28T08:22:27.275-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="toolkit" /><category scheme="http://www.blogger.com/atom/ns#" term="jpeg" /><category scheme="http://www.blogger.com/atom/ns#" term="dicom" /><category scheme="http://www.blogger.com/atom/ns#" term="dcm4che" /><category scheme="http://www.blogger.com/atom/ns#" term="convert" /><title>Converting JPEG to DICOM using dcm4che 2</title><content type="html">Hi Folks!&lt;br /&gt;&lt;br /&gt;At last my small quiz has finished. It was just a few votes (15), however, we’ve got an interesting choice: the Jpeg to Dicom tutorial. So let’s see how we can encapsulate a Jpeg image into a Dicom dataset. This tutorial is based on &lt;a href="http://www.dcm4che.org/confluence/display/d2/jpg2dcm"&gt;jpg2dcm utility&lt;/a&gt; from &lt;a href="http://www.dcm4che.org/confluence/display/proj/The+Project"&gt;dcm4che2 toolkit&lt;/a&gt; and you are supposed to know basic java programming, the Eclipse environment, and some Dicom stuff.&lt;br /&gt;&lt;br /&gt;Open your Eclipse IDE and choose File &gt; New &gt; Java Project. Name it &lt;code&gt;myJpegToDicom&lt;/code&gt;. Next we have to create a new class, so right-click the &lt;code&gt;src&lt;/code&gt; package and select New &gt; Class. Enter &lt;code&gt;JpegToDicom&lt;/code&gt; for class name and select the main method option. You'll get something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;public class JpegToDicom {&lt;br /&gt;   public static void main(String[] args) {&lt;br /&gt;      // TODO Auto-generated method stub&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I strongly recommend that you have a look at my previous posts for reviewing some configuration steps. Inside the main’s body let’s code the following lines:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;File jpgSource = new File("c:/picture.jpg"); &lt;br /&gt;File dcmDestination = new File("c:/picture.dcm"); &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The first line creates a new file which is our Jpeg image, and the second one creates our future Dicom file which will keep Jpeg data within. Then, we have to extract some header information from our Jpeg file. To make it easy to understand I decided to use other means than search for Jpeg header markers and hexadecimal numbers. So, let’s do the following:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;try { &lt;br /&gt;   BufferedImage jpegImage = ImageIO.read(jpgSource);&lt;br /&gt;   if (jpegImage == null)&lt;br /&gt;      throw new Exception("Invalid file."); &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We open a try block and then read our Jpeg into a BufferedImage through &lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/javax/imageio/ImageIO.html"&gt;ImageIO.read()&lt;/a&gt; method. If this results in an invalid image so we may throw a new exception. Else, we’ve got a valid image and therefore valuable information about it. The &lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/java/awt/image/BufferedImage.html"&gt;BufferedImage&lt;/a&gt; class has a lot of useful methods for retrieving image data, then let’s save the number of color components (samples per pixel) of our image, the bits per pixel and the bits allocated:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   int colorComponents = jpegImage.getColorModel().getNumColorComponents();&lt;br /&gt;   int bitsPerPixel = jpegImage.getColorModel().getPixelSize();&lt;br /&gt;   int bitsAllocated = (bitsPerPixel / colorComponents);&lt;br /&gt;   int samplesPerPixel = colorComponents;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It’s time to start building our Dicom dataset:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   DicomObject dicom = new BasicDicomObject();&lt;br /&gt;   dicom.putString(Tag.SpecificCharacterSet, VR.CS, "ISO_IR 100");&lt;br /&gt;   dicom.putString(Tag.PhotometricInterpretation, VR.CS, samplesPerPixel == 3 ? "YBR_FULL_422" : "MONOCHROME2");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The first line creates a new basic Dicom object defined by dcm4che2 toolkit. The next one puts header information for Specific Character Set: ISO_IR 100 – it’s the same for ISO-8859-1 – the code for Latin alphabet. Finally, the last line puts header information for photometric interpretation (read with or without colors). So if our image has samples per pixel equals to 3, it has colors (YBR_FULL_422), else it’s a grayscale image (MONOCHROME2).&lt;br /&gt;&lt;br /&gt;The following lines add integer values to our Dicom header. Note that all of them comes from BufferedImage methods. These values are mandatory when encapsulating. For more information you can check &lt;a href="http://medical.nema.org/dicom/2007/07_05pu.pdf"&gt;Part 3.5&lt;/a&gt; of Dicom Standard. &lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   dicom.putInt(Tag.SamplesPerPixel, VR.US, samplesPerPixel);         &lt;br /&gt;   dicom.putInt(Tag.Rows, VR.US, jpegImage.getHeight());&lt;br /&gt;   dicom.putInt(Tag.Columns, VR.US, jpegImage.getWidth());&lt;br /&gt;   dicom.putInt(Tag.BitsAllocated, VR.US, bitsAllocated);&lt;br /&gt;   dicom.putInt(Tag.BitsStored, VR.US, bitsAllocated);&lt;br /&gt;   dicom.putInt(Tag.HighBit, VR.US, bitsAllocated-1);&lt;br /&gt;   dicom.putInt(Tag.PixelRepresentation, VR.US, 0);      &lt;br /&gt;&lt;/pre&gt;    &lt;br /&gt;Also, our Dicom header needs information about date and time of creation: &lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   dicom.putDate(Tag.InstanceCreationDate, VR.DA, new Date());&lt;br /&gt;   dicom.putDate(Tag.InstanceCreationTime, VR.TM, new Date());&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Every Dicom file has a unique identifier. Here we’re generating study, series and Sop instances UIDs. You may want to modify these values, but you should to care about their uniqueness.         &lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   dicom.putString(Tag.StudyInstanceUID, VR.UI, UIDUtils.createUID());&lt;br /&gt;   dicom.putString(Tag.SeriesInstanceUID, VR.UI, UIDUtils.createUID());&lt;br /&gt;   dicom.putString(Tag.SOPInstanceUID, VR.UI, UIDUtils.createUID());&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Our Dicom header is almost done. The following command initiates Dicom metafile information considering JPEGBaseline1 as transfer syntax. This means this file has Jpeg data encapsulated instead common medical image pixel data. The most common Jpeg files use a subset of the Jpeg standard called baseline Jpeg. A baseline Jpeg file contains a single image compressed with the baseline discrete cosine transformation (DCT) and Huffman encoding.&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   dicom.initFileMetaInformation(UID.JPEGBaseline1);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;After initiate the header we can open an output stream for saving our Dicom dataset as follows:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   FileOutputStream fos = new FileOutputStream(dcmDestination);&lt;br /&gt;   BufferedOutputStream bos = new BufferedOutputStream(fos);&lt;br /&gt;   DicomOutputStream dos = new DicomOutputStream(bos);&lt;br /&gt;   dos.writeDicomFile(dicom);&lt;br /&gt;&lt;/pre&gt;     &lt;br /&gt;The next three lines are the most important ones. According to Dicom Standard the data element PixelData (7FE0,0010), if encapsulated, has the value representation OB (Other Byte String) and its length shall be set to an undefined value (in this case -1). It also contains the encoded pixel data stream fragmented into one or more item(s):&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   dos.writeHeader(Tag.PixelData, VR.OB, -1);  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The Item Tag (FFFE,E000) is followed by a 4 byte item length field encoding the explicit number of bytes of the item. The first item in the sequence of items before the encoded pixel data stream shall be a basic item with length equals to zero:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   dos.writeHeader(Tag.Item, null, 0);       &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The next Item then keeps the length of our Jpeg file. &lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   /*&lt;br /&gt;   According to Gunter from dcm4che team we have to take care that &lt;br /&gt;   the pixel data fragment length containing the JPEG stream has &lt;br /&gt;   an even length.&lt;br /&gt;   */&lt;br /&gt;   int jpgLen = (int) jpgSource.length(); &lt;br /&gt;   dos.writeHeader(Tag.Item, null, (jpgLen+1)&amp;~1);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now all we have to do is to fill this item with bytes taken from our Jpeg file:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   FileInputStream fis = new FileInputStream(jpgSource);&lt;br /&gt;   BufferedInputStream bis = new BufferedInputStream(fis);&lt;br /&gt;   DataInputStream dis = new DataInputStream(bis);&lt;br /&gt;&lt;br /&gt;   byte[] buffer = new byte[65536];       &lt;br /&gt;   int b;&lt;br /&gt;   while ((b = dis.read(buffer)) &gt; 0) {&lt;br /&gt;      dos.write(buffer, 0, b);&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Finally, the Dicom Standard tells that we have to put a last Tag: a Sequence Delimiter Item (FFFE,E0DD) with length equals to zero.&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   /*&lt;br /&gt;   According to Gunter from dcm4che team we have to take care that &lt;br /&gt;   the pixel data fragment length containing the JPEG stream has &lt;br /&gt;   an even length. So if needed the line below pads JPEG stream with &lt;br /&gt;   odd length with 0 byte.&lt;br /&gt;   */&lt;br /&gt;   if ((jpgLen&amp;1) != 0) dos.write(0); &lt;br /&gt;   dos.writeHeader(Tag.SequenceDelimitationItem, null, 0);&lt;br /&gt;   dos.close();&lt;br /&gt;} catch(Exception e) {&lt;br /&gt;   System.out.println("ERROR: "+ e.getMessage());&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That’s it! Now we have a Dicom file with Jpeg data encapsulated. The print screen below was taken from &lt;a href="http://www.santesoft.com/dicom_viewer_free.html"&gt;Sante Free Dicom Viwer&lt;/a&gt; and shows a Windows Vista sample Jpeg picture encapsulated into a Dicom file.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cf7FMZ7swNk/ST8R74h-Z2I/AAAAAAAAAEk/6konE7bQgdQ/s1600-h/jpgdicom.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 192px;" src="http://3.bp.blogspot.com/_cf7FMZ7swNk/ST8R74h-Z2I/AAAAAAAAAEk/6konE7bQgdQ/s320/jpgdicom.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5277957008786351970" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;References:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://medical.nema.org/dicom/2007/07_05pu.pdf"&gt;Dicom Standard Part 3.5 - Annex A (Normative) Transfer Syntax Specifications - A4 Transfer Syntaxes for Encapsulation of Encoded Pixel Data.&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.impulseadventure.com/photo/jpeg-huffman-coding.html"&gt;Jpeg Huffman Coding Tutorial&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I hope it helps!&lt;br /&gt;&lt;br /&gt;Regards,&lt;br /&gt;&lt;br /&gt;Samuel.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7177607294183739662-6910278671217988347?l=samucs.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/37-SrWMONV08OfzxM6pD1WBlLe8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/37-SrWMONV08OfzxM6pD1WBlLe8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/37-SrWMONV08OfzxM6pD1WBlLe8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/37-SrWMONV08OfzxM6pD1WBlLe8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Samucs-dev/~4/FEXfFVBmvP8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://samucs.blogspot.com/feeds/6910278671217988347/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=7177607294183739662&amp;postID=6910278671217988347" title="31 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/6910278671217988347?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/6910278671217988347?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Samucs-dev/~3/FEXfFVBmvP8/converting-jpeg-to-dicom-using-dcm4che.html" title="Converting JPEG to DICOM using dcm4che 2" /><author><name>Samuel Covas Salomão</name><uri>http://www.blogger.com/profile/16148621879398945798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="22" height="32" src="http://4.bp.blogspot.com/_cf7FMZ7swNk/Sbr0Wr6hmaI/AAAAAAAAAFE/xFhE3D7G1y4/S220/black.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_cf7FMZ7swNk/ST8R74h-Z2I/AAAAAAAAAEk/6konE7bQgdQ/s72-c/jpgdicom.jpg" height="72" width="72" /><thr:total>31</thr:total><feedburner:origLink>http://samucs.blogspot.com/2008/12/converting-jpeg-to-dicom-using-dcm4che.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEEMSXs6fSp7ImA9WhdSGEs.&quot;"><id>tag:blogger.com,1999:blog-7177607294183739662.post-7793866373266276889</id><published>2008-09-29T10:37:00.000-07:00</published><updated>2011-07-28T08:24:48.515-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-28T08:24:48.515-07:00</app:edited><title>Processing DICOM Images using dcm4che 2</title><content type="html">Hi All,&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cf7FMZ7swNk/SOE4zJot6vI/AAAAAAAAAC4/NOHt5zWwUmw/s1600-h/ImageProcessing.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_cf7FMZ7swNk/SOE4zJot6vI/AAAAAAAAAC4/NOHt5zWwUmw/s320/ImageProcessing.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5251541091901893362" /&gt;&lt;/a&gt;&lt;br /&gt;Lets start. Open your Eclipse IDE and choose File &gt; New &gt; Java Project. Name it myDicomImageProcessing. The next step is to create a new class, so right-click the src package and select New &gt; Class. Enter DicomImageProcessing for class name and select the main method option. You'll get something like this:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;public class DicomImageProcessing {&lt;br /&gt;   public static void main(String[] args) {&lt;br /&gt;      // TODO Auto-generated method stub&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I encourage you to have a look at my last post &lt;a href="http://samucs.blogspot.com/2008/03/converting-dicom-to-jpeg-using-dcm4che.html"&gt;Converting DICOM to JPEG&lt;/a&gt; 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:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;File sourceFile = new File("c:/original.dcm");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This will be our original Dicom file. Next we will open this file and get its pixel data:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;try {&lt;br /&gt;   Iterator&lt;ImageReader&gt; iter = ImageIO.getImageReadersByFormatName("DICOM");&lt;br /&gt;   ImageReader reader = (ImageReader) iter.next();&lt;br /&gt;   DicomImageReadParam param = (DicomImageReadParam) reader.getDefaultReadParam();&lt;br /&gt;   ImageInputStream iis = ImageIO.createImageInputStream(sourceFile);&lt;br /&gt;&lt;br /&gt;   reader.setInput(iis, false);&lt;br /&gt;   Raster raster = reader.readRaster(0, param);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Our &lt;code&gt;ImageReader&lt;/code&gt; is able to return a complete &lt;code&gt;Raster&lt;/code&gt; from our Dicom image. According to Java documentation a &lt;code&gt;Raster&lt;/code&gt; 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:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   if (raster == null) {&lt;br /&gt;      System.out.println("Error: couldn't read Dicom image!");&lt;br /&gt;      return;&lt;br /&gt;   }&lt;br /&gt;   iis.close();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;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 &lt;code&gt;ConvolveOp&lt;/code&gt; class for performing blurring, embossing and sharpening operations. It implements a convolution from the source to the destination.&lt;br /&gt;&lt;br /&gt;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. &lt;br /&gt;&lt;br /&gt;Great, we also need to use the &lt;code&gt;Kernel&lt;/code&gt; 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.&lt;br /&gt;&lt;br /&gt;Now let's create a new kernel for applying an emboss filter to our Dicom image:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   float[] emboss = new float[] { -2,0,0,   0,1,0,   0,0,2 };&lt;br /&gt;   Kernel kernel = new Kernel(3, 3, emboss);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;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 &lt;code&gt;ConvolveOp&lt;/code&gt; class.&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   ConvolveOp op = new ConvolveOp(kernel);&lt;br /&gt;   Raster newRaster = op.filter(raster, null);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Note that, we just pass our kernel as a parameter and create a new &lt;code&gt;ConvolveOp&lt;/code&gt; object. The &lt;code&gt;filter(src,dst)&lt;/code&gt; method can return a &lt;code&gt;BufferedImage&lt;/code&gt; or a new &lt;code&gt;Raster&lt;/code&gt; 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 &lt;code&gt;Raster&lt;/code&gt; as a result. That's it! Our Dicom image was processed!&lt;br /&gt;&lt;br /&gt;In order to save a new Dicom file that contains our processed image, we have to do the following:&lt;br /&gt;1) Extract the array element from the raster DataBuffer;&lt;br /&gt;2) Create a Dicom object without pixel data;&lt;br /&gt;3) Add to the Dicom object the pixel data extracted from the DataBuffer;&lt;br /&gt;4) Write the modified Dicom object to a file;&lt;br /&gt;&lt;br /&gt;So let's go! In this example I use an 16Bit MR Dicom image and its raster holds a &lt;code&gt;DataBufferUShort&lt;/code&gt; object, so we have 16Bit pixels stored on short type arrays. Depending on the file you may get a &lt;code&gt;DataBufferByte&lt;/code&gt; object inside the raster and you'll have to adapt my example code. To extract the array just code the following lines:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   DataBufferUShort buffer = (DataBufferUShort) newRaster.getDataBuffer();&lt;br /&gt;   short[] pixelData = buffer.getData();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The next step is to create a copy of our Dicom file without pixel data. This can be done by calling the &lt;code&gt;getDicomObject()&lt;/code&gt; method from the &lt;code&gt;DicomStreamMetaData&lt;/code&gt; class.&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   DicomStreamMetaData dsmd = (DicomStreamMetaData) reader.getStreamMetadata();&lt;br /&gt;   DicomObject dicom = dsmd.getDicomObject();   &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;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 &lt;code&gt;PixelData&lt;/code&gt; tag and insert our &lt;code&gt;pixelData&lt;/code&gt; short array like the code below:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   dicom.putShorts(Tag.PixelData, dicom.vrOf(Tag.PixelData), pixelData);   &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Finally, lets save our new Dicom file containing the processed image:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   File f = new File("C:/processed.dcm");   &lt;br /&gt;   FileOutputStream fos = new FileOutputStream(f);&lt;br /&gt;   BufferedOutputStream bos = new BufferedOutputStream(fos);&lt;br /&gt;   DicomOutputStream dos = new DicomOutputStream(bos);      &lt;br /&gt;   dos.writeDicomFile(dicom);&lt;br /&gt;   dos.close();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And, if we get any errors let's display a simple message:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   } catch(Exception e) {&lt;br /&gt;      System.out.println("Error: couldn't read dicom image! "+ e.getMessage());&lt;br /&gt;      return;&lt;br /&gt;   } &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;float[] blurring = new float[] { 1f/9f,1f/9f,1f/9f, 1f/9f,1f/9f,1f/9f, 1f/9f,1f/9f,1f/9f };&lt;br /&gt;float[] sharpening = new float[] { -1,-1,-1,   -1,9,-1,   -1,-1,-1 };&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If you have any problems running my examples just let me know!&lt;br /&gt;&lt;br /&gt;Best regards,&lt;br /&gt;&lt;br /&gt;Samuel.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7177607294183739662-7793866373266276889?l=samucs.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Er96KdXm3tVZo0KPHSs94NRG-x8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Er96KdXm3tVZo0KPHSs94NRG-x8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Er96KdXm3tVZo0KPHSs94NRG-x8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Er96KdXm3tVZo0KPHSs94NRG-x8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Samucs-dev/~4/OTadEO_RQj4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://samucs.blogspot.com/feeds/7793866373266276889/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=7177607294183739662&amp;postID=7793866373266276889" title="33 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/7793866373266276889?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/7793866373266276889?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Samucs-dev/~3/OTadEO_RQj4/processing-dicom-images-using-dcm4che-2.html" title="Processing DICOM Images using dcm4che 2" /><author><name>Samuel Covas Salomão</name><uri>http://www.blogger.com/profile/16148621879398945798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="22" height="32" src="http://4.bp.blogspot.com/_cf7FMZ7swNk/Sbr0Wr6hmaI/AAAAAAAAAFE/xFhE3D7G1y4/S220/black.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_cf7FMZ7swNk/SOE4zJot6vI/AAAAAAAAAC4/NOHt5zWwUmw/s72-c/ImageProcessing.JPG" height="72" width="72" /><thr:total>33</thr:total><feedburner:origLink>http://samucs.blogspot.com/2008/09/processing-dicom-images-using-dcm4che-2.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEANRX45eyp7ImA9WhdSGEs.&quot;"><id>tag:blogger.com,1999:blog-7177607294183739662.post-7658588503148497168</id><published>2008-03-25T16:58:00.000-07:00</published><updated>2011-07-28T08:26:34.023-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-28T08:26:34.023-07:00</app:edited><title>Converting DICOM to JPEG using dcm4che 2</title><content type="html">Hi Folks,&lt;br /&gt;&lt;br /&gt;Sorry, I was quite busy these days, weeks, months :) Now, I can share with you how to convert any Dicom image to Jpeg using the amazing dcm4che 2.0 toolkit. I've spent a lot of time trying to figure out the magic of dcm4che and I've got some stuff that will be posted later.However, the best way to learn dcm4che is studying its utilities apps, so dcm2jpg is the one you must have a look. From now on let's just see how to perform the conversion.&lt;br /&gt;&lt;br /&gt;First, you have to download the latest version of &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=37982&amp;package_id=192320"&gt;dcm4che&lt;/a&gt; libraries. Also, you'll need the &lt;a href="https://jai-imageio.dev.java.net/"&gt;JAI ImageIO Toolkit&lt;/a&gt; in order to quickly read pixel data from Dicom images. And if you don't have any java editor get the best one: &lt;a href="http://www.eclipse.org/downloads/"&gt;Eclipse&lt;/a&gt;. You are supposed to know basic java programming, the Eclipse environment and some Dicom stuff.&lt;br /&gt;&lt;br /&gt;Lets start. Open your Eclipse IDE and choose &lt;span style="font-style:italic;"&gt;File &gt; New &gt; Java Project&lt;/span&gt;. Name it &lt;span style="font-weight:bold;"&gt;myDicomToJpeg&lt;/span&gt;. The next step is to create a new class, so right-click the &lt;span style="font-weight:bold;"&gt;src&lt;/span&gt; package and select &lt;span style="font-style:italic;"&gt;New &gt; Class&lt;/span&gt;. Enter &lt;span style="font-weight:bold;"&gt;DicomToJpeg&lt;/span&gt; for class name and select the main method option. You'll get something like this:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;public class DicomToJpeg {&lt;br /&gt;   public static void main(String[] args) {&lt;br /&gt;      // TODO Auto-generated method stub&lt;br /&gt;   } &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In order to use dcm4che classes we have to configure the project's build path. Right-click the project's main folder and select &lt;span style="font-style:italic;"&gt;Properties&lt;/span&gt;. Select the &lt;span style="font-style:italic;"&gt;Java Build Path&lt;/span&gt; option. Under &lt;span style="font-style:italic;"&gt;Libraries&lt;/span&gt; tab we'll find the &lt;span style="font-weight:bold;"&gt;Add External Jars&lt;/span&gt; button. Click on it to select all dcm4che jar files and all JAI ImageIO jar files. Now our project is able to work with dcm4che.&lt;br /&gt;&lt;br /&gt;Write the following line inside the main's body. This is our Dicom file:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;File myDicomFile = new File("c:/dicomImage.dcm");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then let's declare what will be our Jpeg image:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;BufferedImage myJpegImage = null;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The following line returns an Iterator containing all currently registered &lt;code&gt;ImageReaders&lt;/code&gt; that claim to be able to decode the named format (e.g., "DICOM", "jpeg", "tiff").&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;Iterator&amp;lt;ImageReader&amp;gt; iter = ImageIO.getImageReadersByFormatName("DICOM");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The java documentation says an &lt;code&gt;ImageReader&lt;/code&gt; object are normally instantiated by the service provider interface (SPI) class for the specific format. Service provider classes (e.g., instances of &lt;code&gt;ImageReaderSpi&lt;/code&gt;) are registered with the &lt;code&gt;IIORegistry&lt;/code&gt;, which uses them for format recognition and presentation of available format readers and writers. So let's get our &lt;code&gt;ImageReader&lt;/code&gt; object.&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;ImageReader reader = (ImageReader) iter.next();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If you check carefully dcm4che libraries you'll find some specific &lt;span style="font-weight:bold;"&gt;imageio&lt;/span&gt; packages. That's where it keeps the secret of reading Dicom pixel data. Therefore, our &lt;code&gt;ImageReader&lt;/code&gt; object is now an instance of a specific SPI class for the Dicom format. &lt;br /&gt;&lt;br /&gt;In the following line we get parameters for reading the Dicom image. The java documentation says an &lt;code&gt;ImageReadParam&lt;/code&gt; class describe how a stream is to be decoded. Instances of this class or its subclasses are used to supply prescriptive "how-to" information to instances of &lt;code&gt;ImageReader&lt;/code&gt;.&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;DicomImageReadParam param = (DicomImageReadParam) reader.getDefaultReadParam();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Before read all pixel data we have to create an &lt;code&gt;ImageInputStream&lt;/code&gt; object for use by our &lt;code&gt;ImageReader&lt;/code&gt; object. Note that this input stream has our Dicom file as a parameter. As this process throws an &lt;code&gt;IOException&lt;/code&gt; it must be between a try-catch block. &lt;br /&gt;&lt;br /&gt;Now all we have to do is to call the &lt;code&gt;read()&lt;/code&gt; method from our &lt;code&gt;ImageReader&lt;/code&gt; object together with our prescriptive Dicom parameters. The result is a new &lt;code&gt;BufferedImage&lt;/code&gt; filled with Dicom pixel data. Pretty easy, hun :)&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;try {&lt;br /&gt;   ImageInputStream iis = ImageIO.createImageInputStream(myDicomFile);&lt;br /&gt;   reader.setInput(iis, false);   &lt;br /&gt;   myJpegImage = reader.read(0, param);   &lt;br /&gt;   iis.close();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That's it! We read the Dicom image into our myJpegImage object. The following lines just test if we really succeeded. If not, we just print a message.&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   if (myJpegImage == null) {&lt;br /&gt;      System.out.println("\nError: couldn't read dicom image!");&lt;br /&gt;      return;&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You may be asking: ok, how do I get my Jpeg file? The answer is in the following lines. We firstly need to create a Jpeg file that will be sent to an &lt;code&gt;OutputStream&lt;/code&gt; to be saved. Then, the &lt;code&gt;JPEGImageEncoder&lt;/code&gt; object is responsible for encoding our Jpeg image into this output. When we close the &lt;code&gt;OutputStream&lt;/code&gt; our Jpeg file is saved. We're done!!&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   File myJpegFile = new File("c:/jpegImage.jpg");   &lt;br /&gt;   OutputStream output = new BufferedOutputStream(new FileOutputStream(myJpegFile));&lt;br /&gt;   JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(output);&lt;br /&gt;   encoder.encode(myJpegImage);&lt;br /&gt;   output.close();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Finally, if our try to read the image failed, we probably got an exception. So let's handle it printing a message.&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;} &lt;br /&gt;catch(IOException e) {&lt;br /&gt;   System.out.println("\nError: couldn't read dicom image!"+ e.getMessage());&lt;br /&gt;   return;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Have a nice day! Hope it helps :)&lt;br /&gt;&lt;br /&gt;Samuel.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7177607294183739662-7658588503148497168?l=samucs.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/8_nfgX95vhYXl5pIt1g1sSWK_N0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/8_nfgX95vhYXl5pIt1g1sSWK_N0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/8_nfgX95vhYXl5pIt1g1sSWK_N0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/8_nfgX95vhYXl5pIt1g1sSWK_N0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Samucs-dev/~4/61TVhwt4TnI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://samucs.blogspot.com/feeds/7658588503148497168/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=7177607294183739662&amp;postID=7658588503148497168" title="70 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/7658588503148497168?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/7658588503148497168?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Samucs-dev/~3/61TVhwt4TnI/converting-dicom-to-jpeg-using-dcm4che.html" title="Converting DICOM to JPEG using dcm4che 2" /><author><name>Samuel Covas Salomão</name><uri>http://www.blogger.com/profile/16148621879398945798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="22" height="32" src="http://4.bp.blogspot.com/_cf7FMZ7swNk/Sbr0Wr6hmaI/AAAAAAAAAFE/xFhE3D7G1y4/S220/black.JPG" /></author><thr:total>70</thr:total><feedburner:origLink>http://samucs.blogspot.com/2008/03/converting-dicom-to-jpeg-using-dcm4che.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkYNRnw-eCp7ImA9WxRaEEs.&quot;"><id>tag:blogger.com,1999:blog-7177607294183739662.post-1114369759207495862</id><published>2008-01-16T17:08:00.000-08:00</published><updated>2008-12-11T22:43:17.250-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-11T22:43:17.250-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="dcm4chee" /><category scheme="http://www.blogger.com/atom/ns#" term="dicom" /><category scheme="http://www.blogger.com/atom/ns#" term="oracle" /><title>Setting Up dcm4chee for Oracle Database</title><content type="html">Hi Folks!&lt;br /&gt;&lt;br /&gt;I'm starting my masters degree this year and I wrote an interesting research project to build a complete medical image processing server which works together with &lt;a href="http://www.dcm4che.org/confluence/display/ee2/Home"&gt;dcm4chee&lt;/a&gt;: a &lt;a href="http://medical.nema.org/"&gt;DICOM&lt;/a&gt; clinical data manager system. In this post I will show you how to setup dcm4chee properly using the great and free Oracle Express Database. This tutorial is for Windows.&lt;br /&gt;&lt;br /&gt;Firstly, download &lt;a href="http://www.oracle.com/technology/software/products/database/xe/index.html"&gt;OracleXE&lt;/a&gt; and launch it. The installation is quite simple and intuitive. When asked create the system account that will manage the database, so type &lt;b&gt;system&lt;/b&gt; for username and &lt;b&gt;manager&lt;/b&gt; for password. Wait copying its files and then finish the wizard. On the Windows command prompt access the directory: &lt;br /&gt;&lt;br /&gt;&lt;code&gt;oraclexe\app\oracle\product\10.2.0\server\BIN&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;...and execute the &lt;b&gt;sqlplus.exe&lt;/b&gt; program. You will be asked for entering an username and password, which is &lt;b&gt;system&lt;/b&gt; and &lt;b&gt;manager&lt;/b&gt;. If no problems occurred you are now connected to Oracle and will get the &lt;b&gt;C:\SQL&amp;gt&lt;/b&gt; command line.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cf7FMZ7swNk/R46x7kFfwSI/AAAAAAAAAB0/r1iCH8o5hR4/s1600-h/sqlplus.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_cf7FMZ7swNk/R46x7kFfwSI/AAAAAAAAAB0/r1iCH8o5hR4/s320/sqlplus.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5156254260242923810" /&gt;&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The Oracle Express brings a clear web interface where you may perform the database management, however, it uses the Jetty server that works on HTTP port 8080. If you try to run any other server like JBoss you'll get stuck at errors because port 8080 wont't be available. To overcome this issue you must change the HTTP port for Oracle. On SqlPlus type the following SQL commands:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;SQL&gt; begin&lt;br /&gt;  2  dbms_xdb.sethttpport('18080');&lt;br /&gt;  3  end;&lt;br /&gt;  4  /&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;After execute these lines you'll change Oracle HTTP port from 8080 to 18080. We must do it because dcm4chee works under JBoss server that also uses port 8080 for web access. Meanwhile, we're done with Oracle!&lt;br /&gt;&lt;br /&gt;Download &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=37982&amp;package_id=195374"&gt;dcm4chee&lt;/a&gt; binaries for Oracle and also get the amazing &lt;a href="http://labs.jboss.com/jbossas/downloads/"&gt;JBoss&lt;/a&gt; application server. I chose version 2.13.0 of dcm4chee and the JBoss 4.2.2.GA release. Extract dcm4chee files at the root directory &lt;b&gt;"C:\"&lt;/b&gt;. Avoid using a directory that has a name which contains spaces as installation directory. So make it simple, just rename the extracted folder &lt;br /&gt;to &lt;code&gt;dcm4chee&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;The next step is to extract JBoss files to the root directory and then rename the new folder to &lt;code&gt;jboss&lt;/code&gt;. When finished, you have to copy some files from JBoss to dcm4chee by executing &lt;b&gt;install_jboss.bat&lt;/b&gt; with the path of your JBoss installation directory as parameter. Access the Windows command prompt to execute the script. Eg. &lt;code&gt;C:\dcm4chee\bin&gt;intall_jboss.bat C:\jboss&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cf7FMZ7swNk/R46yfUFfwTI/AAAAAAAAAB8/s_aBRXNgKZU/s1600-h/copy.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_cf7FMZ7swNk/R46yfUFfwTI/AAAAAAAAAB8/s_aBRXNgKZU/s320/copy.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5156254874423247154" /&gt;&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;That's it, dcm4chee is almost done! Come back to Oracle for creating your PACS database. Again, access the SqlPlus with your system account and execute the commands below. They create a new Oracle tablespace named &lt;b&gt;pacsdb&lt;/b&gt; and a new database user &lt;b&gt;pacs&lt;/b&gt;. Every dcm4chee data will be stored based on these configurations.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;CREATE TABLESPACE pacsdb&lt;br /&gt;DATAFILE 'C:\xxx\pacsdb.ORA' SIZE 5M&lt;br /&gt;AUTOEXTEND ON NEXT 5120K&lt;br /&gt;DEFAULT STORAGE (INITIAL 10K NEXT 50K MINEXTENTS 1 MAXEXTENTS 121 PCTINCREASE 10) ONLINE;&lt;br /&gt;&lt;br /&gt;CREATE USER pacs IDENTIFIED BY pacs&lt;br /&gt;DEFAULT TABLESPACE pacsdb TEMPORARY TABLESPACE TEMP&lt;br /&gt;QUOTA UNLIMITED ON pacsdb;&lt;br /&gt;&lt;br /&gt;GRANT DBA TO pacs WITH ADMIN OPTION;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Reopen the Windows command prompt and execute SqlPlus. Now you have to establish connection with Oracle through your new user &lt;b&gt;pacs&lt;/b&gt; and password &lt;b&gt;pacs&lt;/b&gt; for generating all tables, primary keys, indexes, and so on. Therefore, type the following command and wait:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;SQL&gt; @C:\dcm4chee\sql\create.ora;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;If no errors occurred your dcm4chee database is complete!&lt;br /&gt;&lt;br /&gt;Important Notes:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1)&lt;/b&gt; dcm4chee doesn't contain an appropriate Jdbc driver for Oracle, so you need to &lt;a href="http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/index.html"&gt;download&lt;/a&gt; this driver and copy it to &lt;code&gt;dcm4chee\server\default\lib\&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2)&lt;/b&gt;Use OCI connection for OracleXE. Change de Jdbc url connection in &lt;code&gt;dcm4chee\server\default\deploy\pacs-oracle-ds.xml&lt;/code&gt;. Locate the tag &lt;code&gt;&amp;ltconnection-url&amp;gt&lt;/code&gt; and change its content to &lt;b&gt;jdbc:oracle:oci:@xe&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3)&lt;/b&gt; Search Oracle installation directory for &lt;b&gt;ocijdbc10g.dll&lt;/b&gt; and copy this file to &lt;code&gt;dcm4chee\bin\native\&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Mission accomplished! Open the Windows command prompt, access &lt;code&gt;dcm4chee\bin&lt;/code&gt; directory and execute &lt;b&gt;run.bat&lt;/b&gt; to startup JBoss server. Finally, open your preffered web browser and go to &lt;b&gt;localhost:8080/dcm4chee-web&lt;/b&gt; to see dcm4chee in action!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cf7FMZ7swNk/R462WkFfwVI/AAAAAAAAACM/j_qbv3E00T8/s1600-h/working.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_cf7FMZ7swNk/R462WkFfwVI/AAAAAAAAACM/j_qbv3E00T8/s320/working.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5156259122145902930" /&gt;&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you have any problems with this tutorial just let me know. &lt;br /&gt;See you on the next post :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7177607294183739662-1114369759207495862?l=samucs.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/9RZlnXK-esRQWNLOze4las6hZco/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/9RZlnXK-esRQWNLOze4las6hZco/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/9RZlnXK-esRQWNLOze4las6hZco/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/9RZlnXK-esRQWNLOze4las6hZco/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Samucs-dev/~4/tQK7EmODRQU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://samucs.blogspot.com/feeds/1114369759207495862/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=7177607294183739662&amp;postID=1114369759207495862" title="21 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/1114369759207495862?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/1114369759207495862?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Samucs-dev/~3/tQK7EmODRQU/setting-up-dcm4chee-for-oracle-database.html" title="Setting Up dcm4chee for Oracle Database" /><author><name>Samuel Covas Salomão</name><uri>http://www.blogger.com/profile/16148621879398945798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="22" height="32" src="http://4.bp.blogspot.com/_cf7FMZ7swNk/Sbr0Wr6hmaI/AAAAAAAAAFE/xFhE3D7G1y4/S220/black.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_cf7FMZ7swNk/R46x7kFfwSI/AAAAAAAAAB0/r1iCH8o5hR4/s72-c/sqlplus.PNG" height="72" width="72" /><thr:total>21</thr:total><feedburner:origLink>http://samucs.blogspot.com/2008/01/setting-up-dcm4chee-for-oracle-database.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkYNRnc_cSp7ImA9WxRaEEs.&quot;"><id>tag:blogger.com,1999:blog-7177607294183739662.post-816854618684854124</id><published>2007-11-28T09:18:00.000-08:00</published><updated>2008-12-11T22:43:17.949-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-11T22:43:17.949-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="video" /><category scheme="http://www.blogger.com/atom/ns#" term="download" /><category scheme="http://www.blogger.com/atom/ns#" term="youtube" /><category scheme="http://www.blogger.com/atom/ns#" term="flv" /><title>Get rid of YouTube Downloaders! Firebug it!</title><content type="html">Hi everyone,&lt;br /&gt;&lt;br /&gt;If you are trying to download videos and always get stuck at YouTube downloader programs, don't worry, just Firebug it!&lt;br /&gt;&lt;br /&gt;The amazing browser Mozilla Firefox is not a simple browser, but a rich and helpful tool for web developers and programmers. Among its extensions we can find one that may upset some world wide portals, I present you &lt;a href="http://www.getfirebug.com"&gt;Firebug&lt;/a&gt;. Firebug "integrates with Firefox to put a wealth of web development tools at your fingertips while you browse. You can edit, debug, and monitor CSS, HTML, and JavaScript live in any web page".&lt;br /&gt;&lt;br /&gt;These days I was trying to download videos from YouTube using some programs that claim to do that easily. However, I got stuck all the time! The programs really didn't work at all. So I decide to have a look at YouTube site through Firebug tool under Mozilla Firefox. There was the key! YouTube videos are "hidden" on different servers and URLs. It's speculation but I believe this is why downloader programs can't do the trick, they are not able to reach those servers and URLs. Using Firebug  I could download my favourite videos properly.&lt;br /&gt;&lt;br /&gt;First you have to download and install &lt;a href="http://www.mozilla.com"&gt;Mozilla Firefox&lt;/a&gt;. When finished, install &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/1843"&gt;Firebug&lt;/a&gt; on Firefox. Then restart the browser and be sure you have this icon at the browser bottom right corner:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cf7FMZ7swNk/R07ikMnoGDI/AAAAAAAAABU/xFO7Utullkg/s1600-h/firebug1.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_cf7FMZ7swNk/R07ikMnoGDI/AAAAAAAAABU/xFO7Utullkg/s320/firebug1.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5138293336366913586" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;To start working with Firebug and YouTube videos you need to access the YouTube site first. Then, just click on Firebug's green icon to open its tool panel. Now you have something like this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cf7FMZ7swNk/R07iq8noGEI/AAAAAAAAABc/qY0vdDGHUkg/s1600-h/firebug2.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_cf7FMZ7swNk/R07iq8noGEI/AAAAAAAAABc/qY0vdDGHUkg/s320/firebug2.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5138293452331030594" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Inside Firebug's panel you can debug Javascripts, inspect Html tags, explore the Html DOM tree, watch the XmlHttpRequest asynchronous requests and even know how long does every object on the page take to be downloaded by the browser. It's really amazing! Now as you were introduced to Firebug, let's see how to download your favourite YouTube videos.&lt;br /&gt;&lt;br /&gt;Search for your video at &lt;a href="http://www.youtube.com"&gt;YouTube.com&lt;/a&gt; and then click on it to start watching. Be sure that is this video you want to download. Now comes Firebug magic! Click on its green icon to open the tool panel. There is a tab named "Net", select it. This tab shows every object on the page and its respective download time. Now just hit &lt;span style="font-weight:bold;"&gt;Ctrl+F5&lt;/span&gt; to refresh the page and see each object being downloaded by the browser.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cf7FMZ7swNk/R07izsnoGFI/AAAAAAAAABk/gdK75krfojA/s1600-h/firebug3.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_cf7FMZ7swNk/R07izsnoGFI/AAAAAAAAABk/gdK75krfojA/s320/firebug3.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5138293602654885970" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Look at the red arrow (it's my arrow). There it is, your favourite video waiting for you to be downloaded. Can you see the real video URL? No more words, let's download the video. Right click the line where you see "get_video" followed by a weird URL and then hit "Open in new tab". Wow, Firefox want me to save a FLV (Flash Video) file? Yes, just do it.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cf7FMZ7swNk/R07i8cnoGGI/AAAAAAAAABs/RdDJ9zS1AhQ/s1600-h/firebug4.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_cf7FMZ7swNk/R07i8cnoGGI/AAAAAAAAABs/RdDJ9zS1AhQ/s320/firebug4.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5138293752978741346" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Wait until the download is finished. The last step is rename the downloaded file from "get_video" to "youfilename.flv".&lt;br /&gt;&lt;br /&gt;That's all folks!&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7177607294183739662-816854618684854124?l=samucs.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/lukZjd-L_Qo3aogXDhGv7kiu2RA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/lukZjd-L_Qo3aogXDhGv7kiu2RA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/lukZjd-L_Qo3aogXDhGv7kiu2RA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/lukZjd-L_Qo3aogXDhGv7kiu2RA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Samucs-dev/~4/Y6le74Jyzrs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://samucs.blogspot.com/feeds/816854618684854124/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=7177607294183739662&amp;postID=816854618684854124" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/816854618684854124?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/816854618684854124?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Samucs-dev/~3/Y6le74Jyzrs/get-rid-of-youtube-downloaders-firebug.html" title="Get rid of YouTube Downloaders! Firebug it!" /><author><name>Samuel Covas Salomão</name><uri>http://www.blogger.com/profile/16148621879398945798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="22" height="32" src="http://4.bp.blogspot.com/_cf7FMZ7swNk/Sbr0Wr6hmaI/AAAAAAAAAFE/xFhE3D7G1y4/S220/black.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_cf7FMZ7swNk/R07ikMnoGDI/AAAAAAAAABU/xFO7Utullkg/s72-c/firebug1.bmp" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://samucs.blogspot.com/2007/11/get-rid-of-youtube-downloaders-firebug.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkYNSX85eyp7ImA9WxRaEEs.&quot;"><id>tag:blogger.com,1999:blog-7177607294183739662.post-4146906003333255736</id><published>2007-10-03T14:18:00.000-07:00</published><updated>2008-12-11T22:43:18.123-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-11T22:43:18.123-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><category scheme="http://www.blogger.com/atom/ns#" term="opengl" /><category scheme="http://www.blogger.com/atom/ns#" term="game" /><title>A Game Engine Project</title><content type="html">Hi Folks!&lt;br /&gt;&lt;br /&gt;From the last three years I've been working hard on a project I called MyGameEngine. The goal was to build a simple game engine where programmers may create their own virtual worlds, or their own 3D games!&lt;br /&gt;&lt;br /&gt;On this post I bring you this great project. It's entirely written in C++ code and the whole graphical stuff was developed through the OpenGL API. If you're interested in downloading the project source code just let me know: &lt;span style="font-weight:bold;"&gt;samucs@gmail.com&lt;/span&gt;. Meanwhile this blog doesn't support downloads.&lt;br /&gt;&lt;br /&gt;Below I present a screenshot of MyGameEngine in action!&lt;br /&gt;Enjoy!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cf7FMZ7swNk/RwQRP4gDijI/AAAAAAAAAAs/v420SCPlzQw/s1600-h/shot1.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_cf7FMZ7swNk/RwQRP4gDijI/AAAAAAAAAAs/v420SCPlzQw/s320/shot1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5117234041162271282" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7177607294183739662-4146906003333255736?l=samucs.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/0pc4JUYtGPGY4r_a6Js02lLuIaw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/0pc4JUYtGPGY4r_a6Js02lLuIaw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/0pc4JUYtGPGY4r_a6Js02lLuIaw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/0pc4JUYtGPGY4r_a6Js02lLuIaw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Samucs-dev/~4/53P1wADWLAQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://samucs.blogspot.com/feeds/4146906003333255736/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=7177607294183739662&amp;postID=4146906003333255736" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/4146906003333255736?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/4146906003333255736?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Samucs-dev/~3/53P1wADWLAQ/game-engine-project.html" title="A Game Engine Project" /><author><name>Samuel Covas Salomão</name><uri>http://www.blogger.com/profile/16148621879398945798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="22" height="32" src="http://4.bp.blogspot.com/_cf7FMZ7swNk/Sbr0Wr6hmaI/AAAAAAAAAFE/xFhE3D7G1y4/S220/black.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_cf7FMZ7swNk/RwQRP4gDijI/AAAAAAAAAAs/v420SCPlzQw/s72-c/shot1.jpg" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://samucs.blogspot.com/2007/10/game-engine-project.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkQBQX4-fSp7ImA9WB9SFEk.&quot;"><id>tag:blogger.com,1999:blog-7177607294183739662.post-7547500181435434109</id><published>2007-10-03T04:12:00.000-07:00</published><updated>2007-10-03T13:45:50.055-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-10-03T13:45:50.055-07:00</app:edited><title>Welcome</title><content type="html">Welcome to my blog! I'm Samuel and here you'll find a lot of stuff related to computer science, programming, research and development, and some unknown mysteries. Feel free to post any comment! Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7177607294183739662-7547500181435434109?l=samucs.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/AcRkrxAS3yTwgijPob3Uj1QWx6k/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/AcRkrxAS3yTwgijPob3Uj1QWx6k/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/AcRkrxAS3yTwgijPob3Uj1QWx6k/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/AcRkrxAS3yTwgijPob3Uj1QWx6k/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Samucs-dev/~4/ZG5H9We8jTo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://samucs.blogspot.com/feeds/7547500181435434109/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=7177607294183739662&amp;postID=7547500181435434109" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/7547500181435434109?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7177607294183739662/posts/default/7547500181435434109?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Samucs-dev/~3/ZG5H9We8jTo/welcome.html" title="Welcome" /><author><name>Samuel Covas Salomão</name><uri>http://www.blogger.com/profile/16148621879398945798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="22" height="32" src="http://4.bp.blogspot.com/_cf7FMZ7swNk/Sbr0Wr6hmaI/AAAAAAAAAFE/xFhE3D7G1y4/S220/black.JPG" /></author><thr:total>1</thr:total><feedburner:origLink>http://samucs.blogspot.com/2007/10/welcome.html</feedburner:origLink></entry></feed>

