30 #include <QApplication>    32 #include "milxQtImage.h"    33 #include "milxQtModel.h"    34 #include "milxQtPlot.h"    35 #include "milxQtFile.h"    37 #include <vtkWindowToImageFilter.h>    39 #include <tclap/CmdLine.h>     41 using namespace TCLAP;
    43 int main(
int argc, 
char* argv[])
    45     QApplication app(argc,argv);
    46     QMainWindow mainWindow;
    49     CmdLine cmd(
"A visualisation tool for labelled images", 
' ', 
milx::NumberToString(milx::Version));
    52     ValueArg<std::string> labelledImageArg(
"l", 
"labels", 
"Labelled image to visualise", 
true, 
"seg.nii.gz", 
"Labels");
    54     ValueArg<std::string> outputArg(
"o", 
"output", 
"Output Screenshot name", 
false, 
"screenshot.png", 
"Output");
    55     ValueArg<std::string> saveArg(
"", 
"save", 
"Save the mesh generated with name. Only for non-volume output.", 
false, 
"surface.vtk", 
"Save");
    56     ValueArg<std::string> surfaceArg(
"s", 
"surface", 
"Surface to overlay with labelled image", 
false, 
"surface.vtk", 
"Surface");
    57     ValueArg<std::string> transformArg(
"t", 
"transform", 
"Transform (ITK Format) to apply to objects being rendered", 
false, 
"rigid.txt", 
"Transform");
    58     ValueArg<std::string> loadViewFileArg(
"", 
"loadviewfile", 
"Load saved view from file (use onscreen mode to save view files)", 
false, 
"camera.cam", 
"Load View File");
    59     ValueArg<float> aboveArg(
"", 
"above", 
"Add above value to thresholding of the labels. Controls max of scalar range of colourmap also.", 
false, 255, 
"Above");
    60     ValueArg<float> belowArg(
"", 
"below", 
"Add below value to thresholding of the labels. Controls min of scalar range of colourmap also.", 
false, 0, 
"Below");
    61     ValueArg<float> opacityArg(
"", 
"opacity", 
"Set the opacity of the surface", 
false, 0.5, 
"Opacity");
    62     ValueArg<float> zoomArg(
"", 
"zoom", 
"Zoom in on the current view by given factor.", 
false, 2.0, 
"Zoom");
    63     ValueArg<int> heightArg(
"y", 
"height", 
"Set the height of the window.", 
false, 600, 
"Height");
    64     ValueArg<int> widthArg(
"x", 
"width", 
"Set the width of the window.", 
false, 800, 
"Width");
    65     ValueArg<int> linearDivisionArg(
"", 
"lineardivision", 
"Evenly space the label values across N to get full use of colourmap.", 
false, 16, 
"Linear Division");
    66     ValueArg<int> linearOffsetArg(
"", 
"linearoffset", 
"Offset the even spacing of the label values across N to get full use of colourmap.", 
false, 1, 
"Linear Offset");
    68     SwitchArg onscreenArg(
"", 
"onscreen", 
"Enable on screen rendering, i.e. display the rendering as an interactive window.", 
false);
    69     SwitchArg inverseArg(
"", 
"inverse", 
"Use the inverse transform when transform file is provided.", 
false);
    70     SwitchArg whiteArg(
"", 
"white", 
"Make background white rather than default gradient colour.", 
false);
    71     SwitchArg loadViewArg(
"", 
"loadview", 
"Load saved view (use smilx or onscreen render mode to view and save with Right Click->View->Save View", 
false);
    72     SwitchArg humanArg(
"", 
"nohuman", 
"Disable human orientation glyph.", 
false);
    73     SwitchArg processArg(
"", 
"postprocess", 
"Process the resulting surfaces from labels to reduce vertices and smooth etc.", 
false);
    74     SwitchArg oversmoothArg(
"", 
"oversmooth", 
"Process the resulting surfaces from labels with oversmoothing. Option is for Postprocess argument.", 
false);
    75     SwitchArg volumeArg(
"", 
"volume", 
"Display using volume rendering instead of marching cude iso-surfaces.", 
false);
    76     SwitchArg lineariseArg(
"", 
"linearise", 
"Evenly space the label values to get full use of colourmap.", 
false);
    77     SwitchArg wireframeArg(
"", 
"wireframe", 
"Display surface as a wireframe model.", 
false);
    78     SwitchArg axialArg(
"", 
"axial", 
"Show axial view based on position of first surface.", 
false);
    79     SwitchArg coronalArg(
"", 
"coronal", 
"Show coronal view based on position of first surface.", 
false);
    80     SwitchArg saggitalArg(
"", 
"saggital", 
"Show saggital view based on position of first surface.", 
false);
    82     SwitchArg jetArg(
"", 
"jet", 
"Change colourmap of the scalars to the Jet map (default)", 
false);
    83     SwitchArg vtkArg(
"", 
"vtk", 
"Change colourmap of the scalars to blue-red (rainbow VTK) map", 
false);
    84     SwitchArg hsvArg(
"", 
"hsv", 
"Change colourmap of the scalars to blue-red (rainbow HSV) map", 
false);
    85     SwitchArg rainbowArg(
"", 
"rainbow", 
"Change colourmap of the scalars to the rainbow map", 
false);
    86     SwitchArg spectralArg(
"", 
"spectral", 
"Change colourmap of the scalars to the spectral map", 
false);
    87     SwitchArg nihArg(
"", 
"NIH", 
"Change colourmap of the scalars to NIH", 
false);
    88     SwitchArg fireArg(
"", 
"NIH_FIRE", 
"Change colourmap of the scalars to NIH Fire", 
false);
    89     SwitchArg aalArg(
"", 
"AAL", 
"Change colourmap of the scalars to AAL", 
false);
    90     SwitchArg hotArg(
"", 
"HOT", 
"Change colourmap of the scalars to HOT", 
false);
    93     cmd.add( labelledImageArg );
    96     cmd.add( surfaceArg );
    97     cmd.add( transformArg );
    98     cmd.add( loadViewFileArg );
   101     cmd.add( opacityArg );
   103     cmd.add( heightArg );
   105     cmd.add( linearDivisionArg );
   106     cmd.add( linearOffsetArg );
   108     cmd.add( onscreenArg );
   109     cmd.add( inverseArg );
   111     cmd.add( loadViewArg );
   113     cmd.add( processArg );
   114     cmd.add( oversmoothArg );
   115     cmd.add( volumeArg );
   116     cmd.add( lineariseArg );
   117     cmd.add( wireframeArg );
   119     cmd.add( coronalArg );
   120     cmd.add( saggitalArg );
   125     cmd.add( rainbowArg );
   126     cmd.add( spectralArg );
   133     cmd.parse( argc, argv );
   136     const std::string labelsName = labelledImageArg.getValue();
   137     const std::string screenName = outputArg.getValue();
   138     const std::string fileName = saveArg.getValue();
   139     const std::string surfaceName = surfaceArg.getValue();
   140     const std::string transformName = transformArg.getValue();
   141     const std::string loadViewName = loadViewFileArg.getValue();
   142     const float aboveValue = aboveArg.getValue();
   143     const float belowValue = belowArg.getValue();
   144     const float opacity = opacityArg.getValue();
   145     const float zoomFactor = zoomArg.getValue();
   146     const int windowHeight = heightArg.getValue();
   147     const int windowWidth = widthArg.getValue();
   148     int N = linearDivisionArg.getValue();
   149     int offset = linearOffsetArg.getValue();
   153     if(inverseArg.isSet())
   155         if(!transformArg.isSet())
   157             cerr << 
