18 #include "milxQtDiffusionTensorImage.h" 20 #include <vtkSphereSource.h> 22 #include <vtkFloatArray.h> 23 #include <vtkPolyDataNormals.h> 24 #include <vtkAppendPolyData.h> 26 #include "vtkDiffusionTensorGlyphFilter.h" 28 typedef vtkDiffusionTensorGlyphFilter::VectorImageType::SpacingType SpacingType;
30 void CalcGlyph(
void *arg)
36 std::cerr <<
"vtkDiffusionTensorGlyphFilter is not valid!" << std::endl;
40 std::vector<vectorImageType::IndexType> indices = glyphFilter->GetTensorImageIndices();
41 vtkDiffusionTensorGlyphFilter::VectorImageType::Pointer image = glyphFilter->GetTensorImage();
42 const vectorImageType::PixelType normVector = glyphFilter->GetNormaliseVector();
45 vectorImageType::IndexType index = indices[glyphFilter->GetPointId()];
47 const vectorImageType::PixelType harmonicsVector = image->GetPixel(index);
50 double radiusScaling = 2.5;
52 double pointCoords[3];
53 glyphFilter->GetPoint(pointCoords);
55 typedef double projectionType;
64 vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();
65 sphereSource->SetThetaResolution( glyphFilter->GetResolution() );
66 sphereSource->SetPhiResolution( glyphFilter->GetResolution() );
67 sphereSource->SetRadius( 1.0 );
68 sphereSource->Update();
69 vtkSmartPointer<vtkPolyData> glyph = sphereSource->GetOutput();
71 vtkSmartPointer<vtkFloatArray> projections = vtkSmartPointer<vtkFloatArray>::New();
72 projections->SetNumberOfComponents(3);
73 projections->SetNumberOfTuples(glyph->GetNumberOfPoints());
74 projections->SetName(
"Fibre Projections");
75 projections->FillComponent(0, 0.0);
76 projections->FillComponent(1, 0.0);
77 projections->FillComponent(2, 0.0);
80 double m_x = pointCoords[0], m_y = pointCoords[1], m_z = pointCoords[2];
81 for(vtkIdType i = 0; i < glyph->GetNumberOfPoints(); i ++)
83 double point_sphere[3];
84 glyph->GetPoint(i, point_sphere);
85 const double x_s = point_sphere[0];
86 const double y_s = point_sphere[1];
87 const double z_s = point_sphere[2];
90 std::vector<double> sHarmonicCoefficients;
91 for(
size_t j = 0; j < harmonicsVector.GetSize(); j ++)
92 sHarmonicCoefficients.push_back(harmonicsVector[j]/normVector[j]);
95 const int n_coefs = sHarmonicCoefficients.size();
96 const int l_max = vtkDiffusionTensorGlyphFilter::LforN( n_coefs );
97 double amplitude = vtkDiffusionTensorGlyphFilter::computeAmplitude( sHarmonicCoefficients, x_s, y_s, z_s, l_max );
104 double x_g = x_s * amplitude * radiusScaling;
105 double y_g = y_s * amplitude * radiusScaling;
106 double z_g = z_s * amplitude * radiusScaling;
108 glyph->GetPoints()->SetPoint(i, x_g, y_g, z_g);
111 for(
size_t j = 0; j < 3; j ++)
113 projectionType axis[3] = {0.0, 0.0, 0.0};
114 coordinate currentProjection(projections->GetTuple3(i)), position(glyph->GetPoint(i));
117 projectionType projection = vtkMath::Dot(axis, position.data_block());
118 currentProjection[j] = projection;
120 projections->SetTuple3(i, static_cast<float>(currentProjection[0])
121 , static_cast<float>(currentProjection[1])
122 , static_cast<float>(currentProjection[2]));
129 glyph->GetPoints()->SetPoint(i, x_g, y_g, z_g);
131 qApp->processEvents();
135 vtkSmartPointer<vtkUnsignedCharArray> scalars = vtkSmartPointer<vtkUnsignedCharArray>::New();
136 scalars->SetNumberOfComponents(3);
137 scalars->SetNumberOfTuples(glyph->GetNumberOfPoints());
138 scalars->SetName(
"Colours");
139 scalars->FillComponent(0, 0);
140 scalars->FillComponent(1, 0);
141 scalars->FillComponent(2, 0);
142 for(vtkIdType i = 0; i < glyph->GetNumberOfPoints(); i ++)
144 coordinate currentProjection(projections->GetTuple3(i));
145 coordinate currentProjSquared = element_product(currentProjection, currentProjection);
146 projectionType maxProjection = currentProjSquared.max_value();
147 currentProjSquared /= maxProjection;
149 unsigned char colourOfPoint[3] = {0, 0, 0};
150 colourOfPoint[0] =
static_cast<unsigned char>( currentProjSquared[0]*255.0 );
151 colourOfPoint[1] =
static_cast<unsigned char>( currentProjSquared[1]*255.0 );
152 colourOfPoint[2] =
static_cast<unsigned char>( currentProjSquared[2]*255.0 );
154 scalars->SetTupleValue(i, colourOfPoint);
156 qApp->processEvents();
159 glyph->GetPointData()->SetScalars(scalars);
162 vtkSmartPointer< vtkPolyDataNormals > normals = vtkSmartPointer< vtkPolyDataNormals >::New();
163 #if VTK_MAJOR_VERSION <= 5 164 normals->SetInput(glyph);
166 normals->SetInputData(glyph);
168 normals->ComputePointNormalsOn();
169 normals->SplittingOff();
170 normals->ComputeCellNormalsOff();
173 #if VTK_MAJOR_VERSION <= 5 174 glyphFilter->SetSource(normals->GetOutput());
176 glyphFilter->SetSourceConnection(normals->GetOutputPort());
180 milxQtDiffusionTensorImage::milxQtDiffusionTensorImage(QWidget *theParent) :
milxQtImage(theParent)
189 milxQtDiffusionTensorImage::~milxQtDiffusionTensorImage()
196 if(ITK_VERSION_MAJOR < 4 || VTK_MAJOR_VERSION < 6)
198 printError(
"You are not using ITK 4 or above OR VTK 6 or above. Ignoring.");
202 printDebug(
"Computing Diffusion Glyphs");
204 bool ok1 =
false, ok2 =
false;
205 if(subsampleFactor == 0)
207 subsampleFactor = QInputDialog::getInt(
this, tr(
"Please Provide the sub-sample factor of the data"),
208 tr(
"Sub-sample Factor:"), 1, 1, 1000, 1, &ok1);
209 resolution = QInputDialog::getInt(
this, tr(
"Please Provide the resolution of the glyphs"),
210 tr(
"Resolution:"), 16, 4, 256, 1, &ok2);
223 if(extent[3]-extent[2] == 0)
225 extent[2] = actualExtent[3]-extent[2];
226 extent[3] = actualExtent[3]-extent[3];
235 vectorImageType::SizeType imageSize = sliceVector->GetLargestPossibleRegion().GetSize();
236 size_t sliceDimension = 0;
237 for(
size_t j = 0; j < vectorImageType::ImageDimension; j ++)
239 if(imageSize[j] == 1)
244 vectorImageType::SizeType sliceSubsampleSizes;
245 sliceSubsampleSizes.Fill(subsampleFactor);
246 sliceSubsampleSizes[sliceDimension] = 1;
249 const size_t components = milxQtImage::imageVector->GetNumberOfComponentsPerPixel();
251 cout <<
"Slice Information: " << endl;
255 printDebug(
"Setting up seed points for glyphs using the current slice");
256 vtkSmartPointer<vtkPoints> slicePoints = vtkSmartPointer<vtkPoints>::New();
257 typedef itk::Point<double, 3> InputImagePointType;
258 itk::ImageRegionConstIteratorWithIndex<vectorImageType> imageIterator(imgSubSampled, imgSubSampled->GetLargestPossibleRegion());
261 std::vector<vectorImageType::IndexType> indices;
264 InputImagePointType point;
265 vectorImageType::PixelType maxVector(components);
267 while(!imageIterator.IsAtEnd())
271 imgSubSampled->TransformIndexToPhysicalPoint(imageIterator.GetIndex(), point);
273 position[0] = point[0];
274 position[1] = point[1];
275 position[2] = point[2];
277 slicePoints->InsertNextPoint(position);
278 indices.push_back(imageIterator.GetIndex());
280 vectorImageType::PixelType pixelVector = imageIterator.Get();
281 for(
size_t j = 0; j < pixelVector.GetSize(); j ++)
283 if(maxVector[j] < pixelVector[j])
284 maxVector[j] = pixelVector[j];
289 cout <<
"Max Vector found: " << maxVector << endl;
290 cout <<
"ID Type Size: " <<
sizeof(vtkIdType) << endl;
291 cout <<
"Integer Type Size: " <<
sizeof(unsigned) << endl;
299 vtkSmartPointer<vtkPolyData> slice = vtkSmartPointer<vtkPolyData>::New();
300 slice->SetPoints(slicePoints);
303 vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();
304 sphereSource->SetThetaResolution( resolution );
305 sphereSource->SetPhiResolution( resolution );
306 sphereSource->SetRadius( 1.0 );
307 sphereSource->Update();
308 vtkSmartPointer<vtkUnsignedCharArray> scalars = vtkSmartPointer<vtkUnsignedCharArray>::New();
309 scalars->SetNumberOfComponents(3);
310 scalars->SetNumberOfTuples(sphereSource->GetOutput()->GetNumberOfPoints());
311 scalars->SetName(
"Dummy Colours");
312 scalars->FillComponent(0, 0);
313 scalars->FillComponent(1, 0);
314 scalars->FillComponent(2, 0);
315 sphereSource->GetOutput()->GetPointData()->SetScalars(scalars);
316 vtkSmartPointer< vtkPolyDataNormals > normals = vtkSmartPointer< vtkPolyDataNormals >::New();
317 #if VTK_MAJOR_VERSION <= 5 318 normals->SetInput(sphereSource->GetOutput());
320 normals->SetInputData(sphereSource->GetOutput());
322 normals->ComputePointNormalsOn();
323 normals->SplittingOff();
324 normals->ComputeCellNormalsOff();
327 vtkSmartPointer<vtkDiffusionTensorGlyphFilter> diffusionTensorGlyphs = vtkSmartPointer<vtkDiffusionTensorGlyphFilter>::New();
328 #if VTK_MAJOR_VERSION <= 5 329 diffusionTensorGlyphs->SetInput(slice);
330 diffusionTensorGlyphs->SetSource(normals->GetOutput());
332 diffusionTensorGlyphs->SetInputData(slice);
333 diffusionTensorGlyphs->SetSourceData(normals->GetOutput());
335 diffusionTensorGlyphs->SetTensorImage(sliceVector);
336 diffusionTensorGlyphs->SetTensorImageIndices(indices);
337 diffusionTensorGlyphs->SetNormaliseVector(maxVector);
338 diffusionTensorGlyphs->SetResolution(resolution);
339 diffusionTensorGlyphs->SetGlyphMethod(CalcGlyph, diffusionTensorGlyphs);
340 linkProgressEventOf(diffusionTensorGlyphs);
341 printDebug(
"Creating Glyphs");
342 diffusionTensorGlyphs->SetColorModeToColorBySource();
343 diffusionTensorGlyphs->Update();
346 model->
setName(
"Diffusion Glyphs");
347 model->SetInput(diffusionTensorGlyphs->GetOutput());
348 model->generateModel();
349 model->ImmediateModeRenderingOn();
357 if(ITK_VERSION_MAJOR < 4)
359 printError(
"You are not using ITK 4 or above. Ignoring.");
363 printDebug(
"Computing Diffusion Glyphs via Brute Force");
365 bool ok1 =
false, ok2 =
false;
366 if(subsampleFactor == 0)
368 subsampleFactor = QInputDialog::getInt(
this, tr(
"Please Provide the sub-sample factor of the data"),
369 tr(
"Sub-sample Factor:"), 1, 1, 1000, 1, &ok1);
370 resolution = QInputDialog::getInt(
this, tr(
"Please Provide the resolution of the glyphs"),
371 tr(
"Resolution:"), 16, 4, 256, 1, &ok2);
384 if(extent[3]-extent[2] == 0)
386 extent[2] = actualExtent[3]-extent[2];
387 extent[3] = actualExtent[3]-extent[3];
396 vectorImageType::SizeType imageSize = sliceVector->GetLargestPossibleRegion().GetSize();
397 size_t sliceDimension = 0;
398 for(
size_t j = 0; j < vectorImageType::ImageDimension; j ++)
400 if(imageSize[j] == 1)
405 vectorImageType::SizeType sliceSubsampleSizes;
406 sliceSubsampleSizes.Fill(subsampleFactor);
407 sliceSubsampleSizes[sliceDimension] = 1;
410 const size_t components = milxQtImage::imageVector->GetNumberOfComponentsPerPixel();
412 cout <<
"Slice Information: " << endl;
414 typedef float projectionType;
417 printDebug(
"Setting up seed points for glyphs using the current slice");
418 typedef itk::Point<double, 3> InputImagePointType;
419 itk::ImageRegionConstIteratorWithIndex<vectorImageType> imageIterator(imgSubSampled, imgSubSampled->GetLargestPossibleRegion());
421 vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();
422 sphereSource->SetThetaResolution( resolution );
423 sphereSource->SetPhiResolution( resolution );
424 sphereSource->SetRadius( 1.0 );
425 sphereSource->Update();
426 sphereSource->GetOutput()->GetPointData()->RemoveArray(
"Normals");
429 vtkSmartPointer<vtkAppendPolyData> appendedPolyData = vtkSmartPointer<vtkAppendPolyData>::New();
430 InputImagePointType point;
431 const double radiusScaling = 2.5;
434 while(!imageIterator.IsAtEnd())
436 imgSubSampled->TransformIndexToPhysicalPoint(imageIterator.GetIndex(), point);
438 const vectorImageType::PixelType harmonicsVector = imageIterator.Get();
447 vtkSmartPointer<vtkPolyData> glyph = vtkSmartPointer<vtkPolyData>::New();
448 glyph->DeepCopy(sphereSource->GetOutput());
450 vtkSmartPointer<vtkFloatArray> projections = vtkSmartPointer<vtkFloatArray>::New();
451 projections->SetNumberOfComponents(3);
452 projections->SetNumberOfTuples(glyph->GetNumberOfPoints());
453 projections->SetName(
"Fibre Projections");
454 projections->FillComponent(0, 0.0);
455 projections->FillComponent(1, 0.0);
456 projections->FillComponent(2, 0.0);
459 double m_x = point[0], m_y = point[1], m_z = point[2];
460 for(vtkIdType i = 0; i < glyph->GetNumberOfPoints(); i ++)
462 double point_sphere[3];
463 glyph->GetPoint(i, point_sphere);
464 const double x_s = point_sphere[0];
465 const double y_s = point_sphere[1];
466 const double z_s = point_sphere[2];
469 std::vector<double> sHarmonicCoefficients;
470 for(
size_t j = 0; j < harmonicsVector.GetSize(); j ++)
471 sHarmonicCoefficients.push_back(harmonicsVector[j]);
474 const int n_coefs = sHarmonicCoefficients.size();
475 const int l_max = vtkDiffusionTensorGlyphFilter::LforN( n_coefs );
476 double amplitude = vtkDiffusionTensorGlyphFilter::computeAmplitude( sHarmonicCoefficients, x_s, y_s, z_s, l_max );
483 double x_g = x_s * amplitude * radiusScaling;
484 double y_g = y_s * amplitude * radiusScaling;
485 double z_g = z_s * amplitude * radiusScaling;
487 glyph->GetPoints()->SetPoint(i, x_g, y_g, z_g);
490 for(
size_t j = 0; j < 3; j ++)
492 projectionType axis[3] = {0.0, 0.0, 0.0};
493 const projectionType position[3] = {glyph->GetPoint(i)[0], glyph->GetPoint(i)[1], glyph->GetPoint(i)[2]};
494 projectionType currentProjection[3] = {projections->GetTuple3(i)[0], projections->GetTuple3(i)[1], projections->GetTuple3(i)[2]};
497 const projectionType projection = vtkMath::Dot(axis, position);
498 currentProjection[j] = projection;
500 projections->SetTuple3(i, currentProjection[0], currentProjection[1], currentProjection[2]);
507 glyph->GetPoints()->SetPoint(i, x_g, y_g, z_g);
509 qApp->processEvents();
513 vtkSmartPointer<vtkUnsignedCharArray> scalars = vtkSmartPointer<vtkUnsignedCharArray>::New();
514 scalars->SetNumberOfComponents(3);
515 scalars->SetNumberOfTuples(glyph->GetNumberOfPoints());
516 scalars->SetName(
"Colours");
517 scalars->FillComponent(0, 0);
518 scalars->FillComponent(1, 0);
519 scalars->FillComponent(2, 0);
521 for(vtkIdType i = 0; i < glyph->GetNumberOfPoints(); i ++)
523 coordinate currentProjection(projections->GetTuple3(i));
524 coordinate currentProjSquared = element_product(currentProjection, currentProjection);
525 projectionType maxProjection = currentProjSquared.max_value();
526 currentProjSquared /= maxProjection;
528 unsigned char colourOfPoint[3] = {0, 0, 0};
529 colourOfPoint[0] =
static_cast<unsigned char>( currentProjSquared[0]*255.0 );
530 colourOfPoint[1] =
static_cast<unsigned char>( currentProjSquared[1]*255.0 );
531 colourOfPoint[2] =
static_cast<unsigned char>( currentProjSquared[2]*255.0 );
533 scalars->SetTupleValue(i, colourOfPoint);
535 qApp->processEvents();
538 glyph->GetPointData()->SetScalars(scalars);
540 #if VTK_MAJOR_VERSION <= 5 541 appendedPolyData->AddInput(glyph);
543 appendedPolyData->AddInputData(glyph);
548 cout <<
"Updating Polydata" << endl;
549 appendedPolyData->Update();
552 model->
SetInput(appendedPolyData->GetOutput());
553 model->setName(
"Diffusion Glyphs");
554 model->generateModel();
555 model->ImmediateModeRenderingOn();
561 void milxQtDiffusionTensorImage::createActions()
563 diffusionAct =
new QAction(
this);
564 diffusionAct->setText(QApplication::translate(
"Model",
"Diffusion Glyphs for Slice", 0, QApplication::UnicodeUTF8));
565 diffusionAct->setShortcut(tr(
"Shift+Alt+d"));
566 diffusion2Act =
new QAction(
this);
567 diffusion2Act->setText(QApplication::translate(
"Model",
"Diffusion Glyphs for Slice Brute Force", 0, QApplication::UnicodeUTF8));
568 diffusion2Act->setShortcut(tr(
"Ctrl+Shift+d"));
571 void milxQtDiffusionTensorImage::createConnections()
574 connect(diffusionAct, SIGNAL(triggered()),
this, SLOT(diffusionGlyphs()));
575 connect(diffusion2Act, SIGNAL(triggered()),
this, SLOT(diffusionGlyphs2()));
580 void milxQtDiffusionTensorImage::contextMenuEvent(QContextMenuEvent *currentEvent)
584 contextMenu->addSeparator()->setText(tr(
"Diffusion Tensor"));
585 contextMenu->addAction(diffusionAct);
586 contextMenu->addAction(diffusion2Act);
587 contextMenu->addSeparator()->setText(tr(
"Extensions"));
588 foreach(QAction *currAct, extActionsToAdd)
590 contextMenu->addAction(currAct);
592 contextMenu->addSeparator();
599 contextMenu->exec(currentEvent->globalPos());
vtkSmartPointer< vtkImageData > imageData
Points to the current VTK Image Data, Smart Pointer.
QMenu * basicContextMenu()
Return the basic context menu with the milxQtImage class ordering. This is for the benefit of derived...
void setName(const QString filename)
Set the name of the data.
vtkSmartPointer< vtkImageViewer3 > viewer
VTK Viewer handler, Smart Pointer.
This class represents the MILX Qt Image Display object using VTK.
void done(int value)
Send signal that computation is done. Value carries the progress,.
void SetInput(vtkSmartPointer< vtkPolyData > mesh)
Assigns the mesh provided to the class, preparing for display. Call generateModel() and then show() t...
void resultAvailable(milxQtRenderWindow *)
Send signal that Resultant render window is available for showing.
QString prefix
Prefix of the data.
This class represents the MILX Qt Model/Mesh Display object using VTK.
void working(int value)
Send signal that computation is in progress. Value carries the progress,.
QAction * refreshAct
Action for refreshing the display.
Represents an image (i.e. an regular rectangular array with scalar values) and their common operation...
QMenu * contourMenu
Contour Menu.
QAction * resetAct
Action for refreshing the display.
void diffusionGlyphs(size_t subsampleFactor=0, size_t resolution=16)
static void Information(itk::SmartPointer< TImage > img)
Prints the information of the image to standard output.
vectorImageType::Pointer imageVector
Up to date vector image data.
QMenu * windowPropertiesMenu
Context Menu.
static itk::SmartPointer< TImage > SubsampleImage(itk::SmartPointer< TImage > img, typename TImage::SizeType factors)
Subsamples or shrinks the current image using the factors provided.
void diffusionGlyphs2(size_t subsampleFactor=0, size_t resolution=16)