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
// different coloration.
// Start by creating 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 sagittalColors = new vtkImageMapToColors();
sagittalColors.SetInput(theImageData);
sagittalColors.SetLookupTable(bwLut);
vtkImageActor sagittal = new vtkImageActor();
sagittal.SetInput(sagittalColors.GetOutput());
sagittal.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(sagittal);
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);
}
}
vtkGDCMImageReader
Definition vtkGDCMImageReader.h:105
vtkGDCMImageReader::SetFileNames
virtual void SetFileNames(vtkStringArray *)
vtkGDCMImageReader::CanReadFile
virtual int CanReadFile(const char *fname)