"Error in arguments! Inverse argument needs to be used with the transform argument." << endl;
   163     vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New(); 
   164         transform->Identity();
   165         transform->PostMultiply();
   166     if(transformArg.isSet())
   169         transform->Concatenate(matrix);
   170         if(inverseArg.isSet())
   171             transform->Inverse();
   174     std::cerr << 
"Reading Header for type info etc." << std::endl;
   175     std::string pixelType, componentType;
   176     size_t dimensions = 3;
   179         milx::PrintError(
"Failed Reading Image. Check the image type/file. Exiting.");
   187     QScopedPointer<milxQtFile> reader(
new milxQtFile);
   188     QScopedPointer<milxQtImage> labelledImage(
new milxQtImage);  
   189     bool success = reader->openImage(labelsName.c_str(), labelledImage.data());
   190         labelledImage->setName(labelsName.c_str());
   191     if(aboveArg.isSet() || belowArg.isSet())
   192         labelledImage->threshold(0, belowValue, aboveValue);
   193         labelledImage->generateImage();
   196     QPointer<milxQtImage> eightBitImage;  
   197     if(componentType == 
"unsigned_char" || componentType == 
"unsigned char")
   199         eightBitImage = labelledImage.data();
   204         milx::PrintWarning(
"8-bit image not found and will be cast to 8-bit image for visualisation.");
   205         eightBitImage = 
new milxQtImage(labelledImage.data());
   208     eightBitImage->setName(labelsName.c_str());
   209     eightBitImage->generateImage();
   212     std::cout << 
">> " << values.size() << 
" Labels present: " << std::endl;
   213     for(
size_t j = 0; j < values.size(); j ++)
   214         std::cout << static_cast<unsigned>(values[j]) << 
