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...