SMILX  1.01
milxQtImage.cpp
1 /*=========================================================================
2  The Software is copyright (c) Commonwealth Scientific and Industrial Research Organisation (CSIRO)
3  ABN 41 687 119 230.
4  All rights reserved.
5 
6  Licensed under the CSIRO BSD 3-Clause License
7  You may not use this file except in compliance with the License.
8  You may obtain a copy of the License in the file LICENSE.md or at
9 
10  https://stash.csiro.au/projects/SMILI/repos/smili/browse/license.txt
11 
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  See the License for the specific language governing permissions and
16  limitations under the License.
17 =========================================================================*/
18 #include "milxQtImage.h"
19 
20 //ITK
21 //#include <itkImageToHistogramFilter.h>
22 //VTK Libraries
23 #include <vtkCamera.h>
24 #include <vtkImageMagnify.h>
25 #include <vtkRenderer.h>
26 #include <vtkRenderWindow.h>
27 #include <vtkImageActor.h>
28 #include <vtkImageMapToWindowLevelColors.h>
29 #include <vtkInteractorStyleImage.h>
30 #include <vtkPolyDataToImageStencil.h>
31 #include <vtkImageStencil.h>
32 #include <vtkImageFFT.h>
33 #include <vtkImageButterworthHighPass.h>
34 #include <vtkImageRFFT.h>
35 #include <vtkImageMagnitude.h>
36 #include <vtkImageGradientMagnitude.h>
37 #include <vtkImageShiftScale.h>
38 #include <vtkImageCast.h>
39 #include <vtkImageFlip.h>
40 #include <vtkImageReslice.h>
41 #include <vtkImageBlend.h>
42 #include <vtkDistanceRepresentation.h>
43 #include <vtkOrientedGlyphContourRepresentation.h>
44 #include <vtkBoxRepresentation.h>
45 #include <vtkImageActorPointPlacer.h>
46 #include <vtkDijkstraImageContourLineInterpolator.h>
47 #include <vtkDijkstraImageGeodesicPath.h>
48 #include <vtkTextProperty.h>
49 #include <vtkLogLookupTable.h>
50 
51 #include "milxColourMap.h"
52 #include "milxQtFile.h"
53 
54 //milxQtImage
55 milxQtImage::milxQtImage(QWidget *theParent, bool contextSystem) : milxQtRenderWindow(theParent, contextSystem)
56 {
58  usingVTKImage = false;
59  imported = false;
60  appendedData = false;
61  eightbit = false;
62  integer = false;
63  rgb = false;
64  vectorised = false;
65  viewerSetup = false;
66  volume = false;
67  flipped = true;
68  track = false;
69 
70  meanValue = 0;
71  stddevValue = 0;
72  minValue = 0;
73  maxValue = 0;
74 
76 
78  milxQtWindow::prefix = "Img: ";
79 
81  linkProgressEventOf(milx::ProgressUpdates->GetUpdateObject()); //link itk observer propagator
82 
84  imageChar = charImageType::New();
85  imageInt = intImageType::New();
86  imageRGB = rgbImageType::New();
87  imageFloat = floatImageType::New();
88  imageVector = NULL; //rare so allocate as needed
89 
90  imageData = vtkSmartPointer<vtkImageData>::New();
91  viewer = vtkSmartPointer<vtkImageViewer3>::New();
92  observeProgress = itkEventQtObserver::New();
93  transformMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
94 
96 
97  //View defaults
99  setView(AXIAL);
100  setDefaultOrientation(RADIOLOGICAL);
101 
102  createActions();
104 }
105 
107 {
109 }
110 
111 void milxQtImage::setData(QPointer<milxQtImage> newImg, const bool forceDeepCopy)
112 {
113  if(newImg->is8BitImage())
114  setData(newImg->GetCharImage(), newImg->isDisplayFlipped());
115  else if(newImg->is32BitImage())
116  setData(newImg->GetIntImage(), newImg->isDisplayFlipped());
117  else if(newImg->isVectorImage())
118  setData(newImg->GetVectorImage(), newImg->isDisplayFlipped(), forceDeepCopy);
119  else if(newImg->isRGBImage())
120  setData(newImg->GetRGBImage(), newImg->isDisplayFlipped());
121  else
122  setData(newImg->GetFloatImage(), newImg->isDisplayFlipped());
123 }
124 
125 void milxQtImage::setData(charImageType::Pointer newImg, const bool flipY)
126 {
128 
129  flipped = flipY;
130 
131  loaded = true;
132  eightbit = true;
133  integer = false;
134  rgb = false;
135  vectorised = false;
136  usingVTKImage = false;
137 }
138 
139 void milxQtImage::setData(intImageType::Pointer newImg, const bool flipY)
140 {
142 
143  flipped = flipY;
144 
145  loaded = true;
146  eightbit = false;
147  integer = true;
148  rgb = false;
149  vectorised = false;
150  usingVTKImage = false;
151 }
152 
153 void milxQtImage::setData(rgbImageType::Pointer newImg, const bool flipY)
154 {
156 
157  flipped = flipY;
158 
159  loaded = true;
160  eightbit = false;
161  integer = false;
162  rgb = true;
163  vectorised = false;
164  usingVTKImage = false;
165 }
166 
167 void milxQtImage::setData(floatImageType::Pointer newImg, const bool flipY)
168 {
170 
171  flipped = flipY;
172 
173  loaded = true;
174  eightbit = false;
175  integer = false;
176  rgb = false;
177  vectorised = false;
178  usingVTKImage = false;
179 }
180 
181 void milxQtImage::setData(vectorImageType::Pointer newImg, const bool flipY, const bool deepCopy)
182 {
183  if(deepCopy)
185  else
186  imageVector = newImg;
187 
188  flipped = flipY;
189 
190  loaded = true;
191  eightbit = false;
192  integer = false;
193  rgb = false;
194  vectorised = true;
195  usingVTKImage = false;
196 
197  magnitude();
198 }
199 
200 void milxQtImage::setData(vnl_matrix<double> &newData)
201 {
202  typedef double doublePixelType;
203  typedef itk::Image<doublePixelType, milx::imgDimension> doubleImageType;
204 
205  doubleImageType::Pointer imageDouble = milx::Image<doubleImageType>::ImportMatrixToImage<double>(newData);
206  imageFloat = milx::Image<doubleImageType>::CastImage<floatImageType>(imageDouble);
207  printWarning("Matrix of Double type has been converted to Float type for display");
208  loaded = true;
209  usingVTKImage = false;
210  integer = false;
211  eightbit = false;
212  rgb = false;
213  vectorised = false;
214 }
215 
216 void milxQtImage::setData(const unsigned slice, vnl_matrix<double> &newData)
217 {
218  setData(newData);
219 }
220 
221 void milxQtImage::setData(vtkSmartPointer<vtkImageData> newImg)
222 {
223  imageData->DeepCopy(newImg);
224 
225  usingVTKImage = true;
226  eightbit = false;
227  integer = false;
228  if( (newImg->GetNumberOfScalarComponents() == 4 || newImg->GetNumberOfScalarComponents() == 3) && newImg->GetScalarType() == VTK_UNSIGNED_CHAR )
229  rgb = true;
230  else
231  rgb = false;
232  loaded = true;
233  vectorised = false;
234  flipped = false;
235 
236  //~ histogram(256, 0, 255, false);
237 }
238 
239 void milxQtImage::setDisplayData(QPointer<milxQtImage> newImg)
240 {
241  if(newImg->is8BitImage())
242  setDisplayData(newImg->GetCharImage(), newImg->isDisplayFlipped());
243  else if(newImg->is32BitImage())
244  setDisplayData(newImg->GetIntImage(), newImg->isDisplayFlipped());
245  else if(newImg->isRGBImage())
246  setDisplayData(newImg->GetRGBImage(), newImg->isDisplayFlipped());
247  else if(newImg->isVectorImage())
248  setDisplayData(newImg->GetVectorImage(), newImg->isDisplayFlipped());
249  else
250  setDisplayData(newImg->GetFloatImage(), newImg->isDisplayFlipped());
251 }
252 
253 void milxQtImage::setDisplayData(charImageType::Pointer newImg, const bool flipY)
254 {
255  imageChar = newImg;
256 
257  flipped = flipY;
258 
259  loaded = true;
260  eightbit = true;
261  integer = false;
262  rgb = false;
263  vectorised = false;
264  usingVTKImage = false;
265 }
266 
267 void milxQtImage::setDisplayData(intImageType::Pointer newImg, const bool flipY)
268 {
269  imageInt = newImg;
270 
271  flipped = flipY;
272 
273  loaded = true;
274  eightbit = false;
275  integer = true;
276  rgb = false;
277  vectorised = false;
278  usingVTKImage = false;
279 }
280 
281 void milxQtImage::setDisplayData(rgbImageType::Pointer newImg, const bool flipY)
282 {
283  imageRGB = newImg;
284 
285  flipped = flipY;
286 
287  loaded = true;
288  eightbit = false;
289  integer = false;
290  rgb = true;
291  vectorised = false;
292  usingVTKImage = false;
293 }
294 
295 void milxQtImage::setDisplayData(floatImageType::Pointer newImg, const bool flipY)
296 {
297  imageFloat = newImg;
298 
299  flipped = flipY;
300 
301  loaded = true;
302  eightbit = false;
303  integer = false;
304  rgb = false;
305  vectorised = false;
306  usingVTKImage = false;
307 }
308 
309 void milxQtImage::setDisplayData(vectorImageType::Pointer newImg, const bool flipY)
310 {
311  setData(newImg, flipY, false); //due to the large memory requirements not wise to duplicate
312 }
313 
314 void milxQtImage::setSlice(int slice)
315 {
316  if(!loaded || !volume)
317  return;
318 
319  if(slice >= viewer->GetSliceMin() && slice <= viewer->GetSliceMax())
320  viewer->SetSlice(slice);
321  else
322  printError("Slice out of range! Ignoring.");
323 }
324 
325 void milxQtImage::SetTransform(vtkSmartPointer<vtkTransform> newTransform)
326 {
327  if(loaded)
328  {
329  emit working(-1);
331  vtkSmartPointer<vtkImageReslice> reslice = vtkSmartPointer<vtkImageReslice>::New();
332  #if VTK_MAJOR_VERSION <= 5
333  reslice->SetInput(imageData);
334  #else
335  reslice->SetInputData(imageData);
336  #endif
337  linkProgressEventOf(reslice);
338  reslice->AutoCropOutputOn();
339  reslice->TransformInputSamplingOn();
340  reslice->SetOutputDimensionality(milx::imgDimension);
341  reslice->SetResliceTransform(newTransform);
342  reslice->Update();
343 
344  imageData = reslice->GetOutput();
345  imageData->Modified();
346  #if VTK_MAJOR_VERSION <= 5
347  imageData->Update();
348  #endif
349  emit done(-1);
350 
351  usingVTKImage = true;
352  }
353 }
354 
355 void milxQtImage::generateImage(const bool quietly)
356 {
357  if (loaded)
358  {
359  printDebug("Generating Image");
360  int bounds[6];
361 
362  emit working(-1);
363  updateData(orientAct->isChecked());
364 
365  imageData->GetExtent(bounds);
366 
368 
370  if(bounds[5] > 1)
371  volume = true;
372 
374  #if VTK_MAJOR_VERSION <= 5
375  viewer->SetInput(imageData);
376  #else
377  viewer->SetInputData(imageData);
378  #endif
379  if(!viewerSetup)
380  {
381  printDebug("Setting up viewer");
383  milxQtRenderWindow::SetRenderer(viewer->GetRenderer());
384  printDebug("Size of Image window: " + QString::number(milxQtRenderWindow::GetRenderWindow()->GetSize()[0]) + "x" + QString::number(milxQtRenderWindow::GetRenderWindow()->GetSize()[1]));
385  QVTKWidget::SetRenderWindow(viewer->GetRenderWindow());
386  viewer->SetupInteractor(QVTKWidget::GetInteractor());
387  SetupWidgets(viewer->GetRenderWindow()->GetInteractor());
388  if(volume)
389  viewer->SetSlice(bounds[5]/2); //show middle of volume
390 
391  //Remove VTK events for the right mouse button for Qt context menu
392  QVTKWidget::GetInteractor()->RemoveObservers(vtkCommand::RightButtonPressEvent);
393  QVTKWidget::GetInteractor()->RemoveObservers(vtkCommand::RightButtonReleaseEvent);
394  Connector->Connect(QVTKWidget::GetInteractor(),
395  vtkCommand::EndWindowLevelEvent,
396  this,
397  SLOT( userEvent() ));
398  Connector->Connect(QVTKWidget::GetInteractor(),
399  vtkCommand::MouseWheelForwardEvent,
400  this,
401  SLOT( userEvent() ));
402  Connector->Connect(QVTKWidget::GetInteractor(),
403  vtkCommand::MouseWheelBackwardEvent,
404  this,
405  SLOT( userEvent() ));
406  Connector->Connect(QVTKWidget::GetInteractor(),
407  vtkCommand::KeyPressEvent,
408  this,
409  SLOT( userEvent() ));
410 
411  viewer->GetRenderer()->ResetCamera();
412 
413  //Human Glyph setup
415  humanGlyph->SetDefaultRenderer(viewer->GetRenderer());
416  humanGlyph->SetInteractor(viewer->GetRenderWindow()->GetInteractor());
418  {
419  milxQtRenderWindow::humanAct->setEnabled(true);
420  humanGlyph->On();
421  }
422  else
423  {
424  milxQtRenderWindow::humanAct->setEnabled(false);
425  humanGlyph->Off();
426  }
427 // humanGlyph->InteractiveOn();
428 
429  //Sphere annotate
430  sphereWidget->SetDefaultRenderer(viewer->GetRenderer());
431  sphereWidget->SetInteractor(viewer->GetRenderWindow()->GetInteractor());
432 
433  printDebug("Viewer Setup Complete");
434  }
435  viewer->GetInteractorStyle()->InvokeEvent(vtkCommand::ResetWindowLevelEvent); //Reset window level as if pressing 'r'
436  viewer->GetRenderer()->ResetCamera(); //Reset window view as if pressing 'Shift+r'
437  viewer->UpdateCursor();
438  viewer->Render();
439 
441  if(!viewerSetup)
442  {
443  /*viewer->GetInput()->GetExtent(magBounds);
444  if(magBounds[1] > bounds[1] || magBounds[3] > bounds[3] || magBounds[5] > bounds[5])
445  {
446  printInfo( "Magnified Generate Size: " + QString::number(magBounds[1]+1) + "x" + QString::number(magBounds[3]+1) + "x" + QString::number(magBounds[5]+1) );
447  printWarning("Image magnified by " + QString::number( static_cast<double>(magBounds[1])/bounds[1] ) + " for better display (likely because it was small).");
448  }*/
449 
450  setupEvents();
451 
453  /*if (bounds[1] > minWindowSize && bounds[3] > minWindowSize)
454  {
455  viewer->SetSize(bounds[1],bounds[3]);
456  QVTKWidget::resize(bounds[1],bounds[3]);
457  }
458  else
459  {
460  viewer->SetSize(minWindowSize,minWindowSize);
461  QVTKWidget::resize(minWindowSize,minWindowSize);
462  }*/
463  viewerSetup = true;
464  }
465 
466  //Pass through data with no LUT initially if not RGB or RGBA image
467  //According to VTK docs for vtkImageMapToWindowLevelColors: If the lookup table is not set, or is set to NULL, then the input data will be passed through if it is already of type UNSIGNED_CHAR.
468  printInfo("Number of Image Components: " + QString::number(imageData->GetNumberOfScalarComponents()));
469  if(imageData->GetNumberOfScalarComponents() > 2)
470  {
471  GetWindowLevel()->SetLookupTable(NULL);
472  GetWindowLevel()->SetWindow(255);
473  GetWindowLevel()->SetLevel(127.5);
474  }
475  lookupTable = NULL;
476 
479 
481  if(!quietly)
482  emit modified(this);
483  emit done(-1);
484  }
485  printDebug("Completed Generating Image");
486 }
487 
488 void milxQtImage::generateVoxelisedSurface(vtkSmartPointer<vtkPolyData> surfaceToVoxelise, double *bounds, double *spacing)
489 {
490  bool ok1, ok2, ok3;
491  double xSpacing = 1.0, ySpacing = 1.0, zSpacing = 1.0;
492 
493  if(spacing == NULL)
494  {
495  xSpacing = QInputDialog::getDouble(this, tr("Please enter x spacing value"),
496  tr("X Spacing Value:"), 0.5, -2147483647, 2147483647, 7, &ok1);
497  ySpacing = QInputDialog::getDouble(this, tr("Please enter y spacing value"),
498  tr("Y SpacingValue:"), 0.5, -2147483647, 2147483647, 7, &ok2);
499  zSpacing = QInputDialog::getDouble(this, tr("Please enter z spacing value"),
500  tr("Z Spacing Value:"), 0.5, -2147483647, 2147483647, 7, &ok3);
501  }
502 
503  if(ok1 && ok2 && ok3)
504  {
505  emit working(-1);
506 
507  printDebug("Creating Filled Image");
508  vtkSmartPointer<vtkImageData> whiteImage = vtkSmartPointer<vtkImageData>::New();
509 
510  double totalBounds[6];
511  if(bounds == NULL)
512  {
513  bounds = &totalBounds[0];
514  surfaceToVoxelise->GetBounds(bounds);
515  }
516  double spacing[3]; // desired volume spacing
517  spacing[0] = xSpacing;
518  spacing[1] = ySpacing;
519  spacing[2] = zSpacing;
520  whiteImage->SetSpacing(spacing);
521 
522  //Pad the bounds by a slice
523  bounds[0] -= spacing[0];
524  bounds[1] += spacing[0];
525  bounds[2] -= spacing[1];
526  bounds[3] += spacing[1];
527  bounds[4] -= spacing[2];
528  bounds[5] += spacing[2];
529 
530  // compute dimensions
531  int dim[3];
532  for (int i = 0; i < 3; i++)
533  {
534  dim[i] = static_cast<int>( ceil((bounds[i * 2 + 1] - bounds[i * 2]) / spacing[i]) );
535  }
536  printInfo("Dimensions of Voxelisation is " + QString::number(dim[0]) + "x" + QString::number(dim[1]) + "x" + QString::number(dim[2]));
537  whiteImage->SetDimensions(dim);
538  whiteImage->SetExtent(0, dim[0] - 1, 0, dim[1] - 1, 0, dim[2] - 1);
539 
540  double origin[3];
541  // NOTE: I am not sure whether or not we had to add some offset!
542  origin[0] = bounds[0];// + spacing[0] / 2;
543  origin[1] = bounds[2];// + spacing[1] / 2;
544  origin[2] = bounds[4];// + spacing[2] / 2;
545  whiteImage->SetOrigin(origin);
546  #if VTK_MAJOR_VERSION <= 5
547  whiteImage->SetScalarTypeToUnsignedChar();
548  whiteImage->SetNumberOfScalarComponents(1);
549  whiteImage->AllocateScalars();
550  #else
551  whiteImage->AllocateScalars(VTK_UNSIGNED_CHAR,1);
552  #endif
553 
554  // fill the image with foreground voxels:
555  unsigned char inval = 255;
556  unsigned char outval = 0;
557  for (vtkIdType i = 0; i < whiteImage->GetNumberOfPoints(); ++i)
558  whiteImage->GetPointData()->GetScalars()->SetTuple1(i, inval);
559 
560  // polygonal data --> image stencil:
561  printDebug("Polygonal data --> Image stencil");
562  vtkSmartPointer<vtkPolyDataToImageStencil> pol2stenc = vtkSmartPointer<vtkPolyDataToImageStencil>::New();
563  #if VTK_MAJOR_VERSION <= 5
564  pol2stenc->SetInput(surfaceToVoxelise);
565  #else
566  pol2stenc->SetInputData(surfaceToVoxelise);
567  #endif
568  pol2stenc->SetOutputOrigin(origin);
569  pol2stenc->SetOutputSpacing(spacing);
570  pol2stenc->SetOutputWholeExtent(whiteImage->GetExtent());
571  linkProgressEventOf(pol2stenc); //Keeps UI responsive
572  pol2stenc->Update();
573 
574  // cut the corresponding white image and set the background:
575  printDebug("Image stencil --> Image");
576  vtkSmartPointer<vtkImageStencil> imgstenc = vtkSmartPointer<vtkImageStencil>::New();
577  #if VTK_MAJOR_VERSION <= 5
578  imgstenc->SetInput(whiteImage);
579  imgstenc->SetStencil(pol2stenc->GetOutput());
580  #else
581  imgstenc->SetInputData(whiteImage);
582  imgstenc->SetStencilConnection(pol2stenc->GetOutputPort());
583  #endif
584  imgstenc->ReverseStencilOff();
585  imgstenc->SetBackgroundValue(outval);
586  linkProgressEventOf(imgstenc); //Keeps UI responsive
587  imgstenc->Update();
588 
589  printDebug("Converting to ITK Image");
591  usingVTKImage = false;
592  setName("Voxelised Surface");
594  emit done(-1);
595  }
596 }
597 
598 //VTK Filters
599 vtkSmartPointer<vtkImageData> milxQtImage::butterWorthHighPass(vtkSmartPointer<vtkImageData> img)
600 {
601  printInfo("Computing the FFT of Image.");
602  vtkSmartPointer<vtkImageFFT> fft = vtkSmartPointer<vtkImageFFT>::New();
603 // fft->SetDimensionality(3);
604 #if VTK_MAJOR_VERSION <= 5
605  fft->SetInput(img);
606 #else
607  fft->SetInputData(img);
608 #endif
609  linkProgressEventOf(fft);
610  fft->Update();
611 
612  printInfo("Filtering FFT space of Image.");
613  vtkSmartPointer<vtkImageButterworthHighPass> highPass = vtkSmartPointer<vtkImageButterworthHighPass>::New();
614  highPass->SetInputConnection(fft->GetOutputPort());
615  highPass->SetOrder(2);
616  highPass->SetXCutOff(0.2);
617  highPass->SetYCutOff(0.1);
618  linkProgressEventOf(highPass);
619  highPass->ReleaseDataFlagOff();
620 
621  printInfo("Computing the Inverse FFT of Image.");
622  vtkSmartPointer<vtkImageRFFT> ifft = vtkSmartPointer<vtkImageRFFT>::New();
623  ifft->SetInputConnection(highPass->GetOutputPort());
624  linkProgressEventOf(ifft);
625  ifft->Update();
626 
627  printInfo("Extracting the magnitude and casting to float image type.");
628  vtkSmartPointer<vtkImageMagnitude> magnitudeFilter = vtkSmartPointer<vtkImageMagnitude>::New();
629  magnitudeFilter->SetInputConnection(ifft->GetOutputPort());
630  linkProgressEventOf(magnitudeFilter);
631 
632  vtkSmartPointer<vtkImageCast> rfftCastFilter = vtkSmartPointer<vtkImageCast>::New();
633  rfftCastFilter->SetInputConnection(magnitudeFilter->GetOutputPort());
634  rfftCastFilter->SetOutputScalarTypeToFloat();
635  linkProgressEventOf(rfftCastFilter);
636  rfftCastFilter->Update();
637 
638  return rfftCastFilter->GetOutput();
639 }
640 
641 void milxQtImage::trackView(milxQtImage *windowToTrack, ViewType viewTo)
642 {
643  printDebug("Tracking View");
644  track = true;
645  viewToTrack = viewTo;
646  enableCrosshair();
647  milxQtRenderWindow::Connector->Connect(windowToTrack->GetVTKInteractor(),
648  vtkCommand::MiddleButtonPressEvent,
649 // vtkCommand::LeftButtonPressEvent,
650  this,
651  SLOT( updateTrackedView(vtkObject*) ),
652  NULL, 1.0); //High Priority
653 }
654 
655 void milxQtImage::userEvent(QMouseEvent *event)
656 {
658 }
659 
660 void milxQtImage::userEvent(QKeyEvent *event)
661 {
663 }
664 
665 void milxQtImage::userEvent(QWheelEvent *event)
666 {
668 }
669 
670 void milxQtImage::updateCoords(vtkObject *obj)
671 {
673  vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::SafeDownCast(obj);
674 
675  if(!iren)
676  return;
677 
678  QString message = "";
679 
680  // Get a shortcut to the pixel data.
681  vtkImageData* pImageData = viewer->GetInput();
682 
683  if(!pImageData)
684  return;
685 
686  if( (pImageData->GetNumberOfScalarComponents() == 4 || pImageData->GetNumberOfScalarComponents() == 3)
687  && pImageData->GetScalarType() == VTK_UNSIGNED_CHAR )
688  {
689  message = "RGB Image Pixel Cooridinates Diabled for Performance";
690  updateBar->showMessage(message);
691  return;
692  }
693 
698  if (dataPicker->Pick(iren->GetEventPosition()[0],
699  iren->GetEventPosition()[1],
700  0, // always zero.
701  renderer))
702  {
703  // Get the volume index within the entire volume now.
704  //~ const vtkIdType nVolIdx = dataPicker->GetPointId();
705 
706  double ptMapped[3];
707  dataPicker->GetMapperPosition(ptMapped);
708  //~ printDebug("Mapper Position: " + QString::number(ptMapped[0]) + ", " + QString::number(ptMapped[1]) + ", " + QString::number(ptMapped[2]));
709 
710  //~ if(nVolIdx >= 0) //-1 means no point picked
711  //~ {
712  //~ coordinate current( pImageData->GetPoint(nVolIdx) ), cell(0.0); ///Get the pixel in real space
713  coordinate current( ptMapped ), cell(0.0);
714  const int zAxis = viewer->GetSliceOrientation();
715  int actual[3], relative[3];
716  double spacing[3], origin[3];
717 
718  //~ printDebug("Prev. Current: " + QString::number(current[0]) + ", " + QString::number(current[1]) + ", " + QString::number(current[2]));
719  pImageData->GetSpacing(spacing);
720  pImageData->GetOrigin(origin);
721 
722  //pick is always only 2D, add ``z-axis''
723  if(zAxis == vtkImageViewer2::SLICE_ORIENTATION_XY) //z-axis is z-axis
724  {
725  current[2] = origin[2] + viewer->GetSlice()*spacing[2];
726  //~ printDebug("Axial");
727  }
728  else if(zAxis == vtkImageViewer2::SLICE_ORIENTATION_XZ) //y-axis is z-axis
729  {
730  //~ current[2] = current[1];
731  current[1] = origin[1] + viewer->GetSlice()*spacing[1];
732  //~ printDebug("Coronal");
733  }
734  else if(zAxis == vtkImageViewer2::SLICE_ORIENTATION_YZ) //x-axis is z-axis
735  {
736  //~ current[2] = current[1];
737  //~ current[1] = current[0];
738  current[0] = origin[0] + viewer->GetSlice()*spacing[0];
739  //~ printDebug("Sagittal");
740  }
741 
743  int nVolIdx = pImageData->FindPoint(current.data_block());
744  const bool isInside = pImageData->ComputeStructuredCoordinates(current.data_block(), actual, cell.data_block());
745 
746  relative[0] = actual[0];
747  relative[1] = actual[1];
748  relative[2] = actual[2];
749 
750  //~ printDebug("Current: " + QString::number(current[0]) + ", " + QString::number(current[1]) + ", " + QString::number(current[2]));
751  //~ printDebug("Actual: " + QString::number(actual[0]) + ", " + QString::number(actual[1]) + ", " + QString::number(actual[2]));
752  if(isInside)
753  {
754  if(track)
755  enableCrosshair();
756 
757  //~ printDebug("Relative: " + QString::number(relative[0]) + ", " + QString::number(relative[1]) + ", " + QString::number(relative[2]));
759  switch (pImageData->GetNumberOfScalarComponents())
760  {
761  case 1:
762  {
764  const double scalar = pImageData->GetScalarComponentAsDouble(actual[0], actual[1], actual[2], 0); //Negative cause image flipped so use origin
765  message = "Point " + QString::number(nVolIdx) + ", Indices(" + QString::number(relative[0]) + ", " + QString::number(relative[1]) + ", " + QString::number(relative[2]) + "), "
766  + "Real(" + QString::number(current[0]) + ", " + QString::number(current[1]) + ", " + QString::number(current[2]) + ") = "
767  + QString::number(scalar);
768  }
769  break;
770 
771  case 2:
772  {
774  const double scalarR = pImageData->GetScalarComponentAsDouble(actual[0], actual[1], actual[2], 0); //Negative cause image flipped so use origin
775  const double scalarG = pImageData->GetScalarComponentAsDouble(actual[0], actual[1], actual[2], 1);
776  message = "Point " + QString::number(nVolIdx) + ", Indices(" + QString::number(relative[0]) + ", " + QString::number(relative[1]) + ", " + QString::number(relative[2]) + "), "
777  + "Real(" + QString::number(current[0]) + ", " + QString::number(current[1]) + ", " + QString::number(current[2]) + ") = "
778  + "[" + QString::number(scalarR) + "," + QString::number(scalarG) + "]";
779  }
780  break;
781 
782  case 3:
783  {
785  const double scalarR = pImageData->GetScalarComponentAsDouble(actual[0], actual[1], actual[2], 0); //Negative cause image flipped so use origin
786  const double scalarG = pImageData->GetScalarComponentAsDouble(actual[0], actual[1], actual[2], 1);
787  const double scalarB = pImageData->GetScalarComponentAsDouble(actual[0], actual[1], actual[2], 2);
788  message = "Point " + QString::number(nVolIdx) + ", Indices(" + QString::number(relative[0]) + ", " + QString::number(relative[1]) + ", " + QString::number(relative[2]) + "), "
789  + "Real(" + QString::number(current[0]) + ", " + QString::number(current[1]) + ", " + QString::number(current[2]) + ") = "
790  + "[" + QString::number(scalarR) + "," + QString::number(scalarG) + "," + QString::number(scalarB) + "]";
791  }
792  break;
793 
794  default:
795  message = "Unsupported number of scalar components";
796  break;
797  }
798 
799 // if(track)
800 // emit coordinateChanged(actual[0], actual[1], actual[2]);
801  }
802  //~ }
803  }
804 
806  updateBar->showMessage(message);
807 }
808 
809 void milxQtImage::updateSlice(vtkObject *obj)
810 {
811  vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::SafeDownCast(obj);
812 
813  string keyPressed = iren->GetKeySym();
814 
815  //printDebug("Updating Slice Display");
816  if (keyPressed == "Up")
817  {
818  if (viewer->GetSlice()+1 <= viewer->GetSliceMax())
819  {
820  printDebug("Incrementing from Slice " + QString::number(viewer->GetSlice()) + " to Slice " + QString::number(viewer->GetSlice()+1));
821  viewer->SetSlice(viewer->GetSlice()+1);
822  }
823  }
824  else if (keyPressed == "Down")
825  {
826  if (viewer->GetSlice()-1 >= viewer->GetSliceMin())
827  {
828  printDebug("Decrementing from Slice " + QString::number(viewer->GetSlice()) + " to Slice " + QString::number(viewer->GetSlice()-1));
829  viewer->SetSlice(viewer->GetSlice()-1);
830  }
831  }
832 
833  viewer->GetRenderWindow()->InvokeEvent(vtkCommand::ModifiedEvent, NULL);
834  updateCoords(iren);
835 }
836 
837 void milxQtImage::updateTrackedView(vtkObject *obj)
838 {
839  vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::SafeDownCast(obj);
840  vtkRenderer* irenderer = iren->FindPokedRenderer(0,0);
841  printDebug("Update Tracked View");
842 
843  // Get a shortcut to the pixel data.
844  vtkImageData* pImageData = viewer->GetInput();
845 
846  if (dataPicker->Pick(iren->GetEventPosition()[0],
847  iren->GetEventPosition()[1],
848  0, //always zero
849  irenderer))
850  {
851  double ptMapped[3];
852  dataPicker->GetMapperPosition(ptMapped);
853 
854  coordinate current( ptMapped ), cell(0.0);
855  const int zAxis = viewer->GetSliceOrientation();
856  int actual[3];
857 
858 // printDebug("Prev. Current: " + QString::number(current[0]) + ", " + QString::number(current[1]) + ", " + QString::number(current[2]));
859 
861  const bool isInside = pImageData->ComputeStructuredCoordinates(current.data_block(), actual, cell.data_block());
862 
863  if(isInside)
864  {
865  if(zAxis == vtkImageViewer2::SLICE_ORIENTATION_XY) //z-axis is z-axis
866  {
867  viewer->SetSlice(actual[2]);
868  printDebug("Axial");
869  }
870  else if(zAxis == vtkImageViewer2::SLICE_ORIENTATION_XZ) //y-axis is z-axis
871  {
872  viewer->SetSlice(actual[1]);
873  printDebug("Coronal");
874  }
875  else if(zAxis == vtkImageViewer2::SLICE_ORIENTATION_YZ) //x-axis is z-axis
876  {
877  viewer->SetSlice(actual[0]);
878  printDebug("Sagittal");
879  }
880  #if(VTK_MAJOR_VERSION > 5)
881  viewer->GetCursor()->SetCenter(current[0], current[1], current[2]);
882  #else
883  viewer->GetCursor()->SetFocalPoint(current[0], current[1], current[2]);
884  #endif
885  viewer->GetCursor()->Update();
886  }
887  }
888 
889  viewer->GetRenderWindow()->InvokeEvent(vtkCommand::ModifiedEvent, NULL);
890  viewer->Render();
892 }
893 
895 {
897  disableOrient();
898 
900  {
901  milxQtRenderWindow::contourWidget = vtkSmartPointer<vtkContourWidget>::New();
902  milxQtRenderWindow::contourWidget->SetInteractor(QVTKWidget::GetInteractor());
903  milxQtRenderWindow::contourWidget->FollowCursorOn();
904 
905  printInfo("Contour Image Mode enabled.\nLeft Click to place points, Right click to place end point.");
906  printInfo("Delete key to delete point, Shift+Delete key to reset.");
907 
908  vtkSmartPointer<vtkOrientedGlyphContourRepresentation> rep = vtkOrientedGlyphContourRepresentation::SafeDownCast( milxQtRenderWindow::contourWidget->GetRepresentation() );
909  rep->GetLinesProperty()->SetColor(1, 0.2, 0);
910  rep->GetLinesProperty()->SetLineWidth(5.0);
911 // rep->SetWorldTolerance(0.000005);
912 
913  vtkSmartPointer<vtkImageActorPointPlacer> pointPlacer = vtkSmartPointer<vtkImageActorPointPlacer>::New();
914  pointPlacer->SetImageActor(viewer->GetImageActor());
915  rep->SetPointPlacer(pointPlacer);
916 
918  // Gradient magnitude for edges
919  vtkSmartPointer<vtkImageGradientMagnitude> grad = vtkSmartPointer<vtkImageGradientMagnitude>::New();
920  grad->SetDimensionality(3);
921  grad->HandleBoundariesOn();
922  #if VTK_MAJOR_VERSION <= 5
923  grad->SetInputConnection(imageData->GetProducerPort());
924  #else
925  grad->SetInputData(imageData);
926  #endif
927  grad->Update();
928 
929  // Invert the gradient magnitude so that low costs are
930  // associated with strong edges and scale from 0 to 1
931  double *range = grad->GetOutput()->GetScalarRange();
932  vtkSmartPointer<vtkImageShiftScale> gradInvert = vtkSmartPointer<vtkImageShiftScale>::New();
933  gradInvert->SetShift( -1.0*range[ 1 ] );
934  gradInvert->SetScale( 1.0 /( range[ 0 ] - range[ 1 ] ) );
935  gradInvert->SetOutputScalarTypeToFloat();
936  gradInvert->SetInputConnection( grad->GetOutputPort() );
937  gradInvert->Update();
938 
939  //Slice
940  vtkSmartPointer<vtkImageReslice> reslice = vtkSmartPointer<vtkImageReslice>::New();
941  reslice->SetOutputExtent(viewer->GetImageActor()->GetDisplayExtent()); //get the slice info
942  reslice->SetInputConnection(gradInvert->GetOutputPort());
943  reslice->SetOutputSpacing(imageData->GetSpacing()); //needed
944  reslice->SetOutputOrigin(imageData->GetOrigin()); //needed
945 // reslice->SetOutputDimensionality(2);
946  reslice->Update();
947 
948  vtkSmartPointer<vtkDijkstraImageContourLineInterpolator> interpolator = vtkSmartPointer<vtkDijkstraImageContourLineInterpolator>::New();
949  interpolator->SetCostImage(reslice->GetOutput());
950  vtkSmartPointer<vtkDijkstraImageGeodesicPath> path = interpolator->GetDijkstraImageGeodesicPath();
951  path->StopWhenEndReachedOn();
952  // prevent contour segments from overlapping
953  path->RepelPathFromVerticesOn();
954  // weights are scaled from 0 to 1 as are associated cost
955  // components
956  path->SetCurvatureWeight( 0.15 );
957  path->SetEdgeLengthWeight( 0.8 );
958  path->SetImageWeight( 1.0 );
959  rep->SetLineInterpolator(interpolator);
960  }
961 
962  if(milxQtRenderWindow::contourAct->isChecked())
963  {
965  printInfo("Enabled Contouring");
966  }
967  else
968  {
969  milxQtRenderWindow::contourWidget->EnabledOff();
970  printInfo("Disabled Contouring");
971  }
972 
973  refresh();
974 }
975 
976 void milxQtImage::updateData(const bool orient)
977 {
978  if(!usingVTKImage)
979  {
980  printDebug("Updating Data");
981 
982  floatImageType::DirectionType direction;
983  floatImageType::PointType origin;
984  floatImageType::SpacingType spacing;
985  vtkSmartPointer<vtkImageData> newImageData = vtkSmartPointer<vtkImageData>::New();
986  /*if(eightbit)
987  {
989  if(orient)
990  imageChar = milx::Image<charImageType>::ApplyOrientationToITKImage<charImageType, float>(imageChar, imageChar, true, flipped);
991  imageData->DeepCopy(milx::Image<charImageType>::ConvertITKImageToVTKImage(imageChar));
992  direction = imageChar->GetDirection();
993  origin = imageChar->GetOrigin();
994  spacing = imageChar->GetSpacing();
995  }
996  else if(rgb)
997  {
999  if(orient)
1000  imageRGB = milx::Image<rgbImageType>::ApplyOrientationToITKImage<rgbImageType, float>(imageRGB, imageRGB, true, flipped);
1001  imageData->DeepCopy(milx::Image<rgbImageType>::ConvertITKImageToVTKImage(imageRGB));
1002  direction = imageRGB->GetDirection();
1003  origin = imageRGB->GetOrigin();
1004  spacing = imageRGB->GetSpacing();
1005  }
1006  else //if float and/or vector (which also generates float magnitude image)
1007  {
1009  if(orient)
1010  imageFloat = milx::Image<floatImageType>::ApplyOrientationToITKImage<floatImageType, float>(imageFloat, imageFloat, true, flipped);
1011  imageData->DeepCopy(milx::Image<floatImageType>::ConvertITKImageToVTKImage(imageFloat));
1012  direction = imageFloat->GetDirection();
1013  origin = imageFloat->GetOrigin();
1014  spacing = imageFloat->GetSpacing();
1015  }*/
1016  if(eightbit)
1017  {
1020  direction = imageChar->GetDirection();
1021  origin = imageChar->GetOrigin();
1022  spacing = imageChar->GetSpacing();
1023  if(orient)
1025  else
1026  imageData = newImageData;
1027  //Labelled image flag is set as true to avoid artefacts in resampling within the ApplyOrientationToVTKImage member
1028  printDebug("Updated Internal Char Image Data");
1029  }
1030  else if(integer)
1031  {
1034  direction = imageInt->GetDirection();
1035  origin = imageInt->GetOrigin();
1036  spacing = imageInt->GetSpacing();
1037  if(orient)
1039  else
1040  imageData = newImageData;
1041  //Labelled image flag is set as true to avoid artefacts in resampling within the ApplyOrientationToVTKImage member
1042  printDebug("Updated Internal Integer Image Data");
1043  }
1044  else if(rgb)
1045  {
1048  direction = imageRGB->GetDirection();
1049  origin = imageRGB->GetOrigin();
1050  spacing = imageRGB->GetSpacing();
1051  if(orient)
1053  else
1054  imageData = newImageData;
1055  //Labelled image flag is set as true to avoid artefacts in resampling within the ApplyOrientationToVTKImage member
1056  printDebug("Updated Internal RGB Image Data");
1057  }
1058  else //if float and/or vector (which also generates float magnitude image)
1059  {
1062  direction = imageFloat->GetDirection();
1063  origin = imageFloat->GetOrigin();
1064  spacing = imageFloat->GetSpacing();
1065  if(orient)
1067  else
1068  imageData = newImageData;
1069  //Labelled image flag is set as true to avoid artefacts in resampling within the ApplyOrientationToVTKImage member
1070  printDebug("Updated Internal Float Image Data");
1071  }
1072  }
1073 
1074  imageData->Modified();
1075 #if VTK_MAJOR_VERSION <= 5
1076  imageData->Update();
1077 #endif
1078 
1079  printDebug("Updated Image Data as " + QString(imageData->GetScalarTypeAsString()));
1080 }
1081 
1083 {
1084  //Do not move, needs to be connected after setting up viewer!
1085  milxQtRenderWindow::Connector->Connect(milxQtRenderWindow::GetInteractor(),
1086  vtkCommand::KeyPressEvent,
1087  this,
1088  SLOT( updateSlice(vtkObject *) ),
1089  NULL, 1.0); //High Priority
1090 }
1091 
1092 void milxQtImage::autoLevel(float percentile)
1093 {
1094  printInfo("Auto Updating Window Level");
1095  printDebug("Current Window:" + QString::number(GetIntensityWindow()));
1096  printDebug("Current Level:" + QString::number(GetIntensityLevel()));
1097 
1098  int bins = 256;
1099  float belowValue = -1000, aboveValue = 4000, lowerPercentile = 1.0-percentile, upperPercentile = percentile;
1100  if(maxValue == minValue)
1101  histogram(bins, belowValue, aboveValue, false); //above and below unused here, uses image min/max automatically
1102  belowValue = minValue;
1103  aboveValue = maxValue;
1104 
1105  emit working(-1);
1106  //Compute the percentile contributions to trim levels for better contrast
1107  size_t k = 0, kMin = 0, kMax = 0, kMid = 0;
1108  double binSpacing = (aboveValue-belowValue)/bins, accummulator = 0.0, proportion = 0.0;
1109  //Upper limit of histgram
1110  k = 0;
1111  accummulator = 0.0;
1112  for(double j = belowValue; j < aboveValue; j += binSpacing, k ++)
1113  {
1114  proportion = accummulator/hist->GetVoxelCount();
1115  if(proportion >= lowerPercentile)
1116  break;
1117  accummulator += hist->GetOutput()->GetPointData()->GetScalars()->GetTuple1(k); //freq k
1118  }
1119  kMin = k-1;
1120 // printDebug("k low:" + QString::number(kMin));
1121 // printDebug("accummulator low:" + QString::number(accummulator));
1122  double lowLevel = minValue+(kMin)*binSpacing;
1123  //Lower limit of histgram
1124  k = bins-1;
1125  accummulator = 0.0;
1126  for(double j = aboveValue; j > belowValue; j -= binSpacing, k --)
1127  {
1128  proportion = accummulator/hist->GetVoxelCount();
1129  if(proportion >= lowerPercentile)
1130  break;
1131  accummulator += hist->GetOutput()->GetPointData()->GetScalars()->GetTuple1(k); //freq k
1132  }
1133  kMax = k+1;
1134 // printDebug("k high:" + QString::number(kMax));
1135 // printDebug("accummulator high:" + QString::number(accummulator));
1136  double maxLevel = minValue+(kMax)*binSpacing;
1137  double windowLevel = maxLevel-lowLevel;
1138  double level = lowLevel+windowLevel/2; //center the new window from low limit
1139  emit done(-1);
1140 
1141  printDebug("Histogram Low Level:" + QString::number(lowLevel));
1142  printDebug("Histogram High Level:" + QString::number(maxLevel));
1143  printInfo("Window:" + QString::number(windowLevel));
1144  printInfo("Level:" + QString::number(level));
1145 
1146  viewer->SetColorWindow(windowLevel);
1147  viewer->SetColorLevel(level);
1148  viewer->Render();
1149 }
1150 
1151 void milxQtImage::setLevel(int level)
1152 {
1153 // printInfo("Updating Window Level to "+QString::number(level)+"%");
1154 
1155  double range[2];
1156  imageData->GetScalarRange(range);
1157  double belowValue = range[0];
1158  double aboveValue = range[1];
1159  if(imageData->GetNumberOfScalarComponents() > 2) //Use RGB range
1160  {
1161  belowValue = 0;
1162  aboveValue = 255;
1163  }
1164 
1165  float lvl = (aboveValue-belowValue)*level/100 + belowValue;
1166  printDebug("Contrast Level is "+QString::number(lvl));
1167 
1168  viewer->SetColorWindow(aboveValue-lvl);
1169  if(imageData->GetNumberOfScalarComponents() > 2) //Use RGB range
1170  viewer->SetColorWindow(255);
1171  viewer->SetColorLevel(lvl);
1172 
1173  refresh();
1174 }
1175 
1177 {
1178  return viewer->GetWindowLevel()->GetWindow();
1179 }
1180 
1182 {
1183  return viewer->GetWindowLevel()->GetLevel();
1184 }
1185 
1187 {
1188  viewer->GetWindowLevel()->SetWindow(window);
1189 }
1190 
1192 {
1193  viewer->GetWindowLevel()->SetLevel(level);
1194 }
1195 
1196 #if (ITK_REVIEW || ITK_VERSION_MAJOR > 3)
1197 void milxQtImage::overlay(QString filename)
1198 {
1199  printInfo("Overlaying Labelled Image");
1200 
1201  if(filename.isEmpty())
1202  filename = getOpenFilename("Select Labelled Image");
1203 
1204  if(filename.isEmpty())
1205  return;
1206 
1207  QPointer<milxQtImage> labelledImage = new milxQtImage;
1208  QPointer<milxQtFile> reader = new milxQtFile;
1209  bool success = reader->openImage(filename, labelledImage);
1210 
1211  if(!success)
1212  return;
1213 
1214 // binaryImage->contour(); //!< generate contour from binary image
1215 
1216  printDebug("Overlaying on Image");
1217  emit working(-1);
1218  if(eightbit)
1219  {
1220  if(labelledImage->is8BitImage())
1221  imageRGB = milx::Image<charImageType>::Overlay<charImageType>(imageChar, labelledImage->GetCharImage());
1222  else if(labelledImage->is32BitImage())
1223  imageRGB = milx::Image<charImageType>::Overlay<intImageType>(imageChar, labelledImage->GetIntImage());
1224  else
1225  imageRGB = milx::Image<charImageType>::Overlay<floatImageType>(imageChar, labelledImage->GetFloatImage());
1226  }
1227  else if(integer)
1228  {
1229  if(labelledImage->is8BitImage())
1230  imageRGB = milx::Image<intImageType>::Overlay<charImageType>(imageInt, labelledImage->GetCharImage());
1231  else if(labelledImage->is32BitImage())
1232  imageRGB = milx::Image<intImageType>::Overlay<intImageType>(imageInt, labelledImage->GetIntImage());
1233  else
1234  imageRGB = milx::Image<intImageType>::Overlay<floatImageType>(imageInt, labelledImage->GetFloatImage());
1235  }
1236 // else if(rgb)
1237 // imageRGB = milx::Image::Overlay<rgbImageType>(imageRGB, labelledImage->GetRGBImage());
1238  else
1239  {
1240  if(labelledImage->is8BitImage())
1242  else if(labelledImage->is32BitImage())
1244  else
1245  imageRGB = milx::Image<floatImageType>::Overlay<floatImageType>(imageFloat, labelledImage->GetFloatImage());
1246  }
1247  printWarning("Images Cast to RGB Image for colour!");
1248  printWarning("Origin may be reset!");
1249  emit done(-1);
1250 
1251  eightbit = false;
1252  rgb = true;
1253  generateImage();
1254 }
1255 
1256 void milxQtImage::overlayContour(QString filename)
1257 {
1258  printInfo("Overlaying Labelled Image as Contour");
1259 
1260  if(filename.isEmpty())
1261  {
1262  filename = getOpenFilename("Select Labelled Image");
1263  }
1264 
1265  if(filename.isEmpty())
1266  return;
1267 
1268  QPointer<milxQtImage> labelledImage = new milxQtImage;
1269  QPointer<milxQtFile> reader = new milxQtFile;
1270  bool success = reader->openImage(filename, labelledImage);
1271 
1272  if(!success)
1273  return;
1274 
1275 // binaryImage->contour(); //!< generate contour from binary image
1276 
1277  printDebug("Overlaying Contour on Image");
1278  emit working(-1);
1279  if(eightbit)
1280  {
1281  if(labelledImage->is8BitImage())
1283  else if(labelledImage->is32BitImage())
1285  else
1286  imageRGB = milx::Image<charImageType>::OverlayContour<floatImageType>(imageChar, labelledImage->GetFloatImage());
1287  }
1288  else if(integer)
1289  {
1290  if(labelledImage->is8BitImage())
1292  else if(labelledImage->is32BitImage())
1294  else
1295  imageRGB = milx::Image<intImageType>::OverlayContour<floatImageType>(imageInt, labelledImage->GetFloatImage());
1296  }
1297 // else if(rgb)
1298 // imageRGB = milx::Image::OverlayContour<rgbImageType>(imageRGB, labelledImage->GetRGBImage());
1299  else
1300  {
1301  if(labelledImage->is8BitImage())
1303  else if(labelledImage->is32BitImage())
1305  else
1306  imageRGB = milx::Image<floatImageType>::OverlayContour<floatImageType>(imageFloat, labelledImage->GetFloatImage());
1307  }
1308  printWarning("Images Cast to RGB Image for colour!");
1309  printWarning("Origin may be reset!");
1310  emit done(-1);
1311 
1312  eightbit = false;
1313  rgb = true;
1314  generateImage();
1315 }
1316 
1317 void milxQtImage::computeContour()
1318 {
1319  if(usingVTKImage)
1320  {
1321  printError("Contour from VTK image not support yet.");
1322  return;
1323  }
1324 
1325  printInfo("Computing Contour of Image");
1326  emit working(-1);
1327  if(eightbit)
1329  else if(integer)
1331  else if(rgb)
1333  else
1335  emit done(-1);
1336 
1337  generateImage();
1338 }
1339 #endif
1340 
1341 void milxQtImage::blend(QString filename, float opacity)
1342 {
1343  if(usingVTKImage)
1344  {
1345  printError("Information from VTK image not support yet.");
1346  return;
1347  }
1348 
1349  if(filename.isEmpty())
1350  filename = getOpenFilename();
1351 
1352  if(filename.isEmpty())
1353  return;
1354 
1355  printInfo("Displaying Blending of the Images");
1356 // emit working(-1);
1357 
1358  QPointer<milxQtImage> imageToMatch = new milxQtImage;
1359  QPointer<milxQtFile> reader = new milxQtFile;
1360  bool success = reader->openImage(filename, imageToMatch);
1361 
1362  if(!success)
1363  {
1364  emit done(-1);
1365  return;
1366  }
1367 
1368  imageToMatch->setName(filename);
1369 // imageToMatch->disableDefaultView();
1370  imageToMatch->generateImage();
1371  imageToMatch->setView(getView());
1372 
1373  blend(imageToMatch, opacity);
1374 }
1375 
1376 void milxQtImage::blend(milxQtImage *imageToMatch, float opacity)
1377 {
1378  bool ok1 = true;
1379  if(opacity < 0.0)
1380  {
1381  opacity = QInputDialog::getDouble(this, tr("Please Provide the opacity of the blending"),
1382  tr("Opacity:"), 0.5, 0, 2147483647, 2, &ok1);
1383  }
1384 
1385  if(!ok1)
1386  return;
1387 
1388  if(!GetLookupTable() || !imageToMatch->GetLookupTable())
1389  printWarning("Lookuptable for one of the images was not set.");
1390 
1391  emit working(-1);
1392  vtkSmartPointer<vtkImageData> ucharData1 = GetWindowLevel()->GetOutput();
1393 
1394  printInfo("Blending with Image: " + imageToMatch->strippedName());
1395  vtkSmartPointer<vtkImageData> ucharData2 = imageToMatch->GetWindowLevel()->GetOutput();
1396  printInfo("Number of components in Blending Image: " + QString::number(ucharData2->GetNumberOfScalarComponents()));
1397 
1398  // Combine the images (blend takes multiple connections on the 0th input port)
1399  vtkSmartPointer<vtkImageBlend> blend = vtkSmartPointer<vtkImageBlend>::New();
1400  #if VTK_MAJOR_VERSION <= 5
1401  blend->AddInput(ucharData1);
1402  blend->AddInput(ucharData2);
1403  #else
1404  blend->AddInputData(ucharData1);
1405  blend->AddInputData(ucharData2);
1406  #endif
1407  blend->SetOpacity(0,opacity);
1408  blend->SetOpacity(1,opacity);
1409  linkProgressEventOf(blend);
1410 // blend->SetBlendModeToCompound();
1411  blend->SetBlendModeToNormal();
1412  blend->Update();
1413 
1414  printInfo("Number of components in Blended Image: " + QString::number(blend->GetOutput()->GetNumberOfScalarComponents()));
1415  printInfo("Type of pixel in Blended Image: " + QString(blend->GetOutput()->GetScalarTypeAsString()));
1416 
1417  setData(blend->GetOutput());
1418  emit done(-1);
1419 
1420  //Force RGB colouring
1421  GetWindowLevel()->SetLookupTable(NULL);
1422  lookupTable = NULL;
1423  GetWindowLevel()->SetWindow(255);
1424  GetWindowLevel()->SetLevel(127.5);
1425  viewer->GetRenderer()->ResetCamera();
1426 
1427  generateImage();
1428 }
1429 
1431 {
1432  printInfo("Displaying Volume Rendering of Image");
1433 
1434  vtkSmartPointer<vtkImageData> img;
1435  if(flipped)
1436  {
1437  vtkSmartPointer<vtkImageFlip> imageReorient = vtkSmartPointer<vtkImageFlip>::New();
1438  #if VTK_MAJOR_VERSION <= 5
1439  imageReorient->SetInput(imageData);
1440  #else
1441  imageReorient->SetInputData(imageData);
1442  #endif
1443  imageReorient->SetFilteredAxis(1);
1444  imageReorient->FlipAboutOriginOn();
1445  linkProgressEventOf(imageReorient);
1446  imageReorient->Update(); //ITK image would have been flipped
1447  img = imageReorient->GetOutput();
1448  }
1449  else
1450  img = imageData;
1451 
1454  emit imageToVolume(img, eightbit);
1455 }
1456 
1458 {
1459  printInfo("Computing Information of Image");
1460  emit working(-1);
1461  //~ histogram(256, 0, 255, false);
1462 
1463  floatImageType::DirectionType direction;
1464  floatImageType::PointType origin;
1465  floatImageType::SpacingType spacing;
1466  floatImageType::RegionType::SizeType imageSize;
1467  if(usingVTKImage)
1468  {
1469  printWarning("Information from VTK image, as data not loaded as ITK image.");
1470  int extents[6];
1471 
1472  imageData->GetOrigin(origin.GetDataPointer());
1473  imageData->GetSpacing(spacing.GetDataPointer());
1474  imageData->GetExtent(extents);
1475 
1476  imageSize[0] = extents[1]-extents[0];
1477  imageSize[1] = extents[3]-extents[2];
1478  imageSize[2] = extents[5]-extents[4];
1479  }
1480  else
1481  {
1482  if(eightbit)
1483  {
1484  origin = imageChar->GetOrigin();
1485  spacing = imageChar->GetSpacing();
1486  imageSize = imageChar->GetLargestPossibleRegion().GetSize();
1487  direction = imageChar->GetDirection();
1488  printInfo("Image loaded as 8-bit image.");
1489  }
1490  else if(integer)
1491  {
1492  origin = imageInt->GetOrigin();
1493  spacing = imageInt->GetSpacing();
1494  imageSize = imageInt->GetLargestPossibleRegion().GetSize();
1495  direction = imageInt->GetDirection();
1496  printInfo("Image loaded as Integer image.");
1497  }
1498  else if(rgb)
1499  {
1500  origin = imageRGB->GetOrigin();
1501  spacing = imageRGB->GetSpacing();
1502  imageSize = imageRGB->GetLargestPossibleRegion().GetSize();
1503  direction = imageRGB->GetDirection();
1504  printInfo("Image loaded as RGB image.");
1505  }
1506  else
1507  {
1508  origin = imageFloat->GetOrigin();
1509  spacing = imageFloat->GetSpacing();
1510  imageSize = imageFloat->GetLargestPossibleRegion().GetSize();
1511  direction = imageFloat->GetDirection();
1512  printInfo("Image loaded as floating-point image.");
1513  }
1514  }
1515 
1516  printInfo("Origin: (" + QString::number(origin[0]) + ", " + QString::number(origin[1]) + ", " + QString::number(origin[2]) + ")");
1517  printInfo("Spacing: (" + QString::number(spacing[0]) + ", " + QString::number(spacing[1]) + ", " + QString::number(spacing[2]) + ")");
1518  printInfo("Size: (" + QString::number(imageSize[0]) + ", " + QString::number(imageSize[1]) + ", " + QString::number(imageSize[2]) + ")");
1519  printInfo("Real Size: (" + QString::number(spacing[0]*imageSize[0]) + ", " + QString::number(spacing[1]*imageSize[1]) + ", " + QString::number(spacing[2]*imageSize[2]) + ")");
1520  if(!usingVTKImage)
1521  {
1522  printInfo("Direction/Orientation: ");
1523  printInfo("|" + QString::number(direction(0,0)) + ", " + QString::number(direction(0,1)) + ", " + QString::number(direction(0,2)) + "|");
1524  printInfo("|" + QString::number(direction(1,0)) + ", " + QString::number(direction(1,1)) + ", " + QString::number(direction(1,2)) + "|");
1525  printInfo("|" + QString::number(direction(2,0)) + ", " + QString::number(direction(2,1)) + ", " + QString::number(direction(2,2)) + "|");
1526 
1527  QString orientFlagStr;
1528  if(eightbit)
1530  else if(integer)
1531  orientFlagStr = milx::Image<intImageType>::ImageOrientation(imageInt).c_str();
1532  else if(rgb)
1533  orientFlagStr = milx::Image<rgbImageType>::ImageOrientation(imageRGB).c_str();
1534  else
1536  printInfo("Orientation Flag: " + orientFlagStr);
1537  }
1538 
1539  emit done(-1);
1540 }
1541 
1543 {
1544  if(usingVTKImage)
1545  {
1546  printError("Rescale from VTK image not support yet.");
1547  return;
1548  }
1549 
1550  bool ok1, ok2;
1551  float newMinValue = QInputDialog::getDouble(this, tr("Please Provide the minimum value of new intensities"),
1552  tr("Minimum:"), minValue, -2147483647, 2147483647, 1, &ok1);
1553  float newMaxValue = QInputDialog::getDouble(this, tr("Please Provide the maximum value of new intensities"),
1554  tr("Maximum:"), maxValue, -2147483647, 2147483647, 1, &ok2);
1555 
1556  if(!ok1 || !ok2)
1557  return;
1558 
1559  printInfo("Rescaling Intensities of Image");
1560  emit working(-1);
1561  if(eightbit)
1563  else if(integer)
1564  imageInt = milx::Image<intImageType>::RescaleIntensity(imageInt, newMinValue, newMaxValue);
1565 // else if(rgb)
1566 // imageRGB = milx::Image<rgbImageType>::RescaledIntensity(imageRGB, newMinValue, newMaxValue);
1567  else
1569  emit done(-1);
1570 
1571  generateImage();
1572 }
1573 
1575 {
1576  if(usingVTKImage)
1577  {
1578  printError("Relabelling from VTK image not support yet.");
1579  return;
1580  }
1581 
1582  printInfo("Relabelling Image");
1583  emit working(-1);
1584  if(eightbit)
1586  else
1587  {
1588  printError("Relabelling only supports labelled images.");
1589  return;
1590  }
1591  emit done(-1);
1592 
1593  generateImage();
1594 }
1595 
1597 {
1598  if(usingVTKImage)
1599  {
1600  printError("Histogram equalisation from VTK image not support yet.");
1601  return;
1602  }
1603 
1604 // bool ok1, ok2;
1605 // float newMinValue = QInputDialog::getDouble(this, tr("Please Provide the minimum value of new intensities"),
1606 // tr("Minimum:"), minValue, -2147483647, 2147483647, 1, &ok1);
1607 // float newMaxValue = QInputDialog::getDouble(this, tr("Please Provide the maximum value of new intensities"),
1608 // tr("Maximum:"), maxValue, -2147483647, 2147483647, 1, &ok2);
1609 //
1610 // if(!ok1 || !ok2)
1611 // return;
1612 
1613  printInfo("Histogram Equalisation of Image");
1614  emit working(-1);
1615  if(eightbit)
1617  else if(integer)
1619 // else if(rgb)
1620 // imageRGB = milx::Image<rgbImageType>::HistogramEqualisation(imageRGB);
1621  else
1623  emit done(-1);
1624 
1625  generateImage();
1626 }
1627 
1629 {
1630  if(usingVTKImage)
1631  {
1632  printError("Gradient Magnitude from VTK image not support yet.");
1633  return;
1634  }
1635 
1636  printInfo("Computing Gradient Magnitude of Image");
1637  emit working(-1);
1638  if(eightbit)
1640  else if(integer)
1642 // else if(rgb)
1643 // imageRGB = milx::Image<rgbImageType>::GradientMagnitude(imageRGB);
1644  else
1646  emit done(-1);
1647 
1648  generateImage();
1649 }
1650 
1652 {
1653  if(usingVTKImage)
1654  {
1655  printError("Sobel Edges from VTK image not support yet.");
1656  return;
1657  }
1658 
1659  printInfo("Computing Sobel Edges of Image");
1660  emit working(-1);
1661  if(eightbit)
1662  {
1664  eightbit = false;
1665  }
1666  else if(integer)
1667  {
1669  integer = false;
1670  }
1671 // else if(rgb)
1672 // imageRGB = milx::Image<rgbImageType>::SobelEdges(imageRGB);
1673  else
1675  emit done(-1);
1676 
1677  generateImage();
1678 }
1679 
1681 {
1682  if(usingVTKImage)
1683  {
1684  printError("Canny Edges from VTK image not support yet.");
1685  return;
1686  }
1687 
1688  bool ok1, ok2, ok3;
1689  float variance = QInputDialog::getDouble(this, tr("Please Provide the variance"),
1690  tr("Variance:"), 2.0, 0.0, 1000.0, 5, &ok1);
1691  float upper = QInputDialog::getDouble(this, tr("Please Provide the upper threshold"),
1692  tr("Upper Threshold:"), maxValue, minValue, maxValue, 5, &ok2);
1693  float lower = QInputDialog::getDouble(this, tr("Please Provide the lower threshold"),
1694  tr("Lower Threshold:"), minValue, minValue, maxValue, 5, &ok3);
1695 
1696  if(!ok1 || !ok2 || !ok3)
1697  return;
1698 
1699  printInfo("Computing Canny Edges of Image");
1700  emit working(-1);
1701  if(eightbit)
1702  {
1703  //must be float type image
1705  eightbit = false;
1706  }
1707  else if(integer)
1708  {
1709  //must be float type image
1711  integer = false;
1712  }
1713 // else if(rgb)
1714 // imageRGB = milx::Image<rgbImageType>::CannyEdges(imageRGB, variance, lower, upper);
1715  else
1717  emit done(-1);
1718 
1719  generateImage();
1720 }
1721 
1723 {
1724  if(usingVTKImage)
1725  {
1726  printError("Laplacian from VTK image not support yet.");
1727  return;
1728  }
1729 
1730  printInfo("Computing Laplacian of Image");
1731  emit working(-1);
1732  if(eightbit)
1733  {
1734  //must be float type image
1736  eightbit = false;
1737  }
1738  else if(integer)
1739  {
1740  //must be float type image
1742  integer = false;
1743  }
1744 // else if(rgb)
1745 // imageRGB = milx::Image<rgbImageType>::Laplacian(imageRGB);
1746  else
1748  emit done(-1);
1749 
1750  generateImage();
1751 }
1752 
1754 {
1755  if(usingVTKImage)
1756  {
1757  printError("Normalizing from VTK image not support yet.");
1758  return;
1759  }
1760 
1761  printInfo("Normalizing Image");
1762  emit working(-1);
1763  if(eightbit)
1764  {
1766  eightbit = false;
1767  }
1768  else if(integer)
1769  {
1771  integer = false;
1772  }
1773 // else if(rgb)
1774 // {
1775 // imageFloat = milx::Image<rgbImageType>::Normalization(imageRGB);
1776 // rgb = false;
1777 // }
1778  else
1780  emit done(-1);
1781 
1782  generateImage();
1783 }
1784 
1786 {
1787  if(usingVTKImage)
1788  {
1789  printError("Invert Intensity from VTK image not support yet.");
1790  return;
1791  }
1792 
1793  histogram(256, 0, 255, false); //needed to determine max value
1794 
1795  printInfo("Inverting Intensity of Image");
1796  emit working(-1);
1797  if(eightbit)
1799  else if(integer)
1801 // else if(rgb)
1802 // imageRGB = milx::Image<rgbImageType>::InvertIntensity(imageRGB, maxValue);
1803  else
1805  emit done(-1);
1806 
1807  generateImage();
1808 }
1809 
1811 {
1812  printInfo("Matching Info of Image");
1813  emit working(-1);
1814  if(eightbit)
1816  else if(integer)
1818  else if(rgb)
1820  else
1822  emit done(-1);
1823 
1824  generateImage();
1825 }
1826 
1827 void milxQtImage::matchInfo(QString filename)
1828 {
1829  if(usingVTKImage)
1830  {
1831  printError("Matching Info from VTK image not support yet.");
1832  return;
1833  }
1834 
1835  if(filename.isEmpty())
1836  filename = getOpenFilename();
1837 
1838  if(filename.isEmpty())
1839  return;
1840 
1841  QPointer<milxQtImage> imageToMatch = new milxQtImage;
1842  QPointer<milxQtFile> reader = new milxQtFile;
1843  bool success = reader->openImage(filename, imageToMatch);
1844 
1845  if(!success)
1846  return;
1847 
1848  matchInfo(imageToMatch);
1849 }
1850 
1852 {
1853  printInfo("Matching Histogram of Image");
1854  emit working(-1);
1855  if(eightbit)
1857  else if(integer)
1859 // else if(rgb)
1860 // imageRGB = milx::Image<rgbImageType>::MatchInformation(imageRGB, imageToMatch->GetRGBImage());
1861  else
1863  emit done(-1);
1864 
1865  generateImage();
1866 }
1867 
1868 void milxQtImage::matchHistogram(QString filename)
1869 {
1870  if(usingVTKImage)
1871  {
1872  printError("Matching Histogram from VTK image not support yet.");
1873  return;
1874  }
1875 
1876  if(filename.isEmpty())
1877  filename = getOpenFilename();
1878 
1879  if(filename.isEmpty())
1880  return;
1881 
1882  QPointer<milxQtImage> imageToMatch = new milxQtImage;
1883  QPointer<milxQtFile> reader = new milxQtFile;
1884  bool success = reader->openImage(filename, imageToMatch);
1885 
1886  if(!success)
1887  return;
1888 
1889  matchHistogram(imageToMatch);
1890 }
1891 
1892 void milxQtImage::resample(QString filename)
1893 {
1894  if(usingVTKImage)
1895  {
1896  printError("Resampling from VTK image not support yet.");
1897  return;
1898  }
1899 
1900  if(filename.isEmpty())
1901  filename = getOpenFilename();
1902 
1903  if(filename.isEmpty())
1904  return;
1905 
1906  QPointer<milxQtImage> imageToMatch = new milxQtImage;
1907  QPointer<milxQtFile> reader = new milxQtFile;
1908  bool success = reader->openImage(filename, imageToMatch);
1909 
1910  if(!success)
1911  return;
1912 
1913  printInfo("Resampling Image");
1914  emit working(-1);
1915  if(eightbit)
1916  {
1917  if(imageToMatch->is8BitImage())
1919  else if(imageToMatch->is32BitImage())
1920  {
1921  imageInt = milx::Image<charImageType>::ResampleImage<intImageType>(imageChar, imageToMatch->GetIntImage());
1922  eightbit = false;
1923  integer = true;
1924  }
1925  else
1926  {
1927  imageFloat = milx::Image<charImageType>::ResampleImage<floatImageType>(imageChar, imageToMatch->GetFloatImage());
1928  eightbit = false;
1929  }
1930  }
1931  else if(integer)
1932  {
1933  if(imageToMatch->is8BitImage())
1934  {
1935  imageChar = milx::Image<intImageType>::ResampleImage<charImageType>(imageInt, imageToMatch->GetCharImage());
1936  eightbit = true;
1937  integer = false;
1938  }
1939  else if(imageToMatch->is32BitImage())
1941  else
1942  {
1943  imageFloat = milx::Image<intImageType>::ResampleImage<floatImageType>(imageInt, imageToMatch->GetFloatImage());
1944  integer = false;
1945  }
1946  }
1947 // else if(rgb)
1948 // imageRGB = milx::Image<rgbImageType>::ResampleImage(imageRGB, imageToMatch->GetRGBImage());
1949  else
1950  {
1951  if(imageToMatch->is8BitImage())
1952  {
1953  imageChar = milx::Image<floatImageType>::ResampleImage<charImageType>(imageFloat, imageToMatch->GetCharImage());
1954  eightbit = true;
1955  }
1956  else
1957  imageFloat = milx::Image<floatImageType>::ResampleImage<floatImageType>(imageFloat, imageToMatch->GetFloatImage());
1958  }
1959  emit done(-1);
1960 
1961  generateImage();
1962 }
1963 
1964 void milxQtImage::mask(QString filename)
1965 {
1966  if(usingVTKImage)
1967  {
1968  printError("Masking from VTK image not support yet.");
1969  return;
1970  }
1971 
1972  if(filename.isEmpty())
1973  filename = getOpenFilename("Select Mask");
1974 
1975  if(filename.isEmpty())
1976  return;
1977 
1978  QPointer<milxQtImage> imageToMatch = new milxQtImage;
1979  QPointer<milxQtFile> reader = new milxQtFile;
1980  bool success = reader->openImage(filename, imageToMatch);
1981 
1982  if(!success)
1983  return;
1984 
1985  printInfo("Masking Image");
1986  emit working(-1);
1987  if(eightbit)
1988  {
1989  if(imageToMatch->is8BitImage())
1991  else
1992  imageChar = milx::Image<charImageType>::MaskImage<floatImageType>(imageChar, imageToMatch->GetFloatImage());
1993  }
1994  else if(integer)
1995  {
1996  if(imageToMatch->is8BitImage())
1998  else
1999  imageInt = milx::Image<intImageType>::MaskImage<intImageType>(imageInt, imageToMatch->GetIntImage());
2000  }
2001 // else if(rgb)
2002 // imageRGB = milx::Image<rgbImageType>::MaskImage<rgbImageType>(imageRGB, imageToMatch->GetRGBImage());
2003 #if ITK_VERSION_MAJOR > 3
2004  else if(vectorised)
2005  {
2006  if(imageToMatch->is8BitImage())
2008  else
2009  imageVector = milx::Image<vectorImageType>::MaskImage<floatImageType>(imageVector, imageToMatch->GetFloatImage());
2010 
2011  magnitude();
2012  }
2013 #endif
2014  else
2015  {
2016  if(imageToMatch->is8BitImage())
2018  else
2019  imageFloat = milx::Image<floatImageType>::MaskImage<floatImageType>(imageFloat, imageToMatch->GetFloatImage());
2020  }
2021  emit done(-1);
2022 
2023  generateImage();
2024 }
2025 
2026 void milxQtImage::subsample(size_t xSampleFactor, size_t ySampleFactor, size_t zSampleFactor)
2027 {
2028  if(usingVTKImage)
2029  {
2030  printError("Resampling from VTK image not support yet.");
2031  return;
2032  }
2033 
2034  bool ok1 = false, ok2 = false, ok3 = false;
2035  if(xSampleFactor == 0 && ySampleFactor == 0 && zSampleFactor == 0)
2036  {
2037  xSampleFactor = QInputDialog::getInt(this, tr("Please Provide the downsample factors"),
2038  tr("X Factor:"), 2, 0, 1000, 1, &ok1);
2039  ySampleFactor = QInputDialog::getInt(this, tr("Please Provide the downsample factors"),
2040  tr("Y Factor:"), 2, 0, 1000, 1, &ok2);
2041  zSampleFactor = QInputDialog::getInt(this, tr("Please Provide the downsample factors"),
2042  tr("Z Factor:"), 2, 0, 1000, 1, &ok3);
2043  }
2044 
2045  if(!ok1 || !ok2 || !ok3)
2046  return;
2047 
2048  printInfo("Subsampling Image");
2049  emit working(-1);
2050  floatImageType::SizeType factors;
2051  factors[0] = xSampleFactor;
2052  factors[1] = ySampleFactor;
2053  factors[2] = zSampleFactor;
2054  if(eightbit)
2056  else if(integer)
2058  else if(rgb)
2060  else if(vectorised)
2062  else
2064  emit done(-1);
2065 
2066  generateImage();
2067 }
2068 
2069 void milxQtImage::crop(QString filename)
2070 {
2071  if(usingVTKImage)
2072  {
2073  printError("Masking from VTK image not support yet.");
2074  return;
2075  }
2076 
2077  if(filename.isEmpty())
2078  filename = getOpenFilename("Select Mask");
2079 
2080  if(filename.isEmpty())
2081  return;
2082 
2083  QPointer<milxQtImage> imageToMatch = new milxQtImage;
2084  QPointer<milxQtFile> reader = new milxQtFile;
2085  bool success = reader->openImage(filename, imageToMatch);
2086 
2087  if(!success)
2088  return;
2089 
2090 #if (ITK_REVIEW || ITK_VERSION_MAJOR > 3)
2091  printInfo("Masking and Cropping Image");
2092  emit working(-1);
2093  if(eightbit)
2094  {
2095  if(imageToMatch->is8BitImage())
2097  else
2098  imageChar = milx::Image<charImageType>::MaskAndCropImage<floatImageType>(imageChar, imageToMatch->GetFloatImage());
2099  }
2100  else if(integer)
2101  {
2102  if(imageToMatch->is8BitImage())
2104  else
2105  imageInt = milx::Image<intImageType>::MaskAndCropImage<floatImageType>(imageInt, imageToMatch->GetFloatImage());
2106  }
2107 // else if(rgb)
2108 // imageRGB = milx::Image<rgbImageType>::MaskAndCropImage<rgbImageType>(imageRGB, imageToMatch->GetRGBImage());
2109  else if(vectorised)
2110  {
2111  if(imageToMatch->is8BitImage())
2113  else
2114  imageVector = milx::Image<vectorImageType>::MaskAndCropImage<floatImageType>(imageVector, imageToMatch->GetFloatImage());
2115 
2116  magnitude();
2117  }
2118  else
2119  {
2120  if(imageToMatch->is8BitImage())
2122  else
2123  imageFloat = milx::Image<floatImageType>::MaskAndCropImage<floatImageType>(imageFloat, imageToMatch->GetFloatImage());
2124  }
2125  emit done(-1);
2126 #endif // (ITK_REVIEW || ITK_VERSION_MAJOR > 3)
2127 
2128  generateImage();
2129 }
2130 
2131 void milxQtImage::resampleLabel(QString filename)
2132 {
2133  if(usingVTKImage)
2134  {
2135  printError("Resampling from VTK image not support yet.");
2136  return;
2137  }
2138 
2139  if(filename.isEmpty())
2140  filename = getOpenFilename("Select Reference Image");
2141 
2142  if(filename.isEmpty())
2143  return;
2144 
2145  QPointer<milxQtImage> imageToMatch = new milxQtImage;
2146  QPointer<milxQtFile> reader = new milxQtFile;
2147  bool success = reader->openImage(filename, imageToMatch);
2148 
2149  if(!success)
2150  return;
2151 
2152  printInfo("Resampling as Labelled Image");
2153  emit working(-1);
2154  if(eightbit)
2155  {
2156  if(imageToMatch->is8BitImage())
2158  else
2159  {
2160  imageFloat = milx::Image<charImageType>::ResampleLabel<floatImageType>(imageChar, imageToMatch->GetFloatImage());
2161  eightbit = false;
2162  }
2163  }
2164  else if(integer)
2165  {
2166  if(imageToMatch->is8BitImage())
2167  {
2168  imageChar = milx::Image<intImageType>::ResampleLabel<charImageType>(imageInt, imageToMatch->GetCharImage());
2169  eightbit = true;
2170  integer = false;
2171  }
2172  else
2173  {
2174  imageFloat = milx::Image<intImageType>::ResampleLabel<floatImageType>(imageInt, imageToMatch->GetFloatImage());
2175  integer = false;
2176  }
2177  }
2178 // else if(rgb)
2179 // imageRGB = milx::Image<rgbImageType>::ResampleLabel(imageRGB, imageToMatch->GetRGBImage());
2180  else
2181  {
2182  if(imageToMatch->is8BitImage())
2183  {
2184  imageChar = milx::Image<floatImageType>::ResampleLabel<charImageType>(imageFloat, imageToMatch->GetCharImage());
2185  eightbit = true;
2186  }
2187  else
2188  imageFloat = milx::Image<floatImageType>::ResampleLabel<floatImageType>(imageFloat, imageToMatch->GetFloatImage());
2189  }
2190  emit done(-1);
2191 
2192  generateImage();
2193 }
2194 
2195 void milxQtImage::transform(QString filename, QString refImgFilename, bool inverse)
2196 {
2197  if(usingVTKImage)
2198  {
2199  printError("Checker Board from VTK image not support yet.");
2200  return;
2201  }
2202 
2203  if(filename.isEmpty())
2204  {
2205  filename = getOpenFilename("Select Transform File", "ITK Transform Files (*.txt *.tfm);;VTK Transform Files (*.trsf)");
2206 
2207  QMessageBox msgBox;
2208  msgBox.setText("Use Reference Image");
2209  msgBox.setInformativeText("Do you want to resample to a reference image?");
2210  msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
2211  msgBox.setDefaultButton(QMessageBox::Yes);
2212  int ret1 = msgBox.exec();
2213 
2214  if(ret1 == QMessageBox::Yes)
2215  refImgFilename = getOpenFilename("Select Reference Image");
2216 
2217  QMessageBox msgBox2;
2218  msgBox2.setText("Invert Transform");
2219  msgBox2.setInformativeText("Do you want to invert the transform?");
2220  msgBox2.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
2221  msgBox2.setDefaultButton(QMessageBox::Yes);
2222  int ret2 = msgBox2.exec();
2223 
2224  if(ret2 == QMessageBox::Yes)
2225  inverse = true;
2226  }
2227 
2228  if(filename.isEmpty())
2229  return;
2230 
2231  typedef double transformType;
2232  typedef itk::Transform<transformType> TransformType;
2233  TransformType::Pointer transf = milx::File::OpenTransform<transformType>(filename.toStdString());
2234 
2235  cout << "Transform to be used: ";
2236  transf.Print(cout);
2237 
2238  QPointer<milxQtImage> imageToMatch = new milxQtImage;
2239  QPointer<milxQtFile> reader = new milxQtFile;
2240  bool success = false;
2241  if(!refImgFilename.isEmpty())
2242  {
2243  success = reader->openImage(refImgFilename, imageToMatch);
2244 
2245  if(!success)
2246  return;
2247  }
2248 
2249  printInfo("Transforming Image with " + QString(transf->GetTransformTypeAsString().c_str()));
2250  emit working(-1);
2251  if(!refImgFilename.isEmpty())
2252  {
2253  if(eightbit)
2254  {
2255  if(imageToMatch->is8BitImage())
2256  imageChar = milx::Image<charImageType>::TransformImage<charImageType, TransformType, transformType>(imageChar, imageToMatch->GetCharImage(), transf, inverse, 0); //NN Interp
2257  else
2258  {
2259  imageFloat = milx::Image<charImageType>::TransformImage<floatImageType, TransformType, transformType>(imageChar, imageToMatch->GetFloatImage(), transf, inverse, 0); //NN interp
2260  eightbit = false;
2261  }
2262  }
2263  else if(integer)
2264  {
2265  if(imageToMatch->is8BitImage())
2266  {
2267  imageChar = milx::Image<intImageType>::TransformImage<charImageType, TransformType, transformType>(imageInt, imageToMatch->GetCharImage(), transf, inverse, 0); //NN Interp
2268  eightbit = true;
2269  integer = false;
2270  }
2271  else
2272  {
2273  imageFloat = milx::Image<intImageType>::TransformImage<floatImageType, TransformType, transformType>(imageInt, imageToMatch->GetFloatImage(), transf, inverse, 0); //NN interp
2274  integer = false;
2275  }
2276  }
2277  // else if(rgb)
2278  // imageRGB = milx::Image<rgbImageType>::TransformImage(imageRGB, imageToMatch->GetRGBImage(), transf);
2279  else
2280  {
2281  if(imageToMatch->is8BitImage())
2282  {
2283  imageChar = milx::Image<floatImageType>::TransformImage<charImageType, TransformType, transformType>(imageFloat, imageToMatch->GetCharImage(), transf, inverse);
2284  eightbit = true;
2285  }
2286  else
2287  imageFloat = milx::Image<floatImageType>::TransformImage<floatImageType, TransformType, transformType>(imageFloat, imageToMatch->GetFloatImage(), transf, inverse);
2288  }
2289  }
2290  else
2291  {
2292  printDebug("Transforming without reference image");
2293  if(eightbit)
2294  {
2295  if(imageToMatch->is8BitImage())
2297  else
2298  {
2299  imageFloat = milx::Image<charImageType>::TransformImage<floatImageType, TransformType, transformType>(imageChar, transf, inverse, 0); //NN Interp
2300  eightbit = false;
2301  }
2302  }
2303  else if(integer)
2304  {
2305  if(imageToMatch->is8BitImage())
2306  {
2307  imageChar = milx::Image<intImageType>::TransformImage<charImageType, TransformType, transformType>(imageInt, transf, inverse);
2308  eightbit = true;
2309  integer = false;
2310  }
2311  else
2312  {
2313  imageFloat = milx::Image<intImageType>::TransformImage<floatImageType, TransformType, transformType>(imageInt, transf, inverse);
2314  integer = false;
2315  }
2316  }
2317  // else if(rgb)
2318  // imageRGB = milx::Image<rgbImageType>::TransformImage(imageRGB, imageToMatch->GetRGBImage(), transf);
2319  else
2320  {
2321  if(imageToMatch->is8BitImage())
2322  {
2323  imageChar = milx::Image<floatImageType>::TransformImage<charImageType, TransformType, transformType>(imageFloat, transf, inverse);
2324  eightbit = true;
2325  }
2326  else
2327  imageFloat = milx::Image<floatImageType>::TransformImage<floatImageType, TransformType, transformType>(imageFloat, transf, inverse);
2328  }
2329  }
2330  emit done(-1);
2331  printDebug("Done Transforming");
2332 
2333  generateImage();
2334 }
2335 
2336 void milxQtImage::checkerBoard(milxQtImage *img, int numberOfSquares)
2337 {
2338  if(usingVTKImage)
2339  {
2340  printError("Checker Board from VTK image not support yet.");
2341  return;
2342  }
2343 
2344  bool ok = false;
2345  if(numberOfSquares == 0)
2346  {
2347  numberOfSquares = QInputDialog::getInt(this, tr("Please Provide the number of squares"),
2348  tr("Squares:"), 10, 0, 100, 1, &ok);
2349  }
2350 
2351  if(!ok)
2352  return;
2353 
2354  printInfo("Checker Boarding Image");
2355  emit working(-1);
2356  if(actualNumberOfDimensions > 2)
2357  {
2358  if(eightbit)
2360  else if(eightbit)
2362  // else if(rgb)
2363  // imageRGB = milx::Image<rgbImageType>::CheckerBoard(imageRGB, img->GetRGBImage());
2364  else
2365  imageFloat = milx::Image<floatImageType>::CheckerBoard(imageFloat, img->GetFloatImage(), numberOfSquares);
2366  }
2367  else if(actualNumberOfDimensions == 2) //need to handle 2D images explicitly, floating point exception otherwise
2368  {
2369  int extent[6];
2370  viewer->GetImageActor()->GetDisplayExtent(extent);
2371 
2372  if(flipped)
2373  {
2374  int actualExtent[6];
2375  imageData->GetExtent(actualExtent);
2376 
2377  if(extent[3]-extent[2] == 0) //flip y extent
2378  {
2379  extent[2] = actualExtent[3]-extent[2];
2380  extent[3] = actualExtent[3]-extent[3];
2381  }
2382  }
2383 
2384  if(eightbit)
2385  {
2386  typedef itk::Image<charPixelType, 2> charImage2DType;
2387  charImage2DType::Pointer imageChar2D = milx::Image<charImageType>::ExtractSlice<charImage2DType>(imageChar, extent);
2388  charImage2DType::Pointer imageChar2DToChecker = milx::Image<charImageType>::ExtractSlice<charImage2DType>(img->GetCharImage(), extent);
2389  imageChar2D = milx::Image<charImage2DType>::CheckerBoard(imageChar2D, imageChar2DToChecker, numberOfSquares);
2390  imageChar = milx::Image<charImage2DType>::CastImage<charImageType>(imageChar2D);
2391  }
2392  else if(integer)
2393  {
2394  typedef itk::Image<intPixelType, 2> intImage2DType;
2395  intImage2DType::Pointer imageInt2D = milx::Image<charImageType>::ExtractSlice<intImage2DType>(imageChar, extent);
2396  intImage2DType::Pointer imageInt2DToChecker = milx::Image<intImageType>::ExtractSlice<intImage2DType>(img->GetIntImage(), extent);
2397  imageInt2D = milx::Image<intImage2DType>::CheckerBoard(imageInt2D, imageInt2DToChecker, numberOfSquares);
2398  imageInt = milx::Image<intImage2DType>::CastImage<intImageType>(imageInt2D);
2399  }
2400  // else if(rgb)
2401  // imageRGB = milx::Image<rgbImageType>::CheckerBoard(imageRGB, img->GetRGBImage());
2402  else
2403  {
2404  typedef itk::Image<floatPixelType, 2> floatImage2DType;
2405  floatImage2DType::Pointer imageFloat2D = milx::Image<floatImageType>::ExtractSlice<floatImage2DType>(imageFloat, extent);
2406  floatImage2DType::Pointer imageFloat2DToChecker = milx::Image<floatImageType>::ExtractSlice<floatImage2DType>(img->GetFloatImage(), extent);
2407  imageFloat2D = milx::Image<floatImage2DType>::CheckerBoard(imageFloat2D, imageFloat2DToChecker, numberOfSquares);
2408  imageFloat = milx::Image<floatImage2DType>::CastImage<floatImageType>(imageFloat2D);
2409  }
2410  }
2411  else
2412  {
2413  printError("Actual Dimensions of data is" + QString::number(actualNumberOfDimensions) + ", which is not supported. Ignoring.");
2414  }
2415  emit done(-1);
2416 
2417  generateImage();
2418 }
2419 
2420 void milxQtImage::checkerBoard(QString filename, int numberOfSquares)
2421 {
2422  if(usingVTKImage)
2423  {
2424  printError("Checker Board from VTK image not support yet.");
2425  return;
2426  }
2427 
2428  if(filename.isEmpty())
2429  filename = getOpenFilename();
2430 
2431  if(filename.isEmpty())
2432  return;
2433 
2434  QPointer<milxQtImage> imageToMatch = new milxQtImage;
2435  QPointer<milxQtFile> reader = new milxQtFile;
2436  bool success = reader->openImage(filename, imageToMatch);
2437 
2438  if(!success)
2439  return;
2440 
2441  checkerBoard(imageToMatch, numberOfSquares);
2442 }
2443 
2444 void milxQtImage::distanceMap(bool signedDistance, bool inside)
2445 {
2446  if(usingVTKImage)
2447  {
2448  printError("Distance Map from VTK image not support yet.");
2449  return;
2450  }
2451 
2452  /*if(signedDistance && inside)
2453  {
2455  QMessageBox msgBox;
2456  msgBox.setText("Distance Map Type");
2457  msgBox.setInformativeText("Do you wish to compute signed distances?");
2458  msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
2459  msgBox.setDefaultButton(QMessageBox::Yes);
2460  int ret = msgBox.exec();
2461  if(ret == QMessageBox::Yes)
2462  {
2463  msgBox.setText("Distance Map Inside or Outside");
2464  msgBox.setInformativeText("Do you wish to compute inside (the object) distances?");
2465  msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
2466  msgBox.setDefaultButton(QMessageBox::No);
2467  }
2468  else
2469  signedDistance = false;
2470  int retInside = msgBox.exec();
2471  }*/
2472 
2473  emit working(-1);
2474  if(eightbit)
2475  {
2476  imageFloat = milx::Image<charImageType>::DistanceMap<floatImageType>(imageChar, true, signedDistance, inside);
2477  eightbit = false;
2478  }
2479  else if(integer)
2480  {
2481  imageFloat = milx::Image<intImageType>::DistanceMap<floatImageType>(imageInt, true, signedDistance, inside);
2482  integer = false;
2483  }
2484 // else if(rgb)
2485 // imageRGB = milx::Image::DistanceMap<rgbImageType>(imageRGB);
2486  else
2487  {
2488  imageFloat = milx::Image<floatImageType>::DistanceMap<floatImageType>(imageFloat, false, signedDistance, inside);
2489  }
2490  emit done(-1);
2491 
2492  generateImage();
2493 }
2494 
2495 void milxQtImage::thresholdAbove(float value, float level)
2496 {
2497  if(usingVTKImage)
2498  {
2499  printError("Threshold above for VTK image not support yet.");
2500  return;
2501  }
2502 
2503  histogram(256, 0, 255, false);
2504 
2505  bool ok1 = false, ok2 = false;
2506  if(value == 0 && level == 0)
2507  {
2508  value = QInputDialog::getDouble(this, tr("Please Provide Outside Value"),
2509  tr("Outside Value:"), 0, minValue, maxValue, 5, &ok1);
2510  level = QInputDialog::getDouble(this, tr("Please Provide the threshold upper level"),
2511  tr("Level:"), maxValue, minValue, maxValue, 5, &ok2);
2512 
2513  if(!ok1 || !ok2)
2514  return;
2515  }
2516 
2517  printInfo("Thresholding Image from above");
2518  emit working(-1);
2519  if(eightbit)
2521  else if(integer)
2523 // else if(rgb)
2524 // imageRGB = milx::Image<rgbImageType>::ThresholdAboveImage(imageRGB);
2525  else
2527  emit done(-1);
2528 
2529  generateImage();
2530 }
2531 
2532 void milxQtImage::thresholdBelow(float value, float level)
2533 {
2534  if(usingVTKImage)
2535  {
2536  printError("Threshold below for VTK image not support yet.");
2537  return;
2538  }
2539 
2540  histogram(256, 0, 255, false);
2541 
2542  bool ok1 = false, ok2 = false;
2543  if(value == 0 && level == 0)
2544  {
2545  value = QInputDialog::getDouble(this, tr("Please Provide Outside Value"),
2546  tr("Outside Value:"), 0, minValue, maxValue, 5, &ok1);
2547  level = QInputDialog::getDouble(this, tr("Please Provide the threshold lower level"),
2548  tr("Level:"), minValue, minValue, maxValue, 5, &ok2);
2549 
2550  if(!ok1 || !ok2)
2551  return;
2552  }
2553 
2554  printInfo("Thresholding Image from below");
2555  emit working(-1);
2556  if(eightbit)
2558  else if(integer)
2560 // else if(rgb)
2561 // imageRGB = milx::Image<rgbImageType>::ThresholdBelowImage(imageRGB);
2562  else
2564  emit done(-1);
2565 
2566  generateImage();
2567 }
2568 
2569 void milxQtImage::threshold(float value, float blevel, float alevel)
2570 {
2571  if(usingVTKImage)
2572  {
2573  printError("Threshold for VTK image not support yet.");
2574  return;
2575  }
2576 
2577  histogram(256, 0, 255, false);
2578 
2579  bool ok1 = false, ok2 = false, ok3 = false;
2580  if(value == 0 && blevel == 0 && alevel == 0)
2581  {
2582  value = QInputDialog::getDouble(this, tr("Please Provide Outside Value"),
2583  tr("Outside Value:"), 0, minValue, maxValue, 5, &ok1);
2584  blevel = QInputDialog::getDouble(this, tr("Please Provide the threshold lower level"),
2585  tr("Lower Level:"), minValue, minValue, maxValue, 5, &ok2);
2586  alevel = QInputDialog::getDouble(this, tr("Please Provide the threshold upper level"),
2587  tr("Upper Level:"), maxValue, minValue, maxValue, 5, &ok3);
2588 
2589  if(!ok1 || !ok2 || !ok3)
2590  return;
2591  }
2592 
2593  printInfo("Thresholding Image");
2594  emit working(-1);
2595  if(eightbit)
2597  else if(integer)
2599 // else if(rgb)
2600 // imageRGB = milx::Image<rgbImageType>::ThresholdImage(imageRGB, blevel, alevel);
2601  else
2603  emit done(-1);
2604 
2605  generateImage();
2606 }
2607 
2608 void milxQtImage::otsu(int bins)
2609 {
2610  if(usingVTKImage)
2611  {
2612  printError("Otsu Threshold for VTK image not support yet.");
2613  return;
2614  }
2615 
2616  histogram(256, 0, 255, false);
2617 
2618  bool ok = false;
2619  if(bins == 0)
2620  {
2621  bins = QInputDialog::getInt(this, tr("Please Provide the histogram bins to use"),
2622  tr("Bins:"), 128, 0, 8192, 1, &ok);
2623  }
2624 
2625  if(!ok)
2626  return;
2627 
2628  printInfo("Otsu Thresholding Image");
2629  emit working(-1);
2630  if(eightbit)
2632  else if(integer)
2634  //~ else if(rgb)
2635  //~ imageChar = milx::Image<rgbImageType>::OtsuThresholdImage<charImageType>(imageRGB, bins);
2636  else
2637  imageChar = milx::Image<floatImageType>::OtsuThresholdImage<charImageType>(imageFloat, bins);
2638  emit done(-1);
2639 
2640  eightbit = true;
2641  rgb = false;
2642  generateImage();
2643 }
2644 
2645 void milxQtImage::otsuMultiple(int bins, int labels)
2646 {
2647  if(usingVTKImage)
2648  {
2649  printError("Otsu Multiple Threshold for VTK image not support yet.");
2650  return;
2651  }
2652 
2653  histogram(256, 0, 255, false);
2654 
2655  bool ok = false;
2656  if(bins == 0)
2657  {
2658  bins = QInputDialog::getInt(this, tr("Please Provide the histogram bins to use"),
2659  tr("Bins:"), 128, 0, 8192, 1, &ok);
2660  labels = QInputDialog::getInt(this, tr("Please Provide the number of labels to produce"),
2661  tr("Labels:"), 1, 0, 8192, 1, &ok);
2662  }
2663 
2664  if(!ok)
2665  return;
2666 
2667  printInfo("Otsu Multiple Thresholding Image");
2668  emit working(-1);
2669  if(eightbit)
2671  else if(integer)
2673  //~ else if(rgb)
2674  //~ imageChar = milx::Image<rgbImageType>::OtsuMultipleThresholdImage<charImageType>(imageRGB, bins, labels);
2675  else
2676  imageChar = milx::Image<floatImageType>::OtsuMultipleThresholdImage<charImageType>(imageFloat, bins, labels);
2677  emit done(-1);
2678 
2679  eightbit = true;
2680  rgb = false;
2681  generateImage();
2682 }
2683 
2684 void milxQtImage::binaryThreshold(float value, float blevel, float alevel)
2685 {
2686  if(usingVTKImage)
2687  {
2688  printError("Binary Threshold for VTK image not support yet.");
2689  return;
2690  }
2691 
2692  histogram(256, 0, 255, false);
2693 
2694  bool ok1 = false, ok2 = false, ok3 = false;
2695  if(value == 0 && blevel == 0 && alevel == 0)
2696  {
2697  value = QInputDialog::getDouble(this, tr("Please Provide Inside Value"),
2698  tr("Inside Value:"), 1.0, 0, 255, 1, &ok1);
2699  blevel = QInputDialog::getDouble(this, tr("Please Provide the threshold lower level"),
2700  tr("Lower Level:"), minValue, minValue, maxValue, 5, &ok2);
2701  alevel = QInputDialog::getDouble(this, tr("Please Provide the threshold upper level"),
2702  tr("Upper Level:"), maxValue, minValue, maxValue, 5, &ok3);
2703 
2704  if(!ok1 || !ok2 || !ok3)
2705  return;
2706  }
2707 
2708  printInfo("Binary Thresholding Image");
2709  emit working(-1);
2710  if(eightbit)
2711  imageChar = milx::Image<charImageType>::BinaryThresholdImage<charImageType>(imageChar, 0, value, blevel, alevel);
2712  else if(integer)
2713  imageInt = milx::Image<intImageType>::BinaryThresholdImage<intImageType>(imageInt, 0, value, blevel, alevel);
2714 // else if(rgb)
2715 // imageChar = milx::Image<rgbImageType>::TBinaryThresholdImage<charImageType>(imageRGB, 0, value, blevel, alevel);
2716  else
2717  imageChar = milx::Image<floatImageType>::BinaryThresholdImage<charImageType>(imageFloat, 0, value, blevel, alevel);
2718  emit done(-1);
2719 
2720  eightbit = true;
2721  rgb = false;
2722  generateImage();
2723 }
2724 
2725 void milxQtImage::flip(bool xAxis, bool yAxis, bool zAxis, bool aboutOrigin)
2726 {
2727  if(usingVTKImage)
2728  {
2729  printError("Flipping from VTK image not support yet.");
2730  return;
2731  }
2732 
2733  if(!xAxis && !yAxis && !zAxis)
2734  {
2735  QMessageBox msgBoxX, msgBoxY, msgBoxZ, msgBoxOrigin;
2736  msgBoxX.setText("The image will be flipped");
2737  msgBoxX.setInformativeText("Do you want to flip the x-axis?");
2738  msgBoxX.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
2739  msgBoxX.setDefaultButton(QMessageBox::No);
2740  msgBoxY.setText("The image will be flipped");
2741  msgBoxY.setInformativeText("Do you want to flip the y-axis?");
2742  msgBoxY.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
2743  msgBoxY.setDefaultButton(QMessageBox::Yes);
2744  msgBoxZ.setText("The image will be flipped");
2745  msgBoxZ.setInformativeText("Do you want to flip the z-axis?");
2746  msgBoxZ.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
2747  msgBoxZ.setDefaultButton(QMessageBox::No);
2748  msgBoxOrigin.setText("The image will be flipped");
2749  msgBoxOrigin.setInformativeText("Do you want to flip about the origin?");
2750  msgBoxOrigin.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
2751  msgBoxOrigin.setDefaultButton(QMessageBox::Yes);
2752  int retX = msgBoxX.exec();
2753  int retY = msgBoxY.exec();
2754  int retZ = msgBoxZ.exec();
2755  int retOrigin = msgBoxOrigin.exec();
2756 
2757  if(retX == QMessageBox::Yes)
2758  xAxis = true;
2759  if(retY == QMessageBox::Yes)
2760  yAxis = true;
2761  if(retZ == QMessageBox::Yes)
2762  zAxis = true;
2763  if(retOrigin == QMessageBox::Yes)
2764  aboutOrigin = true;
2765  else
2766  aboutOrigin = false;
2767  }
2768 
2769  printInfo("Flipping Image Data");
2770  emit working(-1);
2771  //~ floatImageType::DirectionType direction;
2772  if(eightbit)
2773  {
2774  imageChar = milx::Image<charImageType>::FlipImage(imageChar, xAxis, yAxis, zAxis, aboutOrigin);
2775  //~ direction = imageChar->GetDirection();
2776  //~ cerr << "Flipped Direction: " << imageChar->GetDirection() << endl;
2777  //~ flipped = !flipped;
2778  //~ imageChar->GetDirection()(1,1) *= -1;
2779  }
2780  else if(integer)
2781  {
2782  imageInt = milx::Image<intImageType>::FlipImage(imageInt, xAxis, yAxis, zAxis, aboutOrigin);
2783  //~ direction = imageInt->GetDirection();
2784  //~ cout << "Flipped Direction: " << imageInt->GetDirection() << endl;
2785  //~ flipped = !flipped;
2786  //~ imageInt->GetDirection()(1,1) *= -1;
2787  }
2788  else if(rgb)
2789  {
2790  imageRGB = milx::Image<rgbImageType>::FlipImage(imageRGB, xAxis, yAxis, zAxis, aboutOrigin);
2791  //~ direction = imageRGB->GetDirection();
2792  //~ flipped = !flipped;
2793  //~ imageRGB->GetDirection()(1,1) *= -1;
2794  }
2795  else
2796  {
2797  imageFloat = milx::Image<floatImageType>::FlipImage(imageFloat, xAxis, yAxis, zAxis, aboutOrigin);
2798  //~ direction = imageFloat->GetDirection();
2799  //~ cerr << "Flipped Direction: " << imageFloat->GetDirection() << endl;
2800  //~ flipped = !flipped;
2801  //~ imageFloat->GetDirection()(1,1) *= -1;
2802  }
2803 
2804  //~ imageFloat::DirectionType flipMatrix;
2805  //~ flipMatrix->SetIdentity();
2806 
2807  emit done(-1);
2808 
2809  generateImage();
2810  viewer->GetRenderer()->ResetCamera();
2811 }
2812 
2813 void milxQtImage::surface(const float value)
2814 {
2815  updateData(orientAct->isChecked());
2816 
2817  emit imageToSurface(imageData, value);
2818 }
2819 
2821 {
2822  updateData(orientAct->isChecked());
2823 
2824  emit imageToPolyData(imageData);
2825 }
2826 
2828 {
2829  if(!vectorised)
2830  return;
2831 
2832  updateData(orientAct->isChecked());
2833 
2834  //For display we want to show the vector magnitudes only
2835  printInfo("Loaded image as vector image.");
2836  printDebug("Computing magnitude of field image.");
2838 
2839  generateImage();
2840 }
2841 
2842 void milxQtImage::component(int index)
2843 {
2844  if(!vectorised)
2845  return;
2846 
2847  updateData(orientAct->isChecked());
2848 
2849  bool ok1 = false;
2850  if(index < 0)
2851  {
2852  index = QInputDialog::getInt(this, tr("Please Provide the component index to display"),
2853  tr("Component:"), 0, 0, imageVector->GetNumberOfComponentsPerPixel(), 1, &ok1);
2854  }
2855 
2856  if(!ok1)
2857  return;
2858 
2860 
2861  generateImage();
2862 }
2863 
2865 {
2866  if(!vectorised)
2867  return;
2868 
2869  updateData(orientAct->isChecked());
2870 
2872 }
2873 
2874 void milxQtImage::vectorField(int subsampleFactor, float scaling)
2875 {
2876  if(!vectorised)
2877  return;
2878 
2879  updateData(orientAct->isChecked());
2880 
2881  const size_t components = imageVector->GetNumberOfComponentsPerPixel();
2882  int ret = QMessageBox::No;
2883  if(components > 3)
2884  {
2885  QMessageBox msgBox;
2886  msgBox.setText("Tensor Field?");
2887  msgBox.setInformativeText("Found more than 3 components. Do you wish to compute a tensor field?");
2888  msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
2889  msgBox.setDefaultButton(QMessageBox::Yes);
2890  ret = msgBox.exec();
2891  }
2892 
2893 // if(components == 6 || components == 9)
2894  if(ret == QMessageBox::Yes)
2895  emit imageToTensorField(imageVector, imageFloat, subsampleFactor, scaling);
2896  else
2897  emit imageToVectorField(imageVector, imageFloat, subsampleFactor, scaling);
2898 }
2899 
2901 {
2902  if(!vectorised)
2903  return;
2904 
2905  updateData(orientAct->isChecked());
2906 
2907  const size_t components = imageVector->GetNumberOfComponentsPerPixel();
2908  if(components != 3)
2909  {
2910  printError("Can only integrate vector fields. Number of Components must be 3.");
2911  return;
2912  }
2913 
2914  int extent[6];
2915  viewer->GetImageActor()->GetDisplayExtent(extent);
2916 
2917  if(flipped)
2918  {
2919  int actualExtent[6];
2920  imageData->GetExtent(actualExtent);
2921 
2922  if(extent[3]-extent[2] == 0) //flip y extent
2923  {
2924  extent[2] = actualExtent[3]-extent[2];
2925  extent[3] = actualExtent[3]-extent[3];
2926  }
2927  }
2928 
2930  floatImageType::Pointer sliceFloat = milx::Image<floatImageType>::ExtractSlice<floatImageType>(imageFloat, extent);
2931 
2932  emit imageToStreamLines(imageVector, sliceFloat);
2933 }
2934 
2936 {
2937  if(usingVTKImage)
2938  {
2939  printError("Anisotropic Diffusion from VTK image not support yet.");
2940  return;
2941  }
2942 
2943  //auto set timestep initially
2944  floatImageType::SizeType imgSize;
2945  if(eightbit)
2946  imgSize = imageChar->GetLargestPossibleRegion().GetSize();
2947  else
2948  imgSize = imageFloat->GetLargestPossibleRegion().GetSize();
2949 
2950  size_t maxDimension = 0;
2951  for(size_t k = 0; k < imgSize.GetSizeDimension(); k ++)
2952  {
2953  if(imgSize[k] > maxDimension)
2954  maxDimension = imgSize[k];
2955  }
2956  printDebug("Timestep will be initially the reciprocal of " + QString::number(maxDimension));
2957  float timestep = 2.0/maxDimension;
2958 
2959  bool ok1 = false, ok2 = false;
2960  int iterations = QInputDialog::getInt(this, tr("Please Provide the number of Iterations"),
2961  tr("Iterations:"), 5, 0, 1000, 1, &ok1);
2962  timestep = QInputDialog::getDouble(this, tr("Please Provide the timestep"),
2963  tr("Timestep:"), timestep, 0.0, 100.0, 5, &ok2);
2964 
2965  if(ok1 && ok2)
2966  {
2967  printInfo("Computing Anisotropic Diffusion of Image");
2968  emit working(-1);
2969  if(eightbit)
2970  {
2971  imageFloat = milx::Image<charImageType>::AnisotropicDiffusion<floatImageType>(imageChar, iterations, timestep);
2972  eightbit = false;
2973  }
2974  else if(integer)
2975  {
2976  imageFloat = milx::Image<intImageType>::AnisotropicDiffusion<floatImageType>(imageInt, iterations, timestep);
2977  integer = false;
2978  }
2979 // else if(rgb)
2980 // imageRGB = milx::Image<rgbImageType>::AnisotropicDiffusion(imageRGB, iterations, timestep);
2981  else
2982  imageFloat = milx::Image<floatImageType>::AnisotropicDiffusion<floatImageType>(imageFloat, iterations, timestep);
2983  emit done(-1);
2984 
2985  generateImage();
2986  }
2987 }
2988 
2990 {
2991  if(usingVTKImage)
2992  {
2993  printError("Gaussian Smoothin from VTK image not support yet.");
2994  return;
2995  }
2996 
2997  bool ok1 = false;
2998  float variance = QInputDialog::getDouble(this, tr("Please Provide the variance of the Gaussian to use"),
2999  tr("Variance:"), 0.5, 0.0, 2147483647, 5, &ok1);
3000 
3001  if(ok1)
3002  {
3003  printInfo("Computing Gaussian Smoothing of Image");
3004  emit working(-1);
3005  if(eightbit)
3007  else if(integer)
3009 // else if(rgb)
3010 // imageRGB = milx::Image<rgbImageType>::GaussianSmooth(imageRGB, variance);
3011  else
3013  emit done(-1);
3014 
3015  generateImage();
3016  }
3017 }
3018 
3020 {
3021  if(usingVTKImage)
3022  {
3023  printError("Bilateral Smoothin from VTK image not support yet.");
3024  return;
3025  }
3026 
3027  bool ok1 = false, ok2 = false;
3028  float sigmaRange = QInputDialog::getDouble(this, tr("Please Provide the range sigma to use"),
3029  tr("Range Sigma:"), 0.5, 0.0, 2147483647, 5, &ok1);
3030  float sigmaSpatial = QInputDialog::getDouble(this, tr("Please Provide the domain/spatial sigma to use"),
3031  tr("Domain Sigma:"), 5, 0.0, 2147483647, 5, &ok2);
3032 
3033  if(ok1)
3034  {
3035  printInfo("Computing Bilateral Smoothing of Image");
3036  emit working(-1);
3037  if(eightbit)
3038  imageChar = milx::Image<charImageType>::Bilateral(imageChar, sigmaRange, sigmaSpatial);
3039  else if(integer)
3040  imageInt = milx::Image<intImageType>::Bilateral(imageInt, sigmaRange, sigmaSpatial);
3041  // else if(rgb)
3042  // imageRGB = milx::Image<rgbImageType>::Bilateral(imageRGB, sigmaRange, sigmaSpatial);
3043  else
3044  imageFloat = milx::Image<floatImageType>::Bilateral(imageFloat, sigmaRange, sigmaSpatial);
3045  emit done(-1);
3046 
3047  generateImage();
3048  }
3049 }
3050 
3052 {
3053  if(usingVTKImage)
3054  {
3055  printError("Median from VTK image not support yet.");
3056  return;
3057  }
3058 
3059  bool ok = false;
3060  int radius = QInputDialog::getInt(this, tr("Please Provide the radius to use"),
3061  tr("Radius:"), 5, 0, 1000, 1, &ok);
3062 
3063  if(ok)
3064  {
3065  printInfo("Computing Median of Image");
3066  emit working(-1);
3067  if(eightbit)
3069  else if(integer)
3071 // else if(rgb)
3072 // imageRGB = milx::Image<rgbImageType>::Median(imageRGB, radius);
3073  else
3075  emit done(-1);
3076 
3077  generateImage();
3078  }
3079 }
3080 
3081 void milxQtImage::zeros(const unsigned long xSize, const unsigned long ySize, const unsigned long zSize, milxQtImage *refImage)
3082 {
3083  if(usingVTKImage)
3084  {
3085  printError("Adding of VTK image not support yet.");
3086  return;
3087  }
3088 
3089  printInfo("Blank Image");
3090  emit working(-1);
3091  if(eightbit)
3092  {
3093  charImageType::SizeType blankSize;
3094  blankSize[0] = xSize; // size along X
3095  blankSize[1] = ySize; // size along Y
3096  blankSize[2] = zSize; // size along Z
3097 
3099 
3100  if(refImage)
3101  {
3102  imageChar->SetOrigin(refImage->GetCharImage()->GetOrigin());
3103  imageChar->SetSpacing(refImage->GetCharImage()->GetSpacing());
3104  imageChar->SetDirection(refImage->GetCharImage()->GetDirection());
3105  }
3106  }
3107  else if(integer)
3108  {
3109  intImageType::SizeType blankSize;
3110  blankSize[0] = xSize; // size along X
3111  blankSize[1] = ySize; // size along Y
3112  blankSize[2] = zSize; // size along Z
3113 
3115 
3116  if(refImage)
3117  {
3118  imageInt->SetOrigin(refImage->GetIntImage()->GetOrigin());
3119  imageInt->SetSpacing(refImage->GetIntImage()->GetSpacing());
3120  imageInt->SetDirection(refImage->GetIntImage()->GetDirection());
3121  }
3122  }
3123  else if(rgb)
3124  {
3125  rgbImageType::SizeType blankSize;
3126  blankSize[0] = xSize; // size along X
3127  blankSize[1] = ySize; // size along Y
3128  blankSize[2] = zSize; // size along Z
3129 
3131 
3132  if(refImage)
3133  {
3134  imageRGB->SetOrigin(refImage->GetRGBImage()->GetOrigin());
3135  imageRGB->SetSpacing(refImage->GetRGBImage()->GetSpacing());
3136  imageRGB->SetDirection(refImage->GetRGBImage()->GetDirection());
3137  }
3138  }
3139  else if(!eightbit && !rgb)
3140  {
3141  floatImageType::SizeType blankSize;
3142  blankSize[0] = xSize; // size along X
3143  blankSize[1] = ySize; // size along Y
3144  blankSize[2] = zSize; // size along Z
3145 
3147 
3148  if(refImage)
3149  {
3150  imageFloat->SetOrigin(refImage->GetFloatImage()->GetOrigin());
3151  imageFloat->SetSpacing(refImage->GetFloatImage()->GetSpacing());
3152  imageFloat->SetDirection(refImage->GetFloatImage()->GetDirection());
3153  }
3154  }
3155  else
3156  printError("Blank image of different types not supported.");
3157  emit done(-1);
3158 
3159  generateImage();
3160 }
3161 
3162 void milxQtImage::resize(double outputSpacing)
3163 {
3164  floatImageType::SpacingType newSpacing;
3165  floatImageType::SizeType newSize;
3166  floatImageType::PointType newOrigin;
3167  floatImageType::DirectionType newDirection;
3168  if(eightbit)
3169  {
3170  newSpacing = imageChar->GetSpacing();
3171  newSize = imageChar->GetLargestPossibleRegion().GetSize();
3172  newOrigin = imageChar->GetOrigin();
3173  newDirection = imageChar->GetDirection();
3174  }
3175  else if(integer)
3176  {
3177  newSpacing = imageInt->GetSpacing();
3178  newSize = imageInt->GetLargestPossibleRegion().GetSize();
3179  newOrigin = imageInt->GetOrigin();
3180  newDirection = imageInt->GetDirection();
3181  }
3182  else if(!eightbit && !rgb && !vectorised)
3183  {
3184  newSpacing = imageFloat->GetSpacing();
3185  newSize = imageFloat->GetLargestPossibleRegion().GetSize();
3186  newOrigin = imageFloat->GetOrigin();
3187  newDirection = imageFloat->GetDirection();
3188  }
3189  else
3190  {
3191  printError("Resize image of different types not supported.");
3192  return;
3193  }
3194 
3195  bool ok1 = false;
3196  if(outputSpacing == 0.0) //none provided
3197  {
3198  outputSpacing = QInputDialog::getDouble(this, tr("Please Provide the new isotropic spacing"),
3199  tr("Isotropic Spacing:"), 0.5, 0.001, 10, 3, &ok1);
3200 
3201  if(!ok1)
3202  return;
3203  }
3204 
3205  printInfo("Resizing Image based on new spacing");
3206  emit working(-1);
3207  floatImageType::SpacingType scaleFactor;
3208  scaleFactor[0] = newSpacing[0]/outputSpacing;
3209  scaleFactor[1] = newSpacing[1]/outputSpacing;
3210  scaleFactor[2] = newSpacing[2]/outputSpacing;
3211  newSpacing.Fill(outputSpacing);
3212  newSize[0] = static_cast<unsigned>(newSize[0]*scaleFactor[0]+0.5); // size along X
3213  newSize[1] = static_cast<unsigned>(newSize[1]*scaleFactor[1]+0.5); // size along Y
3214  newSize[2] = static_cast<unsigned>(newSize[2]*scaleFactor[2]+0.5); // size along Z
3215  std::cout << "Rescaling image by [" << scaleFactor[0] << ", " << scaleFactor[1] << ", " << scaleFactor[2] << "]" << std::endl;
3216  std::cout << "Resampling image to [" << newSize[0] << ", " << newSize[1] << ", " << newSize[2] << "]" << std::endl;
3217 
3218  if(eightbit)
3219  imageChar = milx::Image<charImageType>::ResizeImage(imageChar, newSize, newSpacing, newOrigin, newDirection);
3220  else if(integer)
3221  imageInt = milx::Image<intImageType>::ResizeImage(imageInt, newSize, newSpacing, newOrigin, newDirection);
3222  else if(!eightbit && !rgb && !vectorised)
3223  imageFloat = milx::Image<floatImageType>::ResizeImage(imageFloat, newSize, newSpacing, newOrigin, newDirection);
3224  emit done(-1);
3225 
3226  generateImage();
3227 }
3228 
3229 void milxQtImage::resize(const unsigned long xSize, const unsigned long ySize, const unsigned long zSize, milxQtImage *refImage)
3230 {
3231  if(usingVTKImage)
3232  {
3233  printError("Adding of VTK image not support yet.");
3234  return;
3235  }
3236 
3237  printInfo("Resizing Image");
3238  emit working(-1);
3239  if(eightbit)
3240  {
3241  charImageType::SizeType blankSize;
3242  blankSize[0] = xSize; // size along X
3243  blankSize[1] = ySize; // size along Y
3244  blankSize[2] = zSize; // size along Z
3245 
3246  if(refImage)
3247  imageChar = milx::Image<charImageType>::ResizeImage(imageChar, blankSize, refImage->GetCharImage()->GetSpacing(), refImage->GetCharImage()->GetOrigin(), refImage->GetCharImage()->GetDirection());
3248  else
3249  imageChar = milx::Image<charImageType>::ResizeImage(imageChar, blankSize, imageChar->GetSpacing(), imageChar->GetOrigin(), imageChar->GetDirection());
3250  }
3251  else if(integer)
3252  {
3253  intImageType::SizeType blankSize;
3254  blankSize[0] = xSize; // size along X
3255  blankSize[1] = ySize; // size along Y
3256  blankSize[2] = zSize; // size along Z
3257 
3258  if(refImage)
3259  imageInt = milx::Image<intImageType>::ResizeImage(imageInt, blankSize, refImage->GetIntImage()->GetSpacing(), refImage->GetIntImage()->GetOrigin(), refImage->GetIntImage()->GetDirection());
3260  else
3261  imageInt = milx::Image<intImageType>::ResizeImage(imageInt, blankSize, imageInt->GetSpacing(), imageInt->GetOrigin(), imageInt->GetDirection());
3262  }
3263 // else if(rgb)
3264 // {
3265 // rgbImageType::SizeType blankSize;
3266 // blankSize[0] = xSize; // size along X
3267 // blankSize[1] = ySize; // size along Y
3268 // blankSize[2] = zSize; // size along Z
3269 //
3270 // if(refImage)
3271 // imageRGB = milx::Image<rgbImageType>::ResizeImage(imageRGB, blankSize, refImage->GetRGBImage()->GetSpacing());
3272 // else
3273 // imageRGB = milx::Image<rgbImageType>::ResizeImage(imageRGB, blankSize, imageRGB->GetSpacing());
3274 // }
3275  else if(!eightbit && !rgb && !vectorised)
3276  {
3277  floatImageType::SizeType blankSize;
3278  blankSize[0] = xSize; // size along X
3279  blankSize[1] = ySize; // size along Y
3280  blankSize[2] = zSize; // size along Z
3281 
3282  if(refImage)
3283  imageFloat = milx::Image<floatImageType>::ResizeImage(imageFloat, blankSize, refImage->GetFloatImage()->GetSpacing(), refImage->GetCharImage()->GetOrigin(), refImage->GetCharImage()->GetDirection());
3284  else
3285  imageFloat = milx::Image<floatImageType>::ResizeImage(imageFloat, blankSize, imageFloat->GetSpacing(), imageFloat->GetOrigin(), imageFloat->GetDirection());
3286  }
3287  else
3288  printError("Blank image of different types not supported.");
3289  emit done(-1);
3290 
3291  generateImage();
3292 }
3293 
3295 {
3296  if(usingVTKImage)
3297  {
3298  printError("Adding of VTK image not support yet.");
3299  return;
3300  }
3301 
3302  printInfo("Adding Image");
3303  emit working(-1);
3304  if(eightbit && img->is8BitImage())
3306  else if(integer && img->is32BitImage())
3308  else if(rgb && img->isRGBImage())
3310  else if(vectorised && img->isVectorImage())
3311  {
3313  magnitude();
3314  }
3315  else if(!eightbit && !rgb && img->isFloatingPointImage())
3317  else
3318  printError("Adding images of different types not supported.");
3319  emit done(-1);
3320 
3321  generateImage();
3322 }
3323 
3324 void milxQtImage::add(QString filename)
3325 {
3326  if(usingVTKImage)
3327  {
3328  printError("Adding from VTK image not support yet.");
3329  return;
3330  }
3331 
3332  if(filename.isEmpty())
3333  filename = getOpenFilename();
3334 
3335  if(filename.isEmpty())
3336  return;
3337 
3338  QPointer<milxQtImage> imageToSubtract = new milxQtImage;
3339  QPointer<milxQtFile> reader = new milxQtFile;
3340  bool success = reader->openImage(filename, imageToSubtract);
3341 
3342  if(!success)
3343  return;
3344 
3345  add(imageToSubtract);
3346 }
3347 
3349 {
3350  if(usingVTKImage)
3351  {
3352  printError("Subtracting of VTK image not support yet.");
3353  return;
3354  }
3355 
3356  printInfo("Subtracting Image");
3357  emit working(-1);
3358  if(eightbit && img->is8BitImage())
3360  else if(integer && img->is32BitImage())
3362  else if(rgb && img->isRGBImage())
3364  else if(vectorised && img->isVectorImage())
3365  {
3367  magnitude();
3368  }
3369  else if(!eightbit && !rgb && img->isFloatingPointImage())
3371  else
3372  printError("Subtracting images of different types not supported.");
3373  emit done(-1);
3374 
3375  generateImage();
3376 }
3377 
3378 void milxQtImage::subtract(QString filename)
3379 {
3380  if(usingVTKImage)
3381  {
3382  printError("Subtracting from VTK image not support yet.");
3383  return;
3384  }
3385 
3386  if(filename.isEmpty())
3387  filename = getOpenFilename();
3388 
3389  if(filename.isEmpty())
3390  return;
3391 
3392  QPointer<milxQtImage> imageToSubtract = new milxQtImage;
3393  QPointer<milxQtFile> reader = new milxQtFile;
3394  bool success = reader->openImage(filename, imageToSubtract);
3395 
3396  if(!success)
3397  return;
3398 
3399  subtract(imageToSubtract);
3400 }
3401 
3403 {
3404  if (usingVTKImage)
3405  {
3406  printError("Multiplying of VTK image not support yet.");
3407  return;
3408  }
3409 
3410  printInfo("Multiplying Image");
3411  emit working(-1);
3412  if (eightbit && img->is8BitImage())
3414  else if (integer && img->is32BitImage())
3416  else if (!eightbit && !rgb && img->isFloatingPointImage())
3418  else
3419  printError("Multiplying images of Vector, RGB or different types not supported.");
3420  emit done(-1);
3421 
3422  generateImage();
3423 }
3424 
3425 void milxQtImage::multiply(QString filename)
3426 {
3427  if (usingVTKImage)
3428  {
3429  printError("Multiplying from VTK image not support yet.");
3430  return;
3431  }
3432 
3433  if (filename.isEmpty())
3434  filename = getOpenFilename();
3435 
3436  if (filename.isEmpty())
3437  return;
3438 
3439  QPointer<milxQtImage> imageToMultiply = new milxQtImage;
3440  QPointer<milxQtFile> reader = new milxQtFile;
3441  bool success = reader->openImage(filename, imageToMultiply);
3442 
3443  if (!success)
3444  return;
3445 
3446  multiply(imageToMultiply);
3447 }
3448 
3449 void milxQtImage::scale(float scaling)
3450 {
3451  if(usingVTKImage)
3452  {
3453  printError("Scaling of VTK image not support yet.");
3454  return;
3455  }
3456 
3457  printInfo("Scaling Image");
3458  emit working(-1);
3459  if(eightbit)
3460  {
3461  imageFloat = milx::Image<charImageType>::ScaleImage<floatImageType>(imageChar, scaling);
3462  eightbit = false;
3463  }
3464  else if(integer)
3465  {
3466  imageFloat = milx::Image<intImageType>::ScaleImage<floatImageType>(imageInt, scaling);
3467  integer = false;
3468  }
3469 // else if(rgb)
3470 // imageRGB = milx::Image<rgbImageType>::ScaleImage(imageRGB);
3471  else if(vectorised)
3472  {
3473  imageVector = milx::Image<vectorImageType>::ScaleVectorImage(imageVector, scaling, imageVector->GetNumberOfComponentsPerPixel());
3474  magnitude();
3475  }
3476  else
3478  emit done(-1);
3479 
3480  generateImage();
3481 }
3482 
3484 {
3485  if(usingVTKImage)
3486  {
3487  printError("Convolving of VTK images not support yet.");
3488  return;
3489  }
3490 #if (ITK_REVIEW || ITK_VERSION_MAJOR > 3) //Review only members
3491  printInfo("Convolving Images");
3492  emit working(-1);
3493  if(eightbit && img->is8BitImage())
3495  else if(integer && img->is32BitImage())
3497 // else if(rgb && img->isRGBImage())
3498 // imageRGB = milx::Image<rgbImageType>::ConvolveImages(imageRGB, img->GetRGBImage());
3499 // else if(vectorised && img->isVectorImage())
3500 // {
3501 // imageVector = milx::Image<vectorImageType>::ConvolveImages(imageVector, img->GetVectorImage());
3502 // magnitude();
3503 // }
3504  else if(!eightbit && !rgb && img->isFloatingPointImage())
3506  else
3507  printError("Convolving images of different types not supported.");
3508  emit done(-1);
3509 
3510  generateImage();
3511 #endif
3512 }
3513 
3515 {
3516  imageData->DeepCopy( butterWorthHighPass(imageData) );
3517 
3518  typedef itk::VTKImageToImageFilter<floatImageType> ConvertImageType;
3519 
3520  ConvertImageType::Pointer convertFilter = ConvertImageType::New();
3521  convertFilter->SetInput(imageData);
3522  convertFilter->AddObserver(itk::ProgressEvent(), observeProgress);
3523  try
3524  {
3525  convertFilter->Update();
3526  }
3527  catch (itk::ExceptionObject & ex )
3528  {
3529  printError("Failed Converting VTK Image to ITK Image");
3530  printError(ex.GetDescription());
3531  }
3532 
3533  imageFloat = milx::Image<floatImageType>::DuplicateImage(convertFilter->GetOutput());
3534  flipped = false;
3535 
3536  generateImage();
3537 }
3538 
3539 void milxQtImage::interpolateDisplay(const bool quietly)
3540 {
3541  if(loaded && viewerSetup)
3542  {
3543  if(viewer->GetImageActor()->GetInterpolate())
3544  {
3545  printInfo("Disabling Interpolation");
3546  viewer->GetImageActor()->InterpolateOff();
3547  interpolateAct->setChecked(false);
3548  }
3549  else
3550  {
3551  printInfo("Enabling Interpolation");
3552  viewer->GetImageActor()->InterpolateOn();
3553  interpolateAct->setChecked(true);
3554  }
3555 
3557  if(!quietly)
3558  emit modified(this);
3559  }
3560 }
3561 
3562 void milxQtImage::applyOrientDisplay(const bool quietly)
3563 {
3564  if(loaded && viewerSetup)
3565  {
3566  generateImage();
3567  viewer->GetRenderer()->ResetCamera();
3568 
3569  emit milxQtRenderWindow::modified(GetImageActor()); //caution: crash without it
3570  if(!quietly)
3571  emit modified(this);
3572  }
3573 }
3574 
3576 {
3577  if(orientMode == RADIOLOGICAL)
3578  viewer->NeurologicalViewOff();
3579  if(orientMode == NEUROLOGICAL)
3580  viewer->NeurologicalViewOn();
3581 
3583 }
3584 
3585 void milxQtImage::enableScale(QString title, const bool quiet, double minRange, double maxRange, int noOfLabels)
3586 {
3588  milxQtRenderWindow::scale = vtkSmartPointer<vtkScalarBarActor>::New();
3590  milxQtRenderWindow::scalarBar = vtkSmartPointer<vtkScalarBarWidget>::New();
3591 
3593  QMessageBox msgBox;
3594  msgBox.setText("An auto adjusted bar is about to be created");
3595  msgBox.setInformativeText("Would you like to customise the bar?");
3596  msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
3597  msgBox.setDefaultButton(QMessageBox::No);
3598 
3599  int ret = QMessageBox::No;
3600  if(!quiet)
3601  ret = msgBox.exec();
3602 
3603  const float barWidth = 0.1, barHeight = 0.7;
3604 
3605  double range[2];
3606  imageData->GetScalarRange(range);
3607 
3608  lookupTable->SetRange(range[0], range[1]);
3609 
3610  vtkSmartPointer<vtkLogLookupTable> logLookupTable;
3612  {
3613  printInfo("Detected log scale.");
3614  logLookupTable = vtkSmartPointer<vtkLogLookupTable>::New();
3615  logLookupTable->DeepCopy(vtkLookupTable::SafeDownCast(lookupTable));
3616  }
3617 
3618  if(ret == QMessageBox::Yes && !quiet)
3619  {
3620  bool ok1 = false, ok2 = false;
3621 
3622  noOfLabels = QInputDialog::getInt(this, tr("How many labels to show"),
3623  tr("Labels:"), noOfLabels, 0, 99, 1, &ok1);
3624  title = QInputDialog::getText(this, tr("Title of Bar"),
3625  tr("Title:"), QLineEdit::Normal,
3626  title, &ok2);
3627 
3628  if(!ok1 || !ok2)
3629  return;
3630 
3632  milxQtRenderWindow::scale->SetLookupTable(logLookupTable);
3633  else
3634  milxQtRenderWindow::scale->SetLookupTable(lookupTable);
3635  milxQtRenderWindow::scale->SetNumberOfLabels(noOfLabels);
3636 
3637  vtkImageMapToWindowLevelColors *filterColorsOverlay = viewer->GetWindowLevel();
3638  filterColorsOverlay->SetLookupTable(lookupTable);
3639  filterColorsOverlay->PassAlphaToOutputOn();
3640  filterColorsOverlay->Update();
3641 
3642  milxQtRenderWindow::customScalarBar = true;
3643  }
3644  else if(quiet && minRange != maxRange)
3645  {
3646  printInfo("Using custom scalar range for scalars.");
3648  milxQtRenderWindow::scale->SetLookupTable(logLookupTable);
3649  else
3650  milxQtRenderWindow::scale->SetLookupTable(lookupTable);
3651  milxQtRenderWindow::scale->SetNumberOfLabels(noOfLabels);
3652 
3653  vtkImageMapToWindowLevelColors *filterColorsOverlay = viewer->GetWindowLevel();
3654  filterColorsOverlay->SetLookupTable(lookupTable);
3655  filterColorsOverlay->PassAlphaToOutputOn();
3656  filterColorsOverlay->Update();
3657 
3658  milxQtRenderWindow::customScalarBar = true;
3659  }
3660  else
3661  {
3662  printInfo("Using scalar range from image.");
3664  milxQtRenderWindow::scale->SetLookupTable(logLookupTable);
3665  else
3666  milxQtRenderWindow::scale->SetLookupTable(lookupTable);
3667  milxQtRenderWindow::scale->SetNumberOfLabels(3);
3668 
3669  vtkImageMapToWindowLevelColors *filterColorsOverlay = viewer->GetWindowLevel();
3670  filterColorsOverlay->SetLookupTable(lookupTable);
3671  filterColorsOverlay->PassAlphaToOutputOn();
3672  filterColorsOverlay->Update();
3673 
3674  milxQtRenderWindow::customScalarBar = false;
3675  }
3676 
3677  milxQtRenderWindow::scale->SetTitle(title.toStdString().c_str());
3678  milxQtRenderWindow::scale->GetLabelTextProperty()->SetFontFamilyToArial();
3679  milxQtRenderWindow::scale->GetLabelTextProperty()->SetFontSize(8);
3680  milxQtRenderWindow::scale->GetPositionCoordinate()->SetCoordinateSystemToNormalizedViewport();
3681  milxQtRenderWindow::scale->GetPositionCoordinate()->SetValue(.2,.05);
3682  milxQtRenderWindow::scale->SetWidth( barWidth );
3683  milxQtRenderWindow::scale->SetHeight( barHeight );
3684  milxQtRenderWindow::scale->SetPosition( 0.99 - barWidth, 0.1 );
3685  milxQtRenderWindow::scale->SetLabelFormat("%-#6.3f");
3686  milxQtRenderWindow::scale->GetTitleTextProperty()->SetFontFamilyToArial();
3687  milxQtRenderWindow::scale->GetTitleTextProperty()->SetFontSize(8);
3688  milxQtRenderWindow::scale->GetLabelTextProperty()->SetJustificationToCentered();
3689 
3690  if(milxQtRenderWindow::backgroundAct->isChecked())
3691  {
3692  milxQtRenderWindow::scale->GetLabelTextProperty()->SetColor(0, 0, 0);
3693  milxQtRenderWindow::scale->GetTitleTextProperty()->SetColor(0, 0, 0);
3694  }
3695 
3696  //Add scale to scale widget
3697  milxQtRenderWindow::scalarBar->SetInteractor(QVTKWidget::GetInteractor());
3699  milxQtRenderWindow::scalarBar->EnabledOn();
3700 
3702  milxQtRenderWindow::scaleAct->setChecked(true);
3703 }
3704 
3705 void milxQtImage::scaleDisplay(const bool forceDisplay)
3706 {
3707  if(!viewerSetup)
3708  {
3709  printError("Image Data not generated. Ignoring scalar bar operation.");
3710  return;
3711  }
3712 
3713  if(!lookupTable)
3714  {
3715  QMessageBox msgBox;
3716  msgBox.setText("Currently not using a colour map");
3717  msgBox.setInformativeText("Please choose a colour map first");
3718  msgBox.setStandardButtons(QMessageBox::Ok);
3719  msgBox.setIcon(QMessageBox::Warning);
3720  msgBox.exec();
3721  scaleAct->setChecked(false);
3722  return;
3723  }
3724 
3725  if(scaleAct->isChecked() || forceDisplay)
3726  enableScale(imageData->GetPointData()->GetScalars()->GetName(), forceDisplay);
3727  else
3728  disableScale();
3729 
3730  Render();
3731 }
3732 
3733 #if VTK_MAJOR_VERSION > 5
3734 void milxQtImage::resliceMode(const bool quietly)
3735 {
3736  if(resliceAct->isChecked())
3737  enableResliceMode();
3738  else
3739  disableResliceMode();
3740 
3741  if(!quietly)
3742  emit modified(this);
3743 }
3744 #endif
3745 
3746 void milxQtImage::showCrosshair(const bool quietly)
3747 {
3748  if(cursorAct->isChecked())
3749  enableCrosshair();
3750  else
3751  disableCrosshair();
3752 
3753  if(!quietly)
3754  emit modified(this);
3755 }
3756 
3757 void milxQtImage::setView(int viewMode)
3758 {
3759  if(!volume)
3760  {
3761  printDebug("Volume is 2D. Not changing view to " + QString::number(viewMode));
3762  viewToXYPlane();
3763  return;
3764  }
3765 
3766  milxQtRenderWindow::setView(viewMode);
3767 }
3768 
3770 {
3771  if(viewerSetup)
3772  {
3773  viewer->SetSliceOrientationToXY();
3774  currentView = AXIAL;
3775  }
3776 }
3777 
3779 {
3780  if(viewerSetup)
3781  {
3782  viewer->SetSliceOrientationToXZ();
3783  currentView = CORONAL;
3784  }
3785 }
3786 
3788 {
3789  if(viewerSetup)
3790  {
3791  viewer->SetSliceOrientationToYZ();
3792  currentView = SAGITTAL;
3793  }
3794 }
3795 
3797 {
3798  double range[2];
3799  imageData->GetScalarRange(range);
3800 
3801  lookupTable->SetRange(range[0], range[1]);
3802 
3803  vtkImageMapToWindowLevelColors *filterColorsOverlay = viewer->GetWindowLevel();
3804  filterColorsOverlay->SetLookupTable(lookupTable);
3805  filterColorsOverlay->PassAlphaToOutputOn();
3806  filterColorsOverlay->Update();
3807 
3808  scaleDisplay();
3809 }
3810 
3811 void milxQtImage::histogram(int bins, float belowValue, float aboveValue, bool plotHistogram)
3812 {
3813  printInfo("Computing Histogram of Image");
3814  updateData(orientAct->isChecked());
3815 
3816  double range[2];
3817  imageData->GetScalarRange(range);
3818 
3819  int ret = QMessageBox::No;
3820  if(plotHistogram)
3821  {
3823  bool ok1 = false, ok2 = false, ok3 = false;
3824  bins = QInputDialog::getInt(this, tr("Please Provide the number of bins"),
3825  tr("Number of Bins:"), 256, 2, 16384, 1, &ok1);
3826  belowValue = QInputDialog::getDouble(this, tr("Please Provide the lower level"),
3827  tr("Lower Level:"), range[0], -2147483647, 2147483647, 1, &ok2);
3828  aboveValue = QInputDialog::getDouble(this, tr("Please Provide the upper level"),
3829  tr("Upper Level:"), range[1], belowValue, 2147483647, 1, &ok3);
3830 
3831  if(!ok1 || !ok2 || !ok3)
3832  return;
3833 
3834  QMessageBox msgBox;
3835  msgBox.setText("Ignore Zero Values in Statistics?");
3836  msgBox.setInformativeText("Do you wish to ignore zero values in Max/Min/Sum/Mean statistics?");
3837  msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
3838  msgBox.setDefaultButton(QMessageBox::No);
3839  ret = msgBox.exec();
3840  }
3841  else
3842  {
3843  belowValue = range[0];
3844  aboveValue = range[1];
3845  }
3846 
3847  double binSpacing = (aboveValue-belowValue)/bins;
3848  printInfo("Bin Spacing: " + QString::number(binSpacing));
3849  hist = vtkSmartPointer<vtkImageAccumulate>::New();
3850  #if VTK_MAJOR_VERSION <= 5
3851  hist->SetInput(imageData);
3852  #else
3853  hist->SetInputData(imageData);
3854  #endif
3855  //Only set first values as single component image assumed
3856  hist->SetComponentExtent(0, bins-1, 0, 0, 0, 0); //bins
3857  hist->SetComponentOrigin(belowValue, 0, 0); //offset
3858  hist->SetComponentSpacing(binSpacing, 0, 0); //spacing
3859  if(ret == QMessageBox::Yes)
3860  {
3861  printWarning("Ignore zero values in summary statistics");
3862  hist->IgnoreZeroOn();
3863  }
3864  else
3865  hist->IgnoreZeroOff();
3867  hist->Update();
3868  hist->Print(cout);
3869 
3870  const coordinate meanTuple( hist->GetMean() );
3871  const coordinate stddevTuple(hist->GetStandardDeviation());
3872  const coordinate minTuple( hist->GetMin() );
3873  const coordinate maxTuple( hist->GetMax() );
3874  if(imageData->GetNumberOfScalarComponents() == 1)
3875  {
3876  meanValue = meanTuple[0];
3877  stddevValue = stddevTuple[0];
3878  minValue = minTuple[0];
3879  maxValue = maxTuple[0];
3880  }
3881  else
3882  {
3883  meanValue = meanTuple.mean();
3884  stddevValue = stddevTuple.mean();
3885  minValue = minTuple.mean();
3886  maxValue = maxTuple.mean();
3887  }
3888  printInfo("Mean of the data: " + QString::number(meanValue));
3889  printInfo("Std Deviation of the data: " + QString::number(stddevValue));
3890  printInfo("Min/Max of the data: " + QString::number(minValue) + "/" + QString::number(maxValue));
3891 
3892  if(plotHistogram)
3893  {
3894  #if VTK_MAJOR_VERSION <= 5
3895  hist->GetOutput()->Update();
3896  #endif
3897 
3898  vtkSmartPointer<vtkFloatArray> binsArray = vtkSmartPointer<vtkFloatArray>::New();
3899  binsArray->SetNumberOfComponents(1);
3900  binsArray->SetNumberOfTuples(bins);
3901  binsArray->SetName("Greyscale Bins");
3902  vtkSmartPointer<vtkIntArray> freqArray = vtkSmartPointer<vtkIntArray>::New();
3903  freqArray->SetNumberOfComponents(1);
3904  freqArray->SetNumberOfTuples(bins);
3905  freqArray->SetName("Frequency");
3906  freqArray->FillComponent(0, 0);
3907  int k = 0;
3908  for(float j = belowValue; j < aboveValue; j += binSpacing, k ++)
3909  {
3910  binsArray->SetTuple1(k, j);
3911  freqArray->SetTuple1(k, hist->GetOutput()->GetPointData()->GetScalars()->GetTuple1(k));
3912  }
3913 
3914  vtkSmartPointer<vtkTable> table = vtkSmartPointer<vtkTable>::New();
3915  table->AddColumn(binsArray);
3916  table->AddColumn(freqArray);
3917 
3918  emit tableToPlot(table, "Histogram");
3919  }
3920 }
3921 
3923 {
3924  int extent[6];
3925  viewer->GetImageActor()->GetDisplayExtent(extent);
3926  printDebug("Currently Display Extent: [" +
3927  QString::number(extent[0]) + ", " + QString::number(extent[1]) + ", " +
3928  QString::number(extent[2]) + ", " + QString::number(extent[3]) + ", " +
3929  QString::number(extent[4]) + ", " + QString::number(extent[5]) + "]");
3930 
3931  vtkSmartPointer<vtkImageData> img;
3932  if(flipped)
3933  {
3934  vtkSmartPointer<vtkImageFlip> imageReorient = vtkSmartPointer<vtkImageFlip>::New();
3935  #if VTK_MAJOR_VERSION <= 5
3936  imageReorient->SetInput(imageData);
3937  #else
3938  imageReorient->SetInputData(imageData);
3939  #endif
3940  imageReorient->SetFilteredAxis(1);
3941  imageReorient->FlipAboutOriginOn();
3942  linkProgressEventOf(imageReorient);
3943  imageReorient->Update();
3944  img = imageReorient->GetOutput();
3945 
3946  int actualExtent[6];
3947  imageData->GetExtent(actualExtent);
3948 
3949  if(extent[3]-extent[2] == 0) //flip y extent
3950  {
3951  extent[2] = actualExtent[3]-extent[2];
3952  extent[3] = actualExtent[3]-extent[3];
3953  }
3954  }
3955  else
3956  img = imageData;
3957 
3958  //Pull out the current slice being viewed
3959  vtkSmartPointer<vtkImageReslice> slice = vtkSmartPointer<vtkImageReslice>::New();
3960  slice->SetOutputExtent(extent);
3961  #if VTK_MAJOR_VERSION <= 5
3962  slice->SetInput(img);
3963  #else
3964  slice->SetInputData(img);
3965  #endif
3966  slice->SetOutputSpacing(img->GetSpacing()); //needed
3967  slice->SetOutputOrigin(img->GetOrigin()); //needed
3968  linkProgressEventOf(slice);
3969  slice->Update();
3970 
3971  //check slice orientation
3972  const int zAxis = viewer->GetSliceOrientation();
3973  int axisToDisplace = 2; //z
3974  if(zAxis == vtkImageViewer2::SLICE_ORIENTATION_XZ) //y
3975  axisToDisplace = 1;
3976  else if(zAxis == vtkImageViewer2::SLICE_ORIENTATION_YZ) //x
3977  axisToDisplace = 0;
3978 
3979  emit imageToPlot(slice->GetOutput(), axisToDisplace);
3980 }
3981 
3983 {
3984  viewer->UpdateCursor();
3985  viewer->GetInteractorStyle()->InvokeEvent(vtkCommand::ResetWindowLevelEvent); //Reset window level as if pressing 'r'
3986  viewer->Render();
3988 }
3989 
3991 {
3992  updateData(orientAct->isChecked());
3993  viewer->GetRenderer()->ResetCamera(); //Reset window view as if pressing 'Shift+r'
3994  refresh();
3995 }
3996 
3997 void milxQtImage::createMenu(QMenu *menu)
3998 {
3999  if(!menu)
4000  return;
4001 
4002  menu->clear();
4003  menu->addMenu(basicContextMenu());
4004 
4005  if(!extActionsToAdd.empty())
4006  menu->addSeparator()->setText(tr("Extensions"));
4007  foreach(QAction *currAct, extActionsToAdd)
4008  {
4009  menu->addAction(currAct);
4010  }
4011 
4012  menu->addSeparator();
4013  menu->addAction(milxQtRenderWindow::scaleAct);
4014  menu->addMenu(milxQtRenderWindow::contourMenu);
4016 
4017  menu->addSeparator();
4018  foreach(QAction *currAct, milxQtWindow::actionsToAppend)
4019  {
4020  menu->addAction(currAct);
4021  }
4022  foreach(QMenu *currMenu, milxQtWindow::menusToAppend)
4023  {
4024  menu->addMenu(currMenu);
4025  }
4026  menu->addAction(milxQtRenderWindow::refreshAct);
4027  menu->addAction(milxQtRenderWindow::resetAct);
4028 
4029  //disabling
4030  milxQtRenderWindow::contourPolyDataAct->setDisabled(!contourAct->isChecked());
4031  milxQtRenderWindow::contourNodePolyDataAct->setDisabled(!contourAct->isChecked());
4032  milxQtRenderWindow::contourInitAct->setDisabled(!contourAct->isChecked());
4033 }
4034 
4036 {
4037  milxQtImage *currentImgWindow = qobject_cast<milxQtImage *>( windowActionGroup->checkedAction()->parent() );
4038 
4039  if(currentImgWindow == 0) //Not image so...
4040  {
4041  milxQtRenderWindow *currentWindow = qobject_cast<milxQtRenderWindow *>( windowActionGroup->checkedAction()->parent() );
4042 
4043  if(currentWindow == 0)
4044  {
4045  printError("Error in determining parent of action");
4046  return;
4047  }
4048 
4049  vtkActorCollection *actors = currentWindow->GetActors();
4050  printDebug("Checked Window is: " + currentWindow->strippedNamePrefix());
4051 
4052  size_t n = actors->GetNumberOfItems();
4053 
4054  actors->InitTraversal();
4055  for(size_t j = 0; j < n; j ++)
4056  {
4057  printDebug("Adding Generic Actor into scene.");
4058  vtkActor *currentActor = actors->GetNextItem();
4059 
4060  //Check if already in view
4061  foreach(ModelActorItem item, modelActors)
4062  {
4063  if(currentActor == item.parentActor)
4064  return; //Dont need to do anything.
4065  }
4066 
4067  ModelActorItem item;
4068  item.parentActor = currentActor;
4069  item.modelActor = vtkSmartPointer<vtkActor>::New();
4070  item.modelActor->ShallowCopy(currentActor);
4071  item.modelActor->GetProperty()->LightingOn();
4072  //Fixed discoloration caused by transforming the actor.
4073  //http://vtk.1045678.n5.nabble.com/diffuse-lighting-after-scaling-with-negative-values-td1240907.html
4074  milxQtRenderWindow::lightingAct->setChecked(false); //Disable two-sided lighting to display scalars properly on meshes
4076  item.modelActor->Modified();
4077 
4078  Connector->Connect(currentActor,
4079  vtkCommand::ModifiedEvent,
4080  this,
4081  SLOT( updateModelActor(vtkObject*, unsigned long, void*, void*, vtkCommand*) ),
4082  NULL, 1.0); //High Priority
4083 
4084  if(transformMatrix)
4085  {
4086  printDebug("Transforming Actor to Image Space");
4087  item.modelActor->SetUserMatrix( transformMatrix );
4088  //Fix the actor properties, as they get reset to default ones. \todo fix this
4089  }
4090  modelActors.append(item);
4091  AddActor(item.modelActor);
4092 
4093  qApp->processEvents();
4094  }
4095  }
4096 
4097  Render();
4098 }
4099 
4100 void milxQtImage::updateModelActor(vtkObject * obj, unsigned long, void * client_data, void *, vtkCommand * command)
4101 {
4102  vtkSmartPointer<vtkActor> actor = vtkActor::SafeDownCast(obj);
4103 
4104  //Update the actor which is somehere in list
4105  foreach(ModelActorItem item, modelActors)
4106  {
4107  if(actor == item.parentActor)
4108  {
4109  item.modelActor->ShallowCopy(actor);
4110  item.modelActor->Modified();
4111 
4112  break; //Only one of each is allowed
4113  }
4114  }
4115 
4116  Render();
4117 }
4118 
4119 void milxQtImage::updateDisplay(QPointer<milxQtImage> img)
4120 {
4121  printDebug("Updating dependent display");
4122  setDisplayData(img);
4123  generateImage(true);
4124 
4125  interpolateAct->setChecked(img->isInterpolated());
4126  if(img->isInterpolated() ^ isInterpolated()) //XOR
4127  interpolateDisplay(true);
4128 
4129  if(img->isOriented() ^ isOriented()) //XOR
4130  {
4131  orientAct->setChecked(img->isOriented());
4132  applyOrientDisplay(true);
4133  }
4134 
4135  if(img->isCrosshair() ^ isCrosshair())
4136  {
4137  cursorAct->setChecked(img->isCrosshair());
4138  showCrosshair(true);
4139  }
4140 
4141  Render();
4142 }
4143 
4145 {
4146  //Filters
4147  operateMenu = new QMenu(this);
4148  operateMenu->setTitle(QApplication::translate("Image", "Operations", 0, QApplication::UnicodeUTF8));
4149  rescaleAct = new QAction(this);
4150  rescaleAct->setText(QApplication::translate("Image", "Rescale Intensities", 0, QApplication::UnicodeUTF8));
4151  rescaleAct->setShortcut(tr("Alt+r"));
4152  equaliseAct = new QAction(this);
4153  equaliseAct->setText(QApplication::translate("Image", "Histogram Equalisation", 0, QApplication::UnicodeUTF8));
4154  equaliseAct->setShortcut(tr("Alt+h"));
4155  computeContourAct = new QAction(this);
4156  computeContourAct->setText(QApplication::translate("Image", "Compute Contour", 0, QApplication::UnicodeUTF8));
4157  computeContourAct->setShortcut(tr("Alt+m"));
4158  smoothAct = new QAction(this);
4159  smoothAct->setText(QApplication::translate("Image", "Smooth via Anisotropic Diffusion", 0, QApplication::UnicodeUTF8));
4160  smoothAct->setShortcut(tr("Alt+s"));
4161  gaussianAct = new QAction(this);
4162  gaussianAct->setText(QApplication::translate("Image", "Smooth via Gaussian Convolution", 0, QApplication::UnicodeUTF8));
4163  gaussianAct->setShortcut(tr("Alt+c"));
4164  bilateralAct = new QAction(this);
4165  bilateralAct->setText(QApplication::translate("Image", "Smooth via Bilateral Filter", 0, QApplication::UnicodeUTF8));
4166  bilateralAct->setShortcut(tr("Alt+b"));
4167  medianAct = new QAction(this);
4168  medianAct->setText(QApplication::translate("Image", "Smooth via Median", 0, QApplication::UnicodeUTF8));
4169  medianAct->setShortcut(tr("Shift+Alt+s"));
4170  gradMagAct = new QAction(this);
4171  gradMagAct->setText(QApplication::translate("Image", "Gradient Magnitude", 0, QApplication::UnicodeUTF8));
4172  gradMagAct->setShortcut(tr("Alt+g"));
4173  sobelAct = new QAction(this);
4174  sobelAct->setText(QApplication::translate("Image", "Sobel Edge Detection", 0, QApplication::UnicodeUTF8));
4175  sobelAct->setShortcut(tr("Alt+e"));
4176  cannyAct = new QAction(this);
4177  cannyAct->setText(QApplication::translate("Image", "Canny Edge Detection", 0, QApplication::UnicodeUTF8));
4178  cannyAct->setShortcut(tr("Shift+Alt+e"));
4179  laplacianAct = new QAction(this);
4180  laplacianAct->setText(QApplication::translate("Image", "Apply Laplacian", 0, QApplication::UnicodeUTF8));
4181  laplacianAct->setShortcut(tr("Alt+l"));
4182  highPassAct = new QAction(this);
4183  highPassAct->setText(QApplication::translate("Image", "Butterworth High-Pass Filter", 0, QApplication::UnicodeUTF8));
4184  highPassAct->setShortcut(tr("Shift+Alt+b"));
4185  normAct = new QAction(this);
4186  normAct->setText(QApplication::translate("Image", "Normalize", 0, QApplication::UnicodeUTF8));
4187  normAct->setShortcut(tr("Alt+n"));
4188  invertAct = new QAction(this);
4189  invertAct->setText(QApplication::translate("Image", "Invert Intensities", 0, QApplication::UnicodeUTF8));
4190  invertAct->setShortcut(tr("Alt+v"));
4191  relabelAct = new QAction(this);
4192  relabelAct->setText(QApplication::translate("Image", "Relabel", 0, QApplication::UnicodeUTF8));
4193  relabelAct->setShortcut(tr("Shift+Alt+l"));
4194  //Transform
4195  transformMenu = new QMenu(this);
4196  transformMenu->setTitle(QApplication::translate("Image", "Transforms", 0, QApplication::UnicodeUTF8));
4197  matchAct = new QAction(this);
4198  matchAct->setText(QApplication::translate("Image", "Match Information to ...", 0, QApplication::UnicodeUTF8));
4199  matchAct->setShortcut(tr("Shift+Alt+i"));
4200  matchHistAct = new QAction(this);
4201  matchHistAct->setText(QApplication::translate("Image", "Match Histogram to ...", 0, QApplication::UnicodeUTF8));
4202  matchHistAct->setShortcut(tr("Shift+Alt+h"));
4203  resampleSpacingAct = new QAction(this);
4204  resampleSpacingAct->setText(QApplication::translate("Image", "Resample to spacing ...", 0, QApplication::UnicodeUTF8));
4205  resampleSpacingAct->setShortcut(tr("Ctrl+Alt+r"));
4206  resampleAct = new QAction(this);
4207  resampleAct->setText(QApplication::translate("Image", "Resample Image to ...", 0, QApplication::UnicodeUTF8));
4208  resampleAct->setShortcut(tr("Shift+Alt+r"));
4209  resampleLabelAct = new QAction(this);
4210  resampleLabelAct->setText(QApplication::translate("Image", "Resample as Labelled Image to ...", 0, QApplication::UnicodeUTF8));
4211  resampleLabelAct->setShortcut(tr("Shift+Alt+l"));
4212  subsampleAct = new QAction(this);
4213  subsampleAct->setText(QApplication::translate("Image", "Subsample Image", 0, QApplication::UnicodeUTF8));
4214  subsampleAct->setShortcut(tr("Shift+Alt+s"));
4215  transformAct = new QAction(this);
4216  transformAct->setText(QApplication::translate("Image", "Transform via File ...", 0, QApplication::UnicodeUTF8));
4217  transformAct->setShortcut(tr("Shift+Alt+t"));
4218  maskAct = new QAction(this);
4219  maskAct->setText(QApplication::translate("Image", "Mask Image with ...", 0, QApplication::UnicodeUTF8));
4220  maskAct->setShortcut(tr("Shift+Alt+m"));
4221  cropAct = new QAction(this);
4222  cropAct->setText(QApplication::translate("Image", "Mask and Crop Image with ...", 0, QApplication::UnicodeUTF8));
4223  cropAct->setShortcut(tr("Shift+Alt+a"));
4224  checkerAct = new QAction(this);
4225  checkerAct->setText(QApplication::translate("Image", "Compare as Checkboard to ...", 0, QApplication::UnicodeUTF8));
4226  checkerAct->setShortcut(tr("Shift+Alt+c"));
4227  distMapAct = new QAction(this);
4228  distMapAct->setText(QApplication::translate("Image", "Distance Map", 0, QApplication::UnicodeUTF8));
4229  distMapAct->setShortcut(tr("Alt+d"));
4230  flipAct = new QAction(this);
4231  flipAct->setText(QApplication::translate("Image", "Flip", 0, QApplication::UnicodeUTF8));
4232  flipAct->setShortcut(tr("Alt+f"));
4233  //Threshold
4234  thresholdMenu = new QMenu(this);
4235  thresholdMenu->setTitle(QApplication::translate("Image", "Thresholds", 0, QApplication::UnicodeUTF8));
4236  otsuAct = new QAction(this);
4237  otsuAct->setText(QApplication::translate("Image", "Otsu Threshold", 0, QApplication::UnicodeUTF8));
4238  otsuAct->setShortcut(tr("Alt+u"));
4239  otsuMultipleAct = new QAction(this);
4240  otsuMultipleAct->setText(QApplication::translate("Image", "Otsu Multiple Threshold", 0, QApplication::UnicodeUTF8));
4241  otsuMultipleAct->setShortcut(tr("Shift+Alt+u"));
4242  binaryAct = new QAction(this);
4243  binaryAct->setText(QApplication::translate("Image", "Binary Threshold", 0, QApplication::UnicodeUTF8));
4244  binaryAct->setShortcut(tr("Shift+Alt+b"));
4245  bandAct = new QAction(this);
4246  bandAct->setText(QApplication::translate("Image", "Threshold Outside Band", 0, QApplication::UnicodeUTF8));
4247  bandAct->setShortcut(tr("Alt+t"));
4248  aboveAct = new QAction(this);
4249  aboveAct->setText(QApplication::translate("Image", "Threshold Above", 0, QApplication::UnicodeUTF8));
4250  aboveAct->setShortcut(tr("Shift+Alt+a"));
4251  belowAct = new QAction(this);
4252  belowAct->setText(QApplication::translate("Image", "Threshold Below", 0, QApplication::UnicodeUTF8));
4253  belowAct->setShortcut(tr("Shift+Alt+b"));
4254  //Vector imaging
4255  vectorMenu = new QMenu(this);
4256  vectorMenu->setTitle(QApplication::translate("Image", "Complex/Vector/4D Imaging", 0, QApplication::UnicodeUTF8));
4257  vectorMenu->setDisabled(false);
4258  vectorMagnitudeAct = new QAction(this);
4259  vectorMagnitudeAct->setText(QApplication::translate("Image", "Display Magnitude", 0, QApplication::UnicodeUTF8));
4260  vectorMagnitudeAct->setShortcut(tr("Alt+m"));
4261  vectorComponentAct = new QAction(this);
4262  vectorComponentAct->setText(QApplication::translate("Image", "Display Component ...", 0, QApplication::UnicodeUTF8));
4263  vectorComponentAct->setShortcut(tr("Alt+c"));
4264  pseudoImageAct = new QAction(this);
4265  pseudoImageAct->setText(QApplication::translate("Image", "Display Pseudo-Image", 0, QApplication::UnicodeUTF8));
4266  pseudoImageAct->setShortcut(tr("Alt+p"));
4267  vectorFieldAct = new QAction(this);
4268  vectorFieldAct->setText(QApplication::translate("Image", "Display Vector/Tensor Field", 0, QApplication::UnicodeUTF8));
4269  vectorFieldAct->setShortcut(tr("Alt+f"));
4270  streamLinesAct = new QAction(this);
4271  streamLinesAct->setText(QApplication::translate("Image", "Display Streamlines from Slice", 0, QApplication::UnicodeUTF8));
4272  streamLinesAct->setShortcut(tr("Shift+Alt+s"));
4273 
4274  //Display
4275  levelAct = new QAction(this);
4276  levelAct->setText(QApplication::translate("Image", "Auto-Level Display", 0, QApplication::UnicodeUTF8));
4277  levelAct->setShortcut(tr("Alt+o"));
4278  overlayAct = new QAction(this);
4279  overlayAct->setText(QApplication::translate("Image", "Overlay Labelled Image from ...", 0, QApplication::UnicodeUTF8));
4280  overlayAct->setShortcut(tr("Alt+o"));
4281  overlayContourAct = new QAction(this);
4282  overlayContourAct->setText(QApplication::translate("Image", "Overlay Labelled Image as Contour from ...", 0, QApplication::UnicodeUTF8));
4283  overlayContourAct->setShortcut(tr("Shift+Alt+o"));
4284  blendAct = new QAction(this);
4285  blendAct->setText(QApplication::translate("Image", "Blend Image with ...", 0, QApplication::UnicodeUTF8));
4286  blendAct->setShortcut(tr("Shift+Alt+b"));
4287  volRenderAct = new QAction(this);
4288  volRenderAct->setText(QApplication::translate("Image", "Display as Volume Rendering", 0, QApplication::UnicodeUTF8));
4289  volRenderAct->setShortcut(tr("Alt+v"));
4290  histogramAct = new QAction(this);
4291  histogramAct->setText(QApplication::translate("Image", "Display Histogram", 0, QApplication::UnicodeUTF8));
4292  histogramAct->setShortcut(tr("Alt+h"));
4293  surfacePlotAct = new QAction(this);
4294  surfacePlotAct->setText(QApplication::translate("Image", "Display Slice Surface Plot", 0, QApplication::UnicodeUTF8));
4295  surfacePlotAct->setShortcut(tr("Alt+s"));
4296  surfaceAct = new QAction(this);
4297  surfaceAct->setText(QApplication::translate("Image", "Display Iso-surface", 0, QApplication::UnicodeUTF8));
4298  surfaceAct->setShortcut(tr("Shift+Alt+s"));
4299  polyDataAct = new QAction(this);
4300  polyDataAct->setText(QApplication::translate("Image", "Generate Polygonal Data", 0, QApplication::UnicodeUTF8));
4301  polyDataAct->setShortcut(tr("Shift+Alt+p"));
4302  polyDataAct->setDisabled(true);
4303  infoAct = new QAction(this);
4304  infoAct->setText(QApplication::translate("Image", "Image Information", 0, QApplication::UnicodeUTF8));
4305  infoAct->setShortcut(tr("Alt+i"));
4306  interpolateAct = new QAction(this);
4307  interpolateAct->setText(QApplication::translate("Image", "Interpolation", 0, QApplication::UnicodeUTF8));
4308  interpolateAct->setShortcut(tr("Shift+Alt+i"));
4309  interpolateAct->setCheckable(true);
4310  interpolateAct->setChecked(true);
4311  orientAct = new QAction(this);
4312  orientAct->setText(QApplication::translate("Image", "Apply Orientation", 0, QApplication::UnicodeUTF8));
4313  orientAct->setShortcut(tr("Shift+Alt+o"));
4314  orientAct->setCheckable(true);
4315  orientAct->setChecked(true);
4316  resliceAct = new QAction(this);
4317  resliceAct->setText(QApplication::translate("Image", "3D Slice View Mode", 0, QApplication::UnicodeUTF8));
4318  resliceAct->setShortcut(tr("Shift+Ctrl+s"));
4319  resliceAct->setCheckable(true);
4320  resliceAct->setChecked(false);
4321 #if VTK_MAJOR_VERSION <= 5
4322  resliceAct->setDisabled(true);
4323 #endif
4324  cursorAct = new QAction(this);
4325  cursorAct->setText(QApplication::translate("Image", "Show Cursor", 0, QApplication::UnicodeUTF8));
4326  cursorAct->setShortcut(tr("Shift+Alt+c"));
4327  cursorAct->setCheckable(true);
4328  cursorAct->setChecked(false);
4329 
4330 #if (ITK_REVIEW || ITK_VERSION_MAJOR > 3)
4331  cropAct->setDisabled(false);
4332  computeContourAct->setDisabled(false);
4333  overlayAct->setDisabled(false);
4334  overlayContourAct->setDisabled(false);
4335 #else
4336  cropAct->setDisabled(true);
4337  computeContourAct->setDisabled(true);
4338  overlayAct->setDisabled(true);
4339  overlayContourAct->setDisabled(true);
4340 #endif
4341 
4342  milxQtRenderWindow::actionDefault->setChecked(true);
4343 }
4344 
4346 {
4347  connect(this, SIGNAL(mouseEvent(QMouseEvent*)), this, SLOT(userEvent(QMouseEvent*)));
4348 
4349  //Filter
4350  connect(rescaleAct, SIGNAL(triggered()), this, SLOT(rescale()));
4351  connect(equaliseAct, SIGNAL(triggered()), this, SLOT(histogramEqualisation()));
4352 #if (ITK_REVIEW || ITK_VERSION_MAJOR > 3)
4353  connect(computeContourAct, SIGNAL(triggered()), this, SLOT(computeContour()));
4354 #endif
4355  connect(smoothAct, SIGNAL(triggered()), this, SLOT(anisotropicDiffusion()));
4356  connect(gaussianAct, SIGNAL(triggered()), this, SLOT(gaussianSmooth()));
4357  connect(bilateralAct, SIGNAL(triggered()), this, SLOT(bilateral()));
4358  connect(medianAct, SIGNAL(triggered()), this, SLOT(median()));
4359  connect(gradMagAct, SIGNAL(triggered()), this, SLOT(gradientMagnitude()));
4360  connect(sobelAct, SIGNAL(triggered()), this, SLOT(sobelEdges()));
4361  connect(cannyAct, SIGNAL(triggered()), this, SLOT(cannyEdges()));
4362  connect(laplacianAct, SIGNAL(triggered()), this, SLOT(laplacian()));
4363  connect(highPassAct, SIGNAL(triggered()), this, SLOT(highpass()));
4364  connect(normAct, SIGNAL(triggered()), this, SLOT(normalize()));
4365  connect(invertAct, SIGNAL(triggered()), this, SLOT(invertIntensity()));
4366  connect(relabelAct, SIGNAL(triggered()), this, SLOT(relabel()));
4367 
4368  connect(matchAct, SIGNAL(triggered()), this, SLOT(matchInfo()));
4369  connect(matchHistAct, SIGNAL(triggered()), this, SLOT(matchHistogram()));
4370  connect(resampleSpacingAct, SIGNAL(triggered()), this, SLOT(resize()));
4371  connect(resampleAct, SIGNAL(triggered()), this, SLOT(resample()));
4372  connect(resampleLabelAct, SIGNAL(triggered()), this, SLOT(resampleLabel()));
4373  connect(subsampleAct, SIGNAL(triggered()), this, SLOT(subsample()));
4374  connect(transformAct, SIGNAL(triggered()), this, SLOT(transform()));
4375  connect(maskAct, SIGNAL(triggered()), this, SLOT(mask()));
4376  connect(checkerAct, SIGNAL(triggered()), this, SLOT(checkerBoard()));
4377  connect(distMapAct, SIGNAL(triggered()), this, SLOT(distanceMap()));
4378  connect(flipAct, SIGNAL(triggered()), this, SLOT(flip()));
4379  connect(surfaceAct, SIGNAL(triggered()), this, SLOT(surface()));
4380  connect(polyDataAct, SIGNAL(triggered()), this, SLOT(polyData()));
4381 
4382  connect(aboveAct, SIGNAL(triggered()), this, SLOT(thresholdAbove()));
4383  connect(belowAct, SIGNAL(triggered()), this, SLOT(thresholdBelow()));
4384  connect(bandAct, SIGNAL(triggered()), this, SLOT(threshold()));
4385  connect(otsuAct, SIGNAL(triggered()), this, SLOT(otsu()));
4386  connect(otsuMultipleAct, SIGNAL(triggered()), this, SLOT(otsuMultiple()));
4387  connect(binaryAct, SIGNAL(triggered()), this, SLOT(binaryThreshold()));
4388 
4389  connect(vectorMagnitudeAct, SIGNAL(triggered()), this, SLOT(magnitude()));
4390  connect(vectorComponentAct, SIGNAL(triggered()), this, SLOT(component()));
4391  connect(pseudoImageAct, SIGNAL(triggered()), this, SLOT(pseudoImage()));
4392  connect(vectorFieldAct, SIGNAL(triggered()), this, SLOT(vectorField()));
4393  connect(streamLinesAct, SIGNAL(triggered()), this, SLOT(streamLines()));
4394 
4395  //Display
4396  connect(levelAct, SIGNAL(triggered()), this, SLOT(autoLevel()));
4397 #if (ITK_REVIEW || ITK_VERSION_MAJOR > 3)
4398  connect(cropAct, SIGNAL(triggered()), this, SLOT(crop()));
4399  connect(overlayAct, SIGNAL(triggered()), this, SLOT(overlay()));
4400  connect(overlayContourAct, SIGNAL(triggered()), this, SLOT(overlayContour()));
4401 #endif
4402  connect(blendAct, SIGNAL(triggered()), this, SLOT(blend()));
4403  connect(volRenderAct, SIGNAL(triggered()), this, SLOT(volumeRendering()));
4404  connect(histogramAct, SIGNAL(triggered()), this, SLOT(histogram()));
4405  connect(surfacePlotAct, SIGNAL(triggered()), this, SLOT(surfacePlot()));
4406  connect(infoAct, SIGNAL(triggered()), this, SLOT(imageInformation()));
4407  connect(interpolateAct, SIGNAL(triggered()), this, SLOT(interpolateDisplay()));
4408  connect(orientAct, SIGNAL(triggered()), this, SLOT(applyOrientDisplay()));
4409 #if VTK_MAJOR_VERSION > 5
4410  connect(resliceAct, SIGNAL(triggered()), this, SLOT(resliceMode()));
4411 #endif
4412  connect(cursorAct, SIGNAL(triggered()), this, SLOT(showCrosshair()));
4413  connect(milxQtRenderWindow::refreshAct, SIGNAL(triggered()), this, SLOT(refresh()));
4414  connect(milxQtRenderWindow::resetAct, SIGNAL(triggered()), this, SLOT(reset()));
4415 
4416  milxQtWindow::createConnections(); //consume right click events etc.
4417 }
4418 
4419 void milxQtImage::contextMenuEvent(QContextMenuEvent *currentEvent)
4420 {
4422 
4423  contextMenu->exec(currentEvent->globalPos());
4424 }
4425 
4427 {
4428  contextMenu = new QMenu(this);
4429  contextMenu->setTitle(QApplication::translate("MainWindow", "Imaging", 0, QApplication::UnicodeUTF8));
4430 
4431  foreach(QAction *currAct, milxQtWindow::actionsToAdd)
4432  {
4433  contextMenu->addAction(currAct);
4434  }
4435  foreach(QMenu *currMenu, milxQtWindow::menusToAdd)
4436  {
4437  contextMenu->addMenu(currMenu);
4438  }
4439  contextMenu->addMenu(operationsMenu());
4440  contextMenu->addMenu(thresholdsMenu());
4441  contextMenu->addMenu(transformsMenu());
4442  contextMenu->addMenu(vectorsMenu());
4443 
4444  contextMenu->addSeparator()->setText(tr("Display"));
4445  contextMenu->addAction(levelAct);
4446  contextMenu->addAction(overlayAct);
4447  contextMenu->addAction(overlayContourAct);
4448  contextMenu->addAction(blendAct);
4449  contextMenu->addAction(checkerAct);
4450  contextMenu->addAction(volRenderAct);
4451  contextMenu->addAction(histogramAct);
4452  contextMenu->addAction(surfacePlotAct);
4453  contextMenu->addAction(surfaceAct);
4454 // contextMenu->addAction(polyDataAct);
4455  contextMenu->addAction(infoAct);
4456  contextMenu->addAction(interpolateAct);
4457  contextMenu->addAction(orientAct);
4458  contextMenu->addAction(resliceAct);
4459  contextMenu->addAction(cursorAct);
4466  milxQtRenderWindow::viewGroup->setDisabled(!volume);
4472 
4474 
4475  return contextMenu;
4476 }
4477 
4479 {
4480  operateMenu->addAction(rescaleAct);
4481  operateMenu->addAction(equaliseAct);
4482  operateMenu->addAction(computeContourAct);
4483  operateMenu->addAction(smoothAct);
4484  operateMenu->addAction(gaussianAct);
4485  operateMenu->addAction(bilateralAct);
4486  operateMenu->addAction(medianAct);
4487  operateMenu->addAction(gradMagAct);
4488  operateMenu->addAction(sobelAct);
4489  operateMenu->addAction(cannyAct);
4490  operateMenu->addAction(laplacianAct);
4491  operateMenu->addAction(highPassAct);
4492  operateMenu->addAction(normAct);
4493  operateMenu->addAction(distMapAct);
4494  operateMenu->addAction(matchHistAct);
4495  operateMenu->addAction(invertAct);
4496  operateMenu->addAction(relabelAct);
4497 
4498  return operateMenu;
4499 }
4500 
4502 {
4503  thresholdMenu->addAction(otsuAct);
4504  thresholdMenu->addAction(otsuMultipleAct);
4505  thresholdMenu->addAction(binaryAct);
4506  thresholdMenu->addAction(bandAct);
4507  thresholdMenu->addAction(aboveAct);
4508  thresholdMenu->addAction(belowAct);
4509 
4510  return thresholdMenu;
4511 }
4512 
4514 {
4515  transformMenu->addAction(matchAct);
4516  transformMenu->addAction(resampleSpacingAct);
4517  transformMenu->addAction(resampleAct);
4518  transformMenu->addAction(resampleLabelAct);
4519  transformMenu->addAction(subsampleAct);
4520  transformMenu->addAction(transformAct);
4521  transformMenu->addAction(maskAct);
4522  transformMenu->addAction(cropAct);
4523  transformMenu->addAction(flipAct);
4524 
4525  return transformMenu;
4526 }
4527 
4529 {
4530  vectorMenu->addAction(vectorMagnitudeAct);
4531  vectorMenu->addAction(vectorComponentAct);
4532  vectorMenu->addAction(pseudoImageAct);
4533  vectorMenu->addAction(vectorFieldAct);
4534  vectorMenu->addAction(streamLinesAct);
4535 
4536  //Disable enable based on flags
4537  vectorMenu->setEnabled(vectorised);
4538  pseudoImageAct->setDisabled(true); //not working yet
4539 
4540  return vectorMenu;
4541 }
4542 
4543 void milxQtImage::dropEvent(QDropEvent *currentEvent)
4544 {
4545  if(currentEvent->source() == this) //disallow self drops
4546  return;
4547 
4548  milxQtImage *sourceImage = qobject_cast<milxQtImage *>(currentEvent->source());
4549  if(currentEvent->spontaneous())
4550  currentEvent->ignore(); //dont accept drop
4551 
4552  QList<QUrl> urlsList = currentEvent->mimeData()->urls();
4553  QString tmp, typeString = currentEvent->mimeData()->text();
4554 
4555  for(int j = 0; j < urlsList.size(); j ++)
4556  {
4557  if(urlsList[j].isValid())
4558  {
4559 #ifdef Q_WS_WIN
4560  tmp = urlsList[j].path().remove(0,1);
4561 #else
4562  tmp = urlsList[j].path();
4563 #endif
4564  printInfo("Dropped Path into Image: " + tmp);
4565 
4566  if(sourceImage)
4567  {
4568  currentEvent->acceptProposedAction();
4569  if(currentEvent->proposedAction() == Qt::MoveAction)
4570 // blend(tmp);
4571  blend(sourceImage);
4572  #if (ITK_REVIEW || ITK_VERSION_MAJOR > 3)
4573  if(currentEvent->proposedAction() == Qt::LinkAction)
4574  overlay(tmp);
4575  #endif
4576  else
4577 // checkerBoard(tmp);
4578  checkerBoard(sourceImage);
4579  }
4580  Render();
4581  }
4582  }
4583 }
4584 
4585 void milxQtImage::SetupWidgets(vtkRenderWindowInteractor *interactor)
4586 {
4587  printInfo("Setting up image for Annotation");
4588  interactor->Initialize();
4589 
4590  double imageBounds[6], imgCenter[3];
4591  imageData->GetBounds(imageBounds);
4592  imageData->GetOrigin(imgCenter);
4593  double length = imageBounds[1]-imageBounds[0]/10;
4594 
4595  //line widget setup
4596  lineWidget = vtkSmartPointer<vtkLineWidget2>::New();
4597  lineWidget->SetInteractor(interactor);
4598  lineWidget->CreateDefaultRepresentation();
4599 
4600  //distance widget setup
4601  distanceWidget = vtkSmartPointer<vtkDistanceWidget>::New();
4602  distanceWidget->SetInteractor(interactor);
4603  distanceWidget->CreateDefaultRepresentation();
4604  vtkDistanceRepresentation::SafeDownCast(distanceWidget->GetRepresentation())->SetLabelFormat("%-#6.3g mm");
4605 
4606  //cross distance widget setup
4607  biDirectionWidget = vtkSmartPointer<vtkBiDimensionalWidget>::New();
4608  biDirectionWidget->SetInteractor(interactor);
4609  biDirectionWidget->CreateDefaultRepresentation();
4610 
4611  //angle widget setup
4612  angleWidget = vtkSmartPointer<vtkAngleWidget>::New();
4613  angleWidget->SetInteractor(interactor);
4614  angleWidget->CreateDefaultRepresentation();
4615 
4616  //sphere widget setup
4617  sphereRep = vtkSmartPointer<vtkSphereRepresentation>::New();
4618  sphereRep->SetRepresentationToWireframe();
4619  sphereRep->SetThetaResolution(16);
4620  sphereRep->SetPhiResolution(16);
4621  sphereRep->SetRadius(length);
4622  sphereRep->SetCenter(imgCenter);
4623  sphereRep->HandleTextOn();
4624  sphereRep->RadialLineOn();
4625  sphereRep->HandleVisibilityOn();
4626  sphereWidget = vtkSmartPointer<vtkSphereWidget2>::New();
4627  sphereWidget->SetInteractor(interactor);
4628 // sphereWidget->CreateDefaultRepresentation();
4629  sphereWidget->SetRepresentation(sphereRep);
4630  sphereWidget->ScalingEnabledOn();
4631 
4632  //Change colour
4633  sphereRep->GetSphereProperty()->SetColor(0.9, 0.9, 1.0);
4634 
4635  vtkSmartPointer<vtkPolyData> sphere = vtkSmartPointer<vtkPolyData>::New();
4636  sphereRep->GetPolyData(sphere);
4637 
4638  //box widget
4639  boxWidget = vtkSmartPointer<vtkBoxWidget2>::New();
4640  boxWidget->SetInteractor(interactor);
4641  boxWidget->RotationEnabledOn();
4642  //boxWidget->CreateDefaultRepresentation();
4643 
4644  vtkSmartPointer<vtkBoxRepresentation> boxRepresentation = vtkSmartPointer<vtkBoxRepresentation>::New();
4645  boxRepresentation->SetPlaceFactor( 1 );
4646  boxRepresentation->PlaceWidget(sphere->GetBounds());
4647  boxWidget->SetRepresentation(boxRepresentation);
4648 
4649  //plane widget setup
4650  double actorBounds[6], center[3];
4651 // viewer->GetImageActor()->GetBounds(actorBounds);
4652  sphere->GetBounds(actorBounds);
4653  center[0] = (actorBounds[0] + actorBounds[1])/2.0;
4654  center[1] = (actorBounds[2] + actorBounds[3])/2.0;
4655  center[2] = (actorBounds[4] + actorBounds[5])/2.0;
4656  planeWidget = vtkSmartPointer<vtkPlaneWidget>::New();
4657  planeWidget->SetInteractor(interactor);
4658  planeWidget->SetPlaceFactor( 1 );
4659 // planeWidget->SetRepresentationToOutline();
4660 // planeWidget->SetHandleSize(planeWidget->GetHandleSize()*4);
4661 // planeWidget->SetHandleSize((actorBounds[1]-actorBounds[0])/10.0);
4662 // planeWidget->NormalToXAxisOn();
4663 // planeWidget->NormalToYAxisOn();
4664  planeWidget->NormalToZAxisOn();
4665 // planeWidget->PlaceWidget(actorBounds[0], actorBounds[1], actorBounds[2], actorBounds[3], actorBounds[4], actorBounds[5]);
4666 // planeWidget->PlaceWidget(viewer->GetImageActor()->GetBounds());
4667 // planeWidget->PlaceWidget(sphere->GetBounds());
4668  //X
4669 // planeWidget->SetOrigin(center[0],actorBounds[2],actorBounds[4]);
4670 // planeWidget->SetPoint1(center[0],actorBounds[3],actorBounds[4]);
4671 // planeWidget->SetPoint2(center[0],actorBounds[2],actorBounds[5]);
4672  //Y
4673 // planeWidget->SetOrigin(actorBounds[0],center[1],actorBounds[4]);
4674 // planeWidget->SetPoint1(actorBounds[1],center[1],actorBounds[4]);
4675 // planeWidget->SetPoint2(actorBounds[0],center[1],actorBounds[5]);
4676  //Z
4677  planeWidget->SetOrigin(actorBounds[0],actorBounds[2],center[2]);
4678  planeWidget->SetPoint1(actorBounds[1],actorBounds[2],center[2]);
4679  planeWidget->SetPoint2(actorBounds[0],actorBounds[3],center[2]);
4680  planeWidget->SetResolution(2);
4681 // planeWidget->UpdatePlacement();
4682 }
4683 
4684 QString milxQtImage::getOpenFilename(const QString labelForDialog, QString exts)
4685 {
4686  if(exts.isEmpty())
4687  exts = QString(openMedImageExts.c_str()) + ";;" + QString(openImageExts.c_str()) + ";;" + QString(openOtherImageExts.c_str());
4688  QSettings settings("Shekhar Chandra", "milxQt");
4689  QString path = settings.value("recentPath").toString();
4690  QFileDialog *fileOpener = new QFileDialog(this);
4691  QString filename = fileOpener->getOpenFileName(this,
4692  tr(labelForDialog.toStdString().c_str()),
4693  path,
4694  tr(exts.toStdString().c_str()) );
4695 
4696  return filename;
4697 }
QAction * scaleAct
Action for the scale bar of the display.
void printWarning(QString msg)
Warning message wrapper for console.
QMenu * transformsMenu()
Return the transforms menu with the milxQtImage class ordering. This is for the benefit of derived cl...
void checkerBoard(QString filename="", int numberOfSquares=0)
Tiles another image with the current image using alternating squares for comparison. See generateCheckerBoard() for more info.
vtkLookupTable * GetLookupTable()
Get the lookup table of the colours in display window.
int defaultView
Default view for data (default is axial)
void highpass()
Applies Butterworth high pass filter to image.
bool logScale
Using custom scalar bar?
void printError(QString msg)
Error message wrapper for console.
void reset()
Update data internally and refresh display.
virtual void updateCoords(vtkObject *obj)
Picks the coordinates and pixel value from the current mouse position in the window.
QAction * blendAct
Action for blending images.
Definition: milxQtImage.h:1478
QAction * matchAct
Action for matching info of image to another image.
Definition: milxQtImage.h:1445
static itk::SmartPointer< TImage > ThresholdImage(itk::SmartPointer< TImage > img, float outsideValue, float belowValue, float aboveValue)
Generates an image with the intensities below and above a certain level thresholded (capped) to the o...
Definition: milxImage.h:2939
vtkSmartPointer< vtkImageData > imageData
Points to the current VTK Image Data, Smart Pointer.
Definition: milxQtImage.h:1410
bool isFloatingPointImage()
Returns true if image is a floating point (float) image.
Definition: milxQtImage.h:592
QAction * overlayAct
Action for overlaying labelled image.
Definition: milxQtImage.h:1476
void generateVoxelisedSurface(vtkSmartPointer< vtkPolyData > surfaceToVoxelise, double *bounds=NULL, double *spacing=NULL)
Converts or Voxelises a surface (vtkPolyData) to an image.
virtual void showCrosshair(const bool quietly=false)
Show the cursor/crosshair for marking depending on action. Image must be generated before calling...
QAction * orientAct
Orient image?
Definition: milxQtImage.h:1484
void sobelEdges()
Computes the Sobel edge detection of the image and displays it.
QAction * histogramAct
Action for displaying histogram.
Definition: milxQtImage.h:1480
QAction * saveViewFileAct
Save camera view to file.
bool eightbit
Using eightbit data?
Definition: milxQtImage.h:1388
virtual void scaleDisplay(const bool forceDisplay=false)
Toggles the scale bar display.
QMenu * viewMenu
Context Menu.
vtkSmartPointer< vtkBoxWidget2 > boxWidget
Used for measuring angles.
void bilateral()
Computes the Bilateral smoothing of the image and displays it.
void anisotropicDiffusion()
Computes the anisotropic diffusion (smoothing) of the image and displays it.
QAction * cropAct
Action for auto cropping image.
Definition: milxQtImage.h:1453
QAction * lightingAct
Action for two-sided lighting of the display.
itkEventQtObserver::Pointer observeProgress
Observer for the Qt event loop.
Definition: milxQtImage.h:1416
int currentView
Current view for data.
void contextMenuEvent(QContextMenuEvent *event)
The context menu setup member.
QMenu * basicContextMenu()
Return the basic context menu with the milxQtImage class ordering. This is for the benefit of derived...
QActionGroup * windowActionGroup
used for the custom menu
virtual vtkRenderWindowInteractor * GetVTKInteractor()
Get the interactor associated with the view rendering.
Definition: milxQtImage.h:517
void setName(const QString filename)
Set the name of the data.
QList< QAction * > extActionsToAdd
Extension actions to add.
Definition: milxQtWindow.h:253
void createConnections()
Create the connections for context menu etc.
QAction * relabelAct
Action for relabelling image.
Definition: milxQtImage.h:1442
milxQtImage(QWidget *theParent=0, bool contextSystem=true)
The standard constructor.
Definition: milxQtImage.cpp:55
void invertIntensity()
Computes the inverse intensities of the image and displays it.
vtkActorCollection * GetActors()
Get all the actors in the render window.
void imageToVectorField(vectorImageType::Pointer, floatImageType::Pointer, int, float)
Emit signal to compute image to vector field process.
vtkSmartPointer< vtkContourWidget > contourWidget
contour interaction
static itk::SmartPointer< TImage > RelabelImage(itk::SmartPointer< TImage > labelledImg)
Returns a labelled image with labelled values relabelled consecutively based on connectivity.
Definition: milxImage.h:2690
vtkSmartPointer< vtkRenderer > renderer
Renderer for the data.
void SetIntensityLevel(double level)
Set the level for the image intensity tranfer function.
void AddActor(vtkSmartPointer< vtkProp > actor)
Add a VTK actor to this window.
This class represents the MILX Qt Render Window Display object using QVTK.
QAction * cannyAct
Action for canny edges of image.
Definition: milxQtImage.h:1437
vtkSmartPointer< vtkAngleWidget > angleWidget
Used for measuring angles.
void imageToVolume(vtkSmartPointer< vtkImageData >, bool)
Emit signal to show the image as a volume.
virtual QString strippedNamePrefix()
Returns the stripped (path removed) name of the data with "Generic" prefix.
Definition: milxQtWindow.h:98
vtkSmartPointer< vtkLookupTable > lookupTable
Lookup table for the shapes/images, base class is used to allow references to different look up table...
vtkSmartPointer< vtkImageViewer3 > viewer
VTK Viewer handler, Smart Pointer.
Definition: milxQtImage.h:1409
void median()
Computes the median image and displays it.
QAction * otsuMultipleAct
Otsu Threshold.
Definition: milxQtImage.h:1462
void createActions()
Create the actions for context menu etc.
QAction * viewZY
Change view to zy-plane (Coronal)
This class represents the MILX Qt Image Display object using VTK.
Definition: milxQtImage.h:118
void component(int index=-1)
Shows the vector image as a scalar image given component index.
void normalize()
Computes the normalization of the image and displays it.
QAction * pseudoImageAct
Action for displaying vector/tensor fields as a pseudo image.
Definition: milxQtImage.h:1471
QAction * vectorMagnitudeAct
Action for displaying magnitude of vector images.
Definition: milxQtImage.h:1469
bool loaded
Loaded Image from file?
void resize(double outputSpacing=0.0)
Resizes image to spacing given. Currently only does isotropic.
static itk::SmartPointer< TImage > CheckerBoard(itk::SmartPointer< TImage > img, itk::SmartPointer< TImage > imgToCheckerBoard, const int numberOfSquares=0)
Generates a checker board pattern where each box alternates between two images. Ideal for comparison ...
Definition: milxImage.h:2188
void surfacePlot()
Surface plot of slice.
vtkSmartPointer< vtkBiDimensionalWidget > biDirectionWidget
Used for measuring cross distances.
floatImageType::Pointer imageFloat
Up to date floating point image data.
Definition: milxQtImage.h:1402
vtkSmartPointer< vtkMatrix4x4 > transformMatrix
Transform matrix for actor(s)
void gradientMagnitude()
Computes the gradient magnitude of the image and displays it.
virtual void contour()
Draw contour interactively on images.
QMenu * contextMenu
Context Menu.
Definition: milxQtWindow.h:250
virtual void disableCrosshair()
removes the cursor/crosshair.
Definition: milxQtImage.h:1140
void setLevel(int level)
Set window level the display to proportion of maxValue.
virtual void viewToZXPlane()
Change view to zx-plane.
This class represents the MILX Qt File I/O object using VTK/ITK/Qt.
Definition: milxQtFile.h:60
QString strippedName()
Returns the stripped (path removed) name of the data.
Definition: milxQtWindow.h:80
QAction * cursorAct
Show cursor?
Definition: milxQtImage.h:1486
void thresholdAbove(float value=0, float level=0)
Threshold the image for all values above a given value.
vtkSmartPointer< vtkOrientationMarkerWidget > humanGlyph
Glyph for showing equivalent view on human.
QAction * flipAct
Action for flipping image.
Definition: milxQtImage.h:1456
void scale(float scaling)
scales the intensities of current images.
QAction * distMapAct
Action for distance map of image.
Definition: milxQtImage.h:1455
bool rgb
Using RGB data?
Definition: milxQtImage.h:1390
vtkSmartPointer< vtkImageAccumulate > hist
Histogram filter, allocated on histogram() call.
Definition: milxQtImage.h:1413
void vectorField(int subsampleFactor=0, float scaling=0.0)
Converts the vector image to a vector field.
virtual void createMenu(QMenu *menu)
Create the menu for the data in this object. Used for context menu and file menus.
QAction * surfacePlotAct
Action for displaying surface plot.
Definition: milxQtImage.h:1481
QAction * resliceAct
Reslice mode?
Definition: milxQtImage.h:1485
static itk::SmartPointer< TImage > SubtractImages(itk::SmartPointer< TImage > img1, itk::SmartPointer< TImage > img2)
Subtracts image 2 from image 1, returning the result.
Definition: milxImage.h:1944
void volumeRendering()
Display current image as volume rendering.
static itk::SmartPointer< TImage > GradientMagnitude(itk::SmartPointer< TImage > img)
Generates an image with the gradient magnitude of the given image.
Definition: milxImage.h:2283
void blend(QString filename="", float opacity=-1.0)
Display a blend of the current image with another image.
void modified(vtkSmartPointer< vtkImageActor >)
Emit signal to allow updating of image actors if present.
void dropEvent(QDropEvent *event)
Part of the Drag and Drop feature members. Opens the dropped files.
void threshold(float value=0, float blevel=0, float alevel=0)
Threshold the image for all values between a band to a given value.
QAction * laplacianAct
Action for Laplacian of image.
Definition: milxQtImage.h:1438
void setDisplayData(QPointer< milxQtImage > newImg)
Shares the milxQtImage data to current image. You will need to call generate image after this...
void rescale()
Rescaled the intensities of an image to specified new max and min values.
vtkImageActor * GetImageActor()
Returns the internal image actor used for display.
Definition: milxQtImage.h:442
QAction * humanAct
Show human view orientation glyph?
void multiply(milxQtImage *img)
Multiplies img to current image.
void SetTransform(vtkSmartPointer< vtkTransform > transform)
Sets the transform for the image that will be generated. Must pass a vtkTransform objects...
void transform(QString filename="", QString refImgFilename="", bool inverse=false)
Transforms current image given ITK transform file.
double stddevValue
Std deviation data value currently held.
Definition: milxQtImage.h:1420
void mask(QString filename="")
Masks current image with another image.
void setDeletableOnClose(bool delOnClose)
Set if the window deletable on close. Default is true.
Definition: milxQtWindow.h:178
QList< QMenu * > menusToAdd
Context Menu&#39;s to add.
Definition: milxQtWindow.h:254
QAction * belowAct
Threshold from below.
Definition: milxQtImage.h:1466
void applyOrientDisplay(const bool quietly=false)
Toggles applying the orientation matrix of the image.
virtual void SetupWidgets(vtkRenderWindowInteractor *interactor)
Update the interactor so that the widgets are usable. Resizing widges for image objects.
QAction * bandAct
Threshold inbetween band.
Definition: milxQtImage.h:1464
QAction * streamLinesAct
Action for displaying stream lines.
Definition: milxQtImage.h:1473
QAction * otsuAct
Otsu Threshold.
Definition: milxQtImage.h:1461
QAction * backgroundAct
Action for axes of the display.
static itk::SmartPointer< TImage > ThresholdAboveImage(itk::SmartPointer< TImage > img, float outsideValue, float aboveValue)
Generates an image with the intensities above a certain level thresholded (capped) to the outsideValu...
Definition: milxImage.h:2895
void interpolateDisplay(const bool quietly=false)
Toggles interpolation.
bool track
track the coordinates during user interaction
Definition: milxQtImage.h:1395
double GetIntensityLevel()
Get the level for the image intensity tranfer function.
vtkSmartPointer< vtkDistanceWidget > distanceWidget
Used for measuring distances.
void imageToPseudoImage(vectorImageType::Pointer)
Emit signal to compute image to pseudo-image process.
vtkSmartPointer< vtkLineWidget2 > lineWidget
Used for drawing lines.
QAction * volRenderAct
Action for volume rendering.
Definition: milxQtImage.h:1479
vectorImageType::Pointer GetVectorImage()
Returns the internal vector image data. Unlike the other Get*Image() members, the return value can be...
Definition: milxQtImage.h:426
QAction * matchHistAct
Action for matching histogram of image.
Definition: milxQtImage.h:1446
void laplacian()
Computes the Laplacian of the image and displays it.
QString prefix
Prefix of the data.
Definition: milxQtWindow.h:242
QActionGroup * viewGroup
Grouping for check boxes.
void printDebug(QString msg)
Debug message wrapper for console.
QAction * contourPolyDataAct
Save contour surface points as polydata.
virtual void updateLookupTable()
Sets the necessary LUTs to model view.
bool is32BitImage()
Returns true if image is an 32-bit (int) image.
Definition: milxQtImage.h:556
bool appendedData
Appended image data?
Definition: milxQtImage.h:1387
QAction * infoAct
Action for displaying information about the image.
Definition: milxQtImage.h:1482
static std::string ImageOrientation(itk::SmartPointer< TImage > img)
Returns the orientation flag of an image.
Definition: milxImage.h:2126
static itk::SmartPointer< TImage > GaussianSmooth(itk::SmartPointer< TImage > img, const float variance)
Generates the Gaussian smoothing (by convolution) of an image using the variance provided.
Definition: milxImage.h:2616
QAction * actionDefault
Default colours.
void polyData()
Converts the image to polygonal data. Ideally suited for any type of image.
QMenu * vectorMenu
Vector Menu.
Definition: milxQtImage.h:1468
QAction * contourAct
Action for contouring surface points using Dijkstras algorithm.
QAction * checkerAct
Action for checkerboard of image.
Definition: milxQtImage.h:1454
static itk::SmartPointer< TImage > ThresholdBelowImage(itk::SmartPointer< TImage > img, float outsideValue, float aboveValue)
Generates an image with the intensities below a certain level thresholded (capped) to the outsideValu...
Definition: milxImage.h:2917
void updateSlice(vtkObject *obj)
Updates the display of the slice in the window.
void Render()
Force Render or Update of the display.
QMenu * transformMenu
Transform Menu.
Definition: milxQtImage.h:1444
void crop(QString filename="")
Masks and crops the current image with another image.
static itk::SmartPointer< TImage > Laplacian(itk::SmartPointer< TImage > img)
Generates an Laplacian image from the input image.
Definition: milxImage.h:2323
void otsuMultiple(int bins=0, int labels=0)
Otsu Multiple Threshold the image for all values between a band to a given level. ...
bool imported
Imported before?
Definition: milxQtImage.h:1386
void setDefaultOrientation(int orientMode)
Change orientation mode to one of the supported standards. Default: Radiological. ...
static itk::SmartPointer< TImage > ResizeImage(itk::SmartPointer< TImage > img, typename TImage::SizeType imgSize)
Resizes current image using current spacing.
Definition: milxImage.h:1379
QAction * aboveAct
Threshold from above.
Definition: milxQtImage.h:1465
void resample(QString filename="")
Resamples current image to another image.
rgbImageType::Pointer GetRGBImage()
Returns the internal RGB image data.
Definition: milxQtImage.h:408
vtkImageMapToWindowLevelColors * GetWindowLevel()
Returns the internal image window levels data used for display.
Definition: milxQtImage.h:727
void convolve(milxQtImage *img)
Convolves img to current image.
QMenu * thresholdMenu
Threshold Menu.
Definition: milxQtImage.h:1460
virtual void enableCrosshair()
Enables the cursor/crosshair for marking. Image must be generated before calling. ...
Definition: milxQtImage.h:1128
void setView(int viewMode)
Change view to view mode identified by number. 0-axial, 1-coronal, 2-sagittal.
QAction * transformAct
Action for transforming image.
Definition: milxQtImage.h:1451
QAction * levelAct
Action for auto-levelling gamma for display.
Definition: milxQtImage.h:1475
static itk::SmartPointer< TImage > MatchHistogram(itk::SmartPointer< TImage > img, itk::SmartPointer< TImage > imgToMatch, const int bins=128)
Changes the image gray levels to match histogram of image provided.
Definition: milxImage.h:2421
QAction * normAct
Action for normalization of image.
Definition: milxQtImage.h:1440
bool isOriented()
Returns true if orientation is applied to the display of the image.
Definition: milxQtImage.h:648
QAction * binaryAct
Binary Threshold.
Definition: milxQtImage.h:1463
void generateImage(const bool quietly=false)
Assigns the array data to the image and setups up the viewer.
QMenu * vectorsMenu()
Return the vector imaging menu with the milxQtImage class ordering. This is for the benefit of derive...
bool viewerSetup
has the viewer/window been setup (only done initial so is to not disturb users settings) ...
Definition: milxQtImage.h:1392
QList< QAction * > actionsToAppend
Context actions to append.
Definition: milxQtWindow.h:252
QAction * contourNodePolyDataAct
Save contour surface nodes as polydata.
void thresholdBelow(float value=0, float level=0)
Threshold the image for all values below a given value.
bool isCrosshair()
Returns true if cursor shown to the display of the image.
Definition: milxQtImage.h:656
QAction * equaliseAct
Action for contouring image.
Definition: milxQtImage.h:1429
QAction * sobelAct
Action for sobel edges of image.
Definition: milxQtImage.h:1436
double meanValue
Other Variables.
Definition: milxQtImage.h:1419
QAction * refreshAct
Action for refreshing the display.
bool integer
Using integer data?
Definition: milxQtImage.h:1389
QAction * overlayContourAct
Action for overlaying labelled image as contour.
Definition: milxQtImage.h:1477
static itk::SmartPointer< TImage > Bilateral(itk::SmartPointer< TImage > img, const float sigmaRange, const float sigmaSpatial)
Generates the (non-linear) Bilateral smoothing of an image using the sigmas provided.
Definition: milxImage.h:2594
QAction * interpolateAct
Interpolate image?
Definition: milxQtImage.h:1483
static itk::SmartPointer< TImage > SobelEdges(itk::SmartPointer< TImage > img)
Generates an image with Sobel edges, i.e. uses the Sobel edge detection on the input image...
Definition: milxImage.h:2303
QAction * resampleAct
Action for resampling image.
Definition: milxQtImage.h:1448
QAction * contourInitAct
Load contour surface points from polydata.
bool scaleBefore
scale displayed?
QAction * highPassAct
Action for high pass filtering of image.
Definition: milxQtImage.h:1439
Represents an image (i.e. an regular rectangular array with scalar values) and their common operation...
Definition: milxImage.h:174
void enableActionBasedOnView()
Enables the view actions corresponding to current view set.
double minValue
min value in image
Definition: milxQtImage.h:1421
QAction * gradMagAct
Action for gradient magnitude of image.
Definition: milxQtImage.h:1435
bool openImage(const QString filename, vtkImageData *data)
Opens an image file, which is any of the following: JPEG, PNG, DICOM, TIFF, NIFTI, HDR etc.
Definition: milxQtFile.cpp:75
static itk::SmartPointer< TImage > HistogramEqualisation(itk::SmartPointer< TImage > img, float alpha=0.3, float beta=0.3, float radius=5)
Generates an image with the intensities after histogram equalisation. Defaults to classic histogram e...
Definition: milxImage.h:2258
void distanceMap(bool signedDistance=true, bool inside=false)
Computes the distance map of the image and displays it.
void binaryThreshold(float value=0, float blevel=0, float alevel=0)
Binary Threshold the image for all values between a band to a given value.
void cannyEdges()
Computes the Canny edge detection of the image and displays it.
QMenu * contourMenu
Contour Menu.
void imageInformation()
Displays the origin and other important information about the image (not the displayed image...
void SetRenderer(vtkRenderer *rnder)
Assigns a VTK Renderer object.
static vtkSmartPointer< vtkImageData > ApplyOrientationToVTKImage(vtkSmartPointer< vtkImageData > img, itk::SmartPointer< TImage > refImage, vtkSmartPointer< vtkMatrix4x4 > &transformMatrix, const bool labelledImage, const bool flipY=true)
Applies orientation/direction and origin to a VTK image from a reference image.
Definition: milxImage.h:1034
QList< ModelActorItem > modelActors
Model actors being displayed in image view.
Definition: milxQtImage.h:1414
void imageToSurface(vtkSmartPointer< vtkImageData >, const float)
Emit signal to compute image to surface process.
charImageType::Pointer imageChar
Up to date 8-bit greyscale image data.
Definition: milxQtImage.h:1399
QAction * resetAct
Action for refreshing the display.
QAction * gaussianAct
Action for Gaussian smoothing of image.
Definition: milxQtImage.h:1432
bool isVectorImage()
Returns true if image is a vector image.
Definition: milxQtImage.h:610
QMenu * colourMapMenu
Colour map menu.
QAction * subsampleAct
Action for downsampling image.
Definition: milxQtImage.h:1450
void trackView(milxQtImage *windowToTrack, ViewType viewTo)
Enables tracking of the view (axial etc.) to imgToTrack provided.
QAction * rescaleAct
Action for contouring image.
Definition: milxQtImage.h:1428
bool usingVTKImage
using VTK image data?
Definition: milxQtImage.h:1385
virtual void viewToZYPlane()
Change view to zy-plane.
virtual void disableScale()
Disables the scale bar display.
void linkProgressEventOf(vtkObject *obj)
Link the progress of filters etc to keep the UI responsive.
void magnitude()
Shows the vector image as a scalar image given by the magnitude of the vectors.
double maxValue
max value in image
Definition: milxQtImage.h:1422
QAction * saveViewAct
Save camera view.
bool vectorised
Using Vector image data?
Definition: milxQtImage.h:1391
void relabel()
Relabel the objects of a labelled image based on connectivity in consecutive order.
QAction * viewXY
Change view to xy-plane (Axial)
void imageToPlot(vtkSmartPointer< vtkImageData >, int)
Emit signal to show the image as a plot.
QAction * vectorFieldAct
Action for displaying vector/tensor fields.
Definition: milxQtImage.h:1472
QAction * resampleSpacingAct
Action for resampling image based on spacing.
Definition: milxQtImage.h:1447
virtual void enableScale(QString title="", const bool quiet=false, double minRange=0.0, double maxRange=0.0, int noOfLabels=3)
Enable scale bar display with the title provided.
QAction * invertAct
Action for invert intensity of image.
Definition: milxQtImage.h:1441
vtkSmartPointer< vtkPlaneWidget > planeWidget
Used for drawing planes.
void setupEvents()
Executes common events setup and connections code for image viewing.
void lighting()
Toggles two sided lighting in display.
static itk::SmartPointer< TImage > MatchInformation(itk::SmartPointer< TImage > img, itk::SmartPointer< TImage > imgToMatch, bool originOnly=false)
Changes the image info to match that of provided image. By default, only the spacing, region and origin are changed.
Definition: milxImage.h:2386
QString getOpenFilename(const QString labelForDialog="Select Image", QString exts="")
Use the QFileDialog to get an image filename.
QMenu * thresholdsMenu()
Return the thresholds menu with the milxQtImage class ordering. This is for the benefit of derived cl...
virtual ~milxQtImage()
The standard destructor.
void imageToStreamLines(vectorImageType::Pointer, floatImageType::Pointer)
Emit signal to compute image streamlines of vector field process. Every pixel in the float image is u...
bool flipped
Flip for display?
Definition: milxQtImage.h:1394
void imageToPolyData(vtkSmartPointer< vtkImageData >)
Emit signal to compute image to poly data process.
QList< QAction * > actionsToAdd
Context actions to add.
Definition: milxQtWindow.h:251
charImageType::Pointer GetCharImage()
Returns the internal unsigned char image data.
Definition: milxQtImage.h:392
void updateData(const bool orient=true)
Ensures the internal visualisation data is up to date.
void setupHumanGlyph(vtkSmartPointer< vtkMatrix4x4 > mat=NULL)
Setup the human orientation glyph even if some transform if present between glyph and view...
QAction * medianAct
Action for median smoothing of image.
Definition: milxQtImage.h:1434
vtkSmartPointer< vtkSphereWidget2 > sphereWidget
Used for measuring angles.
size_t actualNumberOfDimensions
All images loaded as 3D images or 3D vector images, this shows actual dimension.
Definition: milxQtImage.h:1405
static itk::SmartPointer< TImage > AddImages(itk::SmartPointer< TImage > img1, itk::SmartPointer< TImage > img2)
Adds image 1 to image 2, returning the result.
Definition: milxImage.h:1922
void histogramEqualisation()
Rescale the intensities of an image based on histogram equalisation.
QAction * viewZX
Change view to zx-plane (Sagittal)
virtual void customOperation()
Custom operation, data dependent for viewing in unified environment.
void modified(QPointer< milxQtImage >)
Emit signal to send updated image data. Used for updating dependent displays.
static itk::SmartPointer< TImage > FlipImage(itk::SmartPointer< TImage > img, bool xAxis=false, bool yAxis=true, bool zAxis=false, bool aboutOrigin=true)
Generates an image with axes flipped. Currently flips the y-axis as default, but can do other axes al...
Definition: milxImage.h:2501
void updateTrackedView(vtkObject *obj)
Updates the display of the slice in the window according to view tracking.
void done(int value)
Send signal that computation is done. Value carries the progress,.
void pseudoImage()
Converts the vector image to a pseudo-image, where each vector component is &#39;coloured&#39;.
vtkSmartPointer< vtkScalarBarActor > scale
Scale for the display.
void subsample(size_t xSampleFactor=0, size_t ySampleFactor=0, size_t zSampleFactor=0)
Downsamples current image by factors given.
static itk::SmartPointer< TImage > DuplicateImage(itk::SmartPointer< TImage > img)
Duplicates the image into a new image.
Definition: milxImage.h:1152
floatImageType::Pointer GetFloatImage()
Returns the internal float image data.
Definition: milxQtImage.h:416
void setView(int viewMode)
Change view to view mode identified by number. 0-axial, 1-coronal, 2-sagittal.
QAction * computeContourAct
Action for contouring image.
Definition: milxQtImage.h:1430
QAction * maskAct
Action for resampling image.
Definition: milxQtImage.h:1452
static itk::SmartPointer< TImage > ScaleVectorImage(itk::SmartPointer< TImage > img, float scaling, int numberOfComponents)
Scales each component of the vector image intensities by scaling factor and returns the result...
Definition: milxImage.h:2011
bool isRGBImage()
Returns true if image is an RGB (3-vector unsigned char image) image.
Definition: milxQtImage.h:574
QAction * polyDataAct
Action for image to poly data.
Definition: milxQtImage.h:1458
void flip(bool xAxis=false, bool yAxis=false, bool zAxis=false, bool aboutOrigin=true)
Flips the image and displays it. If all the arguments are false, then axes will be asked for using GU...
vtkSmartPointer< vtkSphereRepresentation > sphereRep
Sphere for widgets.
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...
void setDefaultView(int viewMode)
Change default view to view mode identified by number. 0-axial, 1-coronal, 2-sagittal.
static itk::SmartPointer< TImage > CannyEdges(itk::SmartPointer< TImage > img, float variance, float lowerThreshold, float upperThreshold)
Generates an Canny edge image from the input image.
Definition: milxImage.h:2343
void surface(const float value=numeric_limits< float >::max())
Converts the image to a surface using the Marching Cubes algorithm. Ideally suited for binary images...
vectorImageType::Pointer imageVector
Up to date vector image data.
Definition: milxQtImage.h:1403
static itk::SmartPointer< itk::Image< float, TImage::ImageDimension > > Normalization(itk::SmartPointer< TImage > img)
Generates an image which is statistically normalised so having pixel values between -1 and 1...
Definition: milxImage.h:2366
void add(milxQtImage *img)
Adds img to current image.
static itk::SmartPointer< TImage > BlankImage(typename TImage::PixelType value, typename TImage::SizeType imgSize)
Creates an empty image filled with value given.
Definition: milxImage.h:1277
void refresh()
Refresh the display of the model including widgets. Camera remains as is.
void gaussianSmooth()
Computes the Gaussian smoothing of the image and displays it.
void autoLevel(float percentile=0.99)
Auto window level the display. Uses Otsu threshold value.
void createConnections()
Create the connections for context menu etc.
intImageType::Pointer imageInt
Up to date 32-bit greyscale image data.
Definition: milxQtImage.h:1400
bool is8BitImage()
Returns true if image is an 8-bit (unsigned char) image.
Definition: milxQtImage.h:537
void printInfo(QString msg)
Info message wrapper for console.
bool useDefaultView
Using log scalar map?
void streamLines()
Converts the vector image to a series of stream lines which all start at the current slice being view...
vtkSmartPointer< vtkEventQtSlotConnect > Connector
VTK Events to slots convertor.
void SetIntensityWindow(double window)
Set the window for the image intensity tranfer function.
QAction * smoothAct
Action for smoothing of image.
Definition: milxQtImage.h:1431
static itk::SmartPointer< TImage > InvertIntensity(itk::SmartPointer< TImage > img, float maxValue)
Generates an image with the intensities reversed based on the max pixel value.
Definition: milxImage.h:2237
void subtract(milxQtImage *img)
Subtracts img from current image.
virtual void viewToXYPlane()
Change view to xy-plane.
bool volume
is the image a volume?
Definition: milxQtImage.h:1393
QAction * resampleLabelAct
Action for resampling image.
Definition: milxQtImage.h:1449
static itk::SmartPointer< TImage > Median(itk::SmartPointer< TImage > img, const int radius)
Generates the (non-linear) median filtering (smoothing) of an image of given neighbourhood radius...
Definition: milxImage.h:2637
void working(int value)
Send signal that computation is in progress. Value carries the progress,.
vtkSmartPointer< vtkScalarBarWidget > scalarBar
Scalar Bar Widget for the display.
void zeros(const unsigned long xSize, const unsigned long ySize, const unsigned long zSize, milxQtImage *refImage=NULL)
Creates image of zeros of size given.
int getView()
Return current view mode identified by number. 0-axial, 1-coronal, 2-sagittal.
void histogram(int bins=256, float belowValue=0, float aboveValue=255, bool plotHistogram=true)
Computes the histogram of the image and prints info found.
void setDefaultOrientation(int orientMode)
Change orientation mode to one of the supported standards. Default: Radiological. ...
QMenu * windowPropertiesMenu
Context Menu.
double GetIntensityWindow()
Get the window for the image intensity tranfer function.
void setSlice(int slice)
Sets the slice of the volume to slice value given.
void refresh()
Refresh display.
intImageType::Pointer GetIntImage()
Returns the internal unsigned char image data.
Definition: milxQtImage.h:400
QAction * surfaceAct
Action for image to surface.
Definition: milxQtImage.h:1457
QMenu * operationsMenu()
Return the operations menu with the milxQtImage class ordering. This is for the benefit of derived cl...
void tableToPlot(vtkSmartPointer< vtkTable >, QString)
Emit signal to show the table as a plot.
void imageToTensorField(vectorImageType::Pointer, floatImageType::Pointer, int, float)
Emit signal to compute image to tensor field process.
QStatusBar * updateBar
Pointer to bar, not allocated or deleted. To be passed to only.
QList< QMenu * > menusToAppend
Context Menu&#39;s to append.
Definition: milxQtWindow.h:255
static itk::SmartPointer< TImage > SubsampleImage(itk::SmartPointer< TImage > img, typename TImage::SizeType factors)
Subsamples or shrinks the current image using the factors provided.
Definition: milxImage.h:1459
QAction * vectorComponentAct
Action for displaying components of vector images.
Definition: milxQtImage.h:1470
QAction * loadViewAct
Load camera view.
ViewType viewToTrack
In tracking mode, what slice to show.
Definition: milxQtImage.h:1406
vtkSmartPointer< vtkPointPicker > dataPicker
For determining coordinates and points from the window.
void matchHistogram(milxQtImage *imageToMatch)
Matches the histogram of another image to the current image. See generateMatchedHistogram() for more ...
void disableOrient()
Disables orientation marker.
void otsu(int bins=0)
Otsu Threshold the image for all values between a band to a given level.
QAction * bilateralAct
Action for bilateral smoothing of image.
Definition: milxQtImage.h:1433
QMenu * operateMenu
Operate Menu.
Definition: milxQtImage.h:1427
void matchInfo(milxQtImage *imageToMatch)
Matches the info of another image to the current image. See generateMatchedInformation() for more inf...
void resampleLabel(QString filename="")
Resamples current image as a labelled image (toavoid interpolation artefacts) to another image...
bool isInterpolated()
Returns true if image display is interpolated.
Definition: milxQtImage.h:637
QAction * loadViewFileAct
Load camera view to file.
rgbImageType::Pointer imageRGB
Up to date 32-bit image data (used only internally atm)
Definition: milxQtImage.h:1401