", ";
   215     std::cout << std::endl;
   217     if(!linearDivisionArg.isSet())
   221     vtkSmartPointer<vtkLookupTable> lookupTable = vtkSmartPointer<vtkLookupTable>::New();
   222         lookupTable->SetTableRange(0.0, values.size()+1);
   223         lookupTable->Build();
   225     std::vector< QSharedPointer<milxQtModel> > isoSurfaces;
   227         model->setName(
"Label Surface Rendering");
   228         model->SetSize(windowHeight, windowWidth);
   229         model->generateRender();
   231 if(volumeArg.isSet())
   233     cout << 
">> Overlay: Volume Rendering" << endl;
   236     std::vector<float> colourValuesAsFloat, opacityValuesAsFloat;
   237     opacityValuesAsFloat.push_back(0.0); 
   238     colourValuesAsFloat.push_back(0.0); 
   239     for(
size_t j = 0; j < values.size(); j ++)
   241         opacityValuesAsFloat.push_back(1.0);
   242         colourValuesAsFloat.push_back( static_cast<float>(values[j]) );
   245     vtkSmartPointer<vtkImageFlip> imageReorient = vtkSmartPointer<vtkImageFlip>::New();
   246     #if VTK_MAJOR_VERSION <= 5   247         imageReorient->SetInput(eightBitImage->GetOutput());
   249         imageReorient->SetInputData(eightBitImage->GetOutput());
   251         imageReorient->SetFilteredAxis(1);
   252         imageReorient->FlipAboutOriginOn();
   253         imageReorient->Update(); 
   255     QScopedPointer<milxQtPlot> label(
new milxQtPlot);  
   256         label->SetSource(imageReorient->GetOutput(), 
true);
   257         label->setOpacityTransferValues(opacityValuesAsFloat);
   258         label->setColourTransferValues(colourValuesAsFloat);
   260         label->colourMapToJet(belowValue, aboveValue); 
   262         label->colourMapToVTK(belowValue, aboveValue);
   264         label->colourMapToHSV(belowValue, aboveValue);
   265     if(rainbowArg.isSet())
   266         label->colourMapToRainbow(belowValue, aboveValue);
   267     if(spectralArg.isSet())
   268         label->colourMapToSpectral(belowValue, aboveValue);
   270         label->colourMapToNIH(belowValue, aboveValue);
   272         label->colourMapToNIH_Fire(belowValue, aboveValue);
   274         label->colourMapToAAL(belowValue, aboveValue);
   276         label->colourMapToHOT(belowValue, aboveValue);
   277         label->volumePlot(imageReorient->GetOutput(), 
true, 
true);
   279     vtkVolumeCollection *volumeCollection = label->GetVolumes();
   281     volumeCollection->InitTraversal();
   282     vtkVolume * volume = volumeCollection->GetNextVolume();
   283     if(transformArg.isSet())
   284         volume->SetUserTransform(transform);
   285     model->AddVolume(volume);
   289     cout << 
">> Overlay: Isosurfacing" << endl;
   290     const float linearScale = (aboveValue-belowValue)/N;
   291     for(
size_t j = 0; j < values.size(); j ++)
   293         if(lineariseArg.isSet())
   294             std::cout << 
">> Iso surface label " << static_cast<unsigned>(values[j]) << 
" -> " << (j+offset)*linearScale << std::endl;
   296             std::cout << 
">> Iso surface label " << 
static_cast<unsigned>(values[j]) << std::endl;
   298         QScopedPointer<milxQtImage> label(
new milxQtImage);  
   299             label->SetInput(eightBitImage->GetCharImage());
   300             label->binaryThreshold(1.0, values[j], values[j]);
   301             label->generateImage();
   304             mdl->generateIsoSurface(label->GetOutput(), 0, 0.5);
   305         if(processArg.isSet())
   307             mdl->quadricDecimate(0.25);
   308             if(oversmoothArg.isSet())
   313         if(transformArg.isSet())
   314             mdl->SetTransform(transform);
   315             mdl->generateModel();
   318         model->colourMapToJet(belowValue, aboveValue); 
   320             model->colourMapToVTK(belowValue, aboveValue);
   322             model->colourMapToHSV(belowValue, aboveValue);
   323         if(rainbowArg.isSet())
   324             model->colourMapToRainbow(belowValue, aboveValue);
   325         if(spectralArg.isSet())
   326             model->colourMapToSpectral(belowValue, aboveValue);
   328             model->colourMapToNIH(belowValue, aboveValue);
   330             model->colourMapToNIH_Fire(belowValue, aboveValue);
   332             model->colourMapToAAL(belowValue, aboveValue);
   334             model->colourMapToHOT(belowValue, aboveValue);
   338         if(lineariseArg.isSet())
   339             model->GetLookupTable()->GetColor((j+offset)*linearScale, colour); 
   341             model->GetLookupTable()->GetColor(values[j], colour); 
   342         mdl->changeColour(colour[0], colour[1], colour[2]);
   344         model->AddActor(mdl->GetActor());
   345         isoSurfaces.push_back(mdl); 
   350         QSharedPointer<milxQtModel> labelMesh(
new milxQtModel);
   351         for(
size_t j = 0; j < isoSurfaces.size(); j ++)
   353             vtkSmartPointer<vtkPolyData> labelPolyData = vtkSmartPointer<vtkPolyData>::New();
   354             labelPolyData->DeepCopy(isoSurfaces[j].data()->GetOutput());
   355             vtkSmartPointer<vtkFloatArray> labelValueArray = vtkSmartPointer<vtkFloatArray>::New();
   356             labelValueArray->SetNumberOfComponents(1);
   357             labelValueArray->SetNumberOfTuples(labelPolyData->GetNumberOfPoints());
   358             labelValueArray->FillComponent(0, values[j]);
   359             labelPolyData->GetPointData()->SetScalars(labelValueArray);
   360             labelMesh->AddInput(labelPolyData);
   362         labelMesh->generateModel();
   366     cout << 
