GDCM 2.2.0

- Main Page
- Related Pages
- Namespaces
- Classes
- Files
- Directories
- Examples

AWTMedical3.java

    /*=========================================================================

      Program: GDCM (Grassroots DICOM). A DICOM library

      Copyright (c) 2006-2011 Mathieu Malaterre
      All rights reserved.
      See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.

         This software is distributed WITHOUT ANY WARRANTY; without even
         the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
         PURPOSE.  See the above copyright notice for more information.

    =========================================================================*/
    package examples;

    import vtk.*;
    //import gdcm.*;

    import vtk.util.VtkPanelContainer;
    import vtk.util.VtkPanelUtil;
    import vtk.util.VtkUtil;

    import java.util.ArrayList;

    import javax.swing.*;
    import java.awt.*;
    import java.io.File;

    public class AWTMedical3  extends JComponent implements VtkPanelContainer {

      private vtkPanel renWin;

        vtkImageData ReadDataFile(File inSelectedFile){

            vtkImageData outImageData = null;
            Directory theDir = new Directory();

            String theInputDirectory = inSelectedFile.getPath();
            theDir.Load(theInputDirectory);

            Scanner theScanner = new Scanner();
            Tag theStudyTag = new Tag(0x0020,0x000d);
            Tag theSeriesTag = new Tag(0x0020,0x000e);
            theScanner.AddTag(theStudyTag);//get studies,
            theScanner.AddTag(theSeriesTag);//get studies,
            theScanner.Scan(theDir.GetFilenames());

            FilenamesType theStudyValues = theScanner.GetOrderedValues(theStudyTag);
            long theNumStudies = theStudyValues.size();
            //for now, take the first study, and nothing else.
            //and the return is actually not FilenamesType, just a
            //vector of strings
            if (theNumStudies != 1)
                return outImageData;
            String theStudyVal = theStudyValues.get(0);
            //now, get all the values from the scanner that are in that
            //study, then from that get their different series
            FilenamesType theFilenames =
                    theScanner.GetAllFilenamesFromTagToValue(theStudyTag, theStudyVal);

            //from that set of filenames, isolate individual series
            //conclude that singleton series = RT struct (can do further
            //checking for things like MIPs and the like)
            //and multiple series entries = volumetric data
            theScanner.Scan(theFilenames);
            FilenamesType theSeriesValues = theScanner.GetOrderedValues(theSeriesTag);
            String studyUID = theScanner.GetValue(theScanner.GetFilenames().get(0), theStudyTag);
            long theNumSeries = theSeriesValues.size();
            for (int i = 0; i < theNumSeries; i++) {
                FilenamesType theSeriesFiles =
                    theScanner.GetAllFilenamesFromTagToValue(theSeriesTag, theSeriesValues.get(i));
                long theNumFilesInSeries = theSeriesFiles.size();
                if (theNumFilesInSeries > 1) {//assume it's CT or volumetric data
                    //for now, assume a single volume
                    //could have multiples, like PET and CT

                    IPPSorter sorter = new IPPSorter();
                    sorter.SetComputeZSpacing(true);
                    sorter.SetZSpacingTolerance(0.001);
                    Boolean sorted = sorter.Sort(theSeriesFiles);
                    if (!sorted){
                        //need some better way to handle failures here
                        return outImageData;
                    }

                    FilenamesType sortedFT = sorter.GetFilenames();
                    long theSize = sortedFT.size();
                    vtkStringArray sa = new vtkStringArray();
                    ArrayList<String> theStrings = new ArrayList<String>();

                    vtkGDCMImageReader gdcmReader = new vtkGDCMImageReader();
                    for (int j = 0; j < theSize; j++) {
                        String theFileName = sortedFT.get(j);
                        if (gdcmReader.CanReadFile(theFileName) > 0){
                            theStrings.add(theFileName);
                            sa.InsertNextValue(theFileName);
                        } else {
                            //this is a busted series
                            //need some more appropriate error here
                            return outImageData;
                        }
                    }

                    gdcmReader.SetFileNames(sa);

                    gdcmReader.Update();

                    outImageData = gdcmReader.GetOutput();//the zeroth output should be the image
                }
            }
            String theImageInfo = "";
            if (outImageData != null){
                theImageInfo = outImageData.Print();
            }
            return outImageData;
        }

        //this function is a rewrite of Medical3 to see if data can
        //be loaded via gdcm easily
      public AWTMedical3(File inFile) {
        // Create the buttons.
        renWin = new vtkPanel();

        vtkImageData theImageData = ReadDataFile(inFile);

        // An isosurface, or contour value of 500 is known to correspond to the
        // skin of the patient. Once generated, a vtkPolyDataNormals filter is
        // is used to create normals for smooth surface shading during rendering.
        // The triangle stripper is used to create triangle strips from the
        // isosurface these render much faster on some systems.
        vtkContourFilter skinExtractor = new vtkContourFilter();
        skinExtractor.SetInput(theImageData);
        skinExtractor.SetValue(0, 500);
        vtkPolyDataNormals skinNormals = new vtkPolyDataNormals();
        skinNormals.SetInput(skinExtractor.GetOutput());
        skinNormals.SetFeatureAngle(60.0);
    //        vtkStripper skinStripper = new vtkStripper();
    //        skinStripper.SetInput(skinNormals.GetOutput());
        vtkPolyDataMapper skinMapper = new vtkPolyDataMapper();
        skinMapper.SetInput(skinNormals.GetOutput());
        skinMapper.ScalarVisibilityOff();
        vtkActor skin = new vtkActor();
        skin.SetMapper(skinMapper);
        skin.GetProperty().SetDiffuseColor(1, .49, .25);
        skin.GetProperty().SetSpecular(.3);
        skin.GetProperty().SetSpecularPower(20);

        // An isosurface, or contour value of 1150 is known to correspond to the
        // skin of the patient. Once generated, a vtkPolyDataNormals filter is
        // is used to create normals for smooth surface shading during rendering.
        // The triangle stripper is used to create triangle strips from the
        // isosurface these render much faster on some systems.
        vtkContourFilter boneExtractor = new vtkContourFilter();
        boneExtractor.SetInput(theImageData);
        boneExtractor.SetValue(0, 1150);
        vtkPolyDataNormals boneNormals = new vtkPolyDataNormals();
        boneNormals.SetInput(boneExtractor.GetOutput());
        boneNormals.SetFeatureAngle(60.0);
        vtkStripper boneStripper = new vtkStripper();
        boneStripper.SetInput(boneNormals.GetOutput());
        vtkPolyDataMapper boneMapper = new vtkPolyDataMapper();
        boneMapper.SetInput(boneStripper.GetOutput());
        boneMapper.ScalarVisibilityOff();
        vtkActor bone = new vtkActor();
        bone.SetMapper(boneMapper);
        bone.GetProperty().SetDiffuseColor(1, 1, .9412);

        // An outline provides context around the data.
        vtkOutlineFilter outlineData = new vtkOutlineFilter();
        outlineData.SetInput(theImageData);
        vtkPolyDataMapper mapOutline = new vtkPolyDataMapper();
        mapOutline.SetInput(outlineData.GetOutput());
        vtkActor outline = new vtkActor();
        outline.SetMapper(mapOutline);
        outline.GetProperty().SetColor(0, 0, 0);

        // Now we are creating three orthogonal planes passing through the
        // volume. Each plane uses a different texture map and therefore has
        // diferent coloration.

        // Start by creatin a black/white lookup table.
        vtkLookupTable bwLut = new vtkLookupTable();
        bwLut.SetTableRange(0, 2000);
        bwLut.SetSaturationRange(0, 0);
        bwLut.SetHueRange(0, 0);
        bwLut.SetValueRange(0, 1);
        bwLut.Build();

        // Now create a lookup table that consists of the full hue circle (from
        // HSV);.
        vtkLookupTable hueLut = new vtkLookupTable();
        hueLut.SetTableRange(0, 2000);
        hueLut.SetHueRange(0, 1);
        hueLut.SetSaturationRange(1, 1);
        hueLut.SetValueRange(1, 1);
        hueLut.Build();

        // Finally, create a lookup table with a single hue but having a range
        // in the saturation of the hue.
        vtkLookupTable satLut = new vtkLookupTable();
        satLut.SetTableRange(0, 2000);
        satLut.SetHueRange(.6, .6);
        satLut.SetSaturationRange(0, 1);
        satLut.SetValueRange(1, 1);
        satLut.Build();

        // Create the first of the three planes. The filter vtkImageMapToColors
        // maps the data through the corresponding lookup table created above.
        // The vtkImageActor is a type of vtkProp and conveniently displays an
        // image on a single quadrilateral plane. It does this using texture
        // mapping and as a result is quite fast. (Note: the input image has to
        // be unsigned char values, which the vtkImageMapToColors produces.);
        // Note also that by specifying the DisplayExtent, the pipeline
        // requests data of this extent and the vtkImageMapToColors only
        // processes a slice of data.
        vtkImageMapToColors saggitalColors = new vtkImageMapToColors();
        saggitalColors.SetInput(theImageData);
        saggitalColors.SetLookupTable(bwLut);
        vtkImageActor saggital = new vtkImageActor();
        saggital.SetInput(saggitalColors.GetOutput());
        saggital.SetDisplayExtent(32, 32, 0, 63, 0, 92);

        // Create the second (axial); plane of the three planes. We use the same
        // approach as before except that the extent differs.
        vtkImageMapToColors axialColors = new vtkImageMapToColors();
        axialColors.SetInput(theImageData);
        axialColors.SetLookupTable(hueLut);
        vtkImageActor axial = new vtkImageActor();
        axial.SetInput(axialColors.GetOutput());
        axial.SetDisplayExtent(0, 63, 0, 63, 46, 46);

        // Create the third (coronal); plane of the three planes. We use the same
        // approach as before except that the extent differs.
        vtkImageMapToColors coronalColors = new vtkImageMapToColors();
        coronalColors.SetInput(theImageData);
        coronalColors.SetLookupTable(satLut);
        vtkImageActor coronal = new vtkImageActor();
        coronal.SetInput(coronalColors.GetOutput());
        coronal.SetDisplayExtent(0, 63, 32, 32, 0, 92);

        // It is convenient to create an initial view of the data. The FocalPoint
        // and Position form a vector direction. Later on (ResetCamera() method)
        // this vector is used to position the camera to look at the data in
        // this direction.
        vtkCamera aCamera = new vtkCamera();
        aCamera.SetViewUp(0, 0, -1);
        aCamera.SetPosition(0, 1, 0);
        aCamera.SetFocalPoint(0, 0, 0);
        aCamera.ComputeViewPlaneNormal();

        // Actors are added to the renderer. An initial camera view is created.
        // The Dolly() method moves the camera towards the FocalPoint,
        // thereby enlarging the image.
        renWin.GetRenderer().AddActor(saggital);
        renWin.GetRenderer().AddActor(axial);
        renWin.GetRenderer().AddActor(coronal);
        renWin.GetRenderer().AddActor(outline);
        renWin.GetRenderer().AddActor(skin);
        renWin.GetRenderer().AddActor(bone);

        // Turn off bone for this example.
        bone.VisibilityOff();

        // Set skin to semi-transparent.
        skin.GetProperty().SetOpacity(0.5);

        // An initial camera view is created.  The Dolly() method moves
        // the camera towards the FocalPoint, thereby enlarging the image.
        renWin.GetRenderer().SetActiveCamera(aCamera);
        renWin.GetRenderer().ResetCamera();
        aCamera.Dolly(1.5);

        // Set a background color for the renderer and set the size of the
        // render window (expressed in pixels).
        renWin.GetRenderer().SetBackground(1, 1, 1);
        VtkPanelUtil.setSize(renWin, 640, 480);

        // Note that when camera movement occurs (as it does in the Dolly()
        // method), the clipping planes often need adjusting. Clipping planes
        // consist of two planes: near and far along the view direction. The
        // near plane clips out objects in front of the plane the far plane
        // clips out objects behind the plane. This way only what is drawn
        // between the planes is actually rendered.
        renWin.GetRenderer().ResetCameraClippingRange();

        // Setup panel
        setLayout(new BorderLayout());
        add(renWin, BorderLayout.CENTER);
      }

      public vtkPanel getRenWin() {
        return renWin;
      }

      public static void main(String s[]) {
        if (s.length == 0){
          return; //need a filename here
        }
        File theFile = new File(s[0]);
        //File theFile = new File("/Users/mmroden/Documents/MVSDownloadDirectory/Documents/1.2.840.113704.1.111.3384.1271766367.5/");
        AWTMedical3 panel = new AWTMedical3(theFile);

        JFrame frame = new JFrame("AWTMedical3");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add("Center", panel);
        frame.pack();
        frame.setVisible(true);
      }

    }