">> Overlay: Generating Scene" << endl;
   367     model->generateRender();
   370     QScopedPointer<milxQtModel> surface(
new milxQtModel); 
   371     if(surfaceArg.isSet())
   373         success = reader->openModel(surfaceName.c_str(), surface.data());
   376             milx::PrintError(
"Failed Reading surface. Check the surface type/file. Exiting.");
   380         cout << 
">> Overlaying surface" << endl;
   381         surface->setName(surfaceName.c_str());
   382         surface->generateModel();
   383         if(wireframeArg.isSet())
   384             surface->generateWireframe();
   385         if(opacityArg.isSet()) 
   386             surface->SetOpacity(opacity);
   388         model->AddActor(surface->GetActor());
   390     model->generateRender();
   392     mainWindow.setCentralWidget(model.data());
   393     mainWindow.resize(windowWidth, windowHeight);
   395         model->disableOrient();
   397         model->background(
true);
   399         model->viewToAxial();
   400     if(coronalArg.isSet())
   401         model->viewToCoronal();
   402     if(saggitalArg.isSet())
   403         model->viewToSagittal();
   404     if(loadViewArg.isSet())
   406     if(loadViewFileArg.isSet())
   407         model->loadView(loadViewName.c_str());
   411         vtkCamera *camera = model->GetRenderer()->GetActiveCamera();
   412         camera->Zoom(zoomFactor);
   414     cout << 
">> Overlay: Rendering" << endl;
   415     if(!onscreenArg.isSet())
   416         model->OffScreenRenderingOn();
   421     model->GetRenderWindow()->Render();
   422     qApp->processEvents();
   423     cout << 
">> Complete" << endl;
   425     if(!onscreenArg.isSet())
   428         vtkSmartPointer<vtkWindowToImageFilter> windowToImage = vtkSmartPointer<vtkWindowToImageFilter>::New();
   429         windowToImage->SetInput(model->GetRenderWindow());
   430         windowToImage->Update();
   432         QScopedPointer<milxQtFile> writer(
new milxQtFile); 
   433         model->GetRenderWindow()->Render();
   434         writer->saveImage(screenName.c_str(), windowToImage->GetOutput());
   436         model->OffScreenRenderingOff(); 
 This class represents the MILX Qt Render Window Display object using QVTK. 
 
This class represents the MILX Qt Image Display object using VTK. 
 
void PrintError(const std::string msg)
Displays a generic msg to standard error with carriage return. 
 
This class represents the MILX Qt File I/O object using VTK/ITK/Qt. 
 
This program Animates image slices and animates surfaces in the model view for creating movies...
 
static vtkMatrix4x4 * OpenITKTransform(std::string filename)
Opens an ITK transform file and converts it to a VTK transform matrix. 
 
This class represents the MILX Qt Model/Mesh Display object using VTK. 
 
The class provides 1D/2D and 3D plotting capability. This includes scatter and surface plots...
 
Represents an image (i.e. an regular rectangular array with scalar values) and their common operation...
 
void PrintWarning(const std::string msg)
Displays a generic msg to standard output with carriage return. 
 
static bool SaveModel(const std::string filename, vtkSmartPointer< vtkPolyData > data, const bool binary=false)
Saves a model as a file, which can be a VTK XML or Legacy VTK PolyData File (i.e. either a *...
 
void PrintInfo(const std::string msg)
Displays a generic msg to standard output with carriage return. 
 
std::string NumberToString(double num, unsigned zeroPad=0)
Number to string converter. 
 
static bool ReadImageInformation(const std::string filename, std::string &pixeltype, std::string &componentType, size_t &dimensions)
Reads just the header of an image file (without reading the image data), and writes the info into the...
 
void setData(QPointer< milxQtImage > newImg, const bool forceDeepCopy=false)
Assigns the milxQtImage data to current image. You will need to call generate image after this...