Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
QmitkTbssRoiAnalysisWidget.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
19 #include "mitkPixelTypeMultiplex.h"
20 
21 #include <qwt_plot_marker.h>
22 #include <qwt_plot_picker.h>
23 #include <qwt_picker_machine.h>
24 
25 #include <vtkCellArray.h>
26 
28  : QmitkPlotWidget(parent)
29 {
30  m_PlotPicker = new QwtPlotPicker(m_Plot->canvas());
31  m_PlotPicker->setStateMachine(new QwtPickerDragPointMachine());
32  m_PlotPicker->setTrackerMode(QwtPicker::ActiveOnly);
33 
34  m_PlottingFiberBundle = false;
35 }
36 
37 
38 
40  mitk::DataNode* startRoi, mitk::DataNode* endRoi, bool avg, int number)
41 {
42 
43  TractContainerType tracts = CreateTracts(fib, startRoi, endRoi);
44 
45  TractContainerType resampledTracts = ParameterizeTracts(tracts, number);
46 
47  // Now we have the resampled tracts. Next we should use these points to read out the values
48 
49 
50 
51  mitkPixelTypeMultiplex3(PlotFiberBundles,img->GetImageDescriptor()->GetChannelTypeById(0),resampledTracts, img, avg);
52  m_CurrentTracts = resampledTracts;
53 }
54 
55 
57  mitk::DataNode *startRoi,
58  mitk::DataNode *endRoi)
59 {
60  mitk::PlaneGeometry* startGeometry2D = const_cast<mitk::PlaneGeometry*>(dynamic_cast<mitk::PlanarFigure*>(startRoi->GetData())->GetPlaneGeometry());
61  mitk::PlaneGeometry* endGeometry2D = const_cast<mitk::PlaneGeometry*>(dynamic_cast<mitk::PlanarFigure*>(endRoi->GetData())->GetPlaneGeometry());
62 
63 
64  mitk::Point3D startCenter = dynamic_cast<mitk::PlanarFigure*>(startRoi->GetData())->GetWorldControlPoint(0); //center Point of start roi
65  mitk::Point3D endCenter = dynamic_cast<mitk::PlanarFigure*>(startRoi->GetData())->GetWorldControlPoint(0); //center Point of end roi
66 
67  mitk::FiberBundle::Pointer inStart = fib->ExtractFiberSubset(startRoi, nullptr);
68  mitk::FiberBundle::Pointer inBoth = inStart->ExtractFiberSubset(endRoi, nullptr);
69 
70 
71 
72  int num = inBoth->GetNumFibers();
73 
74 
75  TractContainerType tracts;
76 
77 
78  vtkSmartPointer<vtkPolyData> fiberPolyData = inBoth->GetFiberPolyData();
79  vtkCellArray* lines = fiberPolyData->GetLines();
80  lines->InitTraversal();
81 
82 
83 
84  // Now find out for each fiber which ROI is encountered first. If this is the startRoi, the direction is ok
85  // Otherwise the plot should be in the reverse direction
86  for( int fiberID( 0 ); fiberID < num; fiberID++ )
87  {
88  vtkIdType numPointsInCell(0);
89  vtkIdType* pointsInCell(nullptr);
90  lines->GetNextCell ( numPointsInCell, pointsInCell );
91 
92  int startId = 0;
93  int endId = 0;
94 
97 
98 
99 
100  for( int pointInCellID( 0 ); pointInCellID < numPointsInCell ; pointInCellID++)
101  {
102 
103 
104  mitk::ScalarType *p = fiberPolyData->GetPoint( pointsInCell[ pointInCellID ] );
105 
106  mitk::Point3D point;
107  point[0] = p[0];
108  point[1] = p[1];
109  point[2] = p[2];
110 
111  mitk::ScalarType distanceToStart = point.EuclideanDistanceTo(startCenter);
112  mitk::ScalarType distanceToEnd = point.EuclideanDistanceTo(endCenter);
113 
114  if(distanceToStart < minDistStart)
115  {
116  minDistStart = distanceToStart;
117  startId = pointInCellID;
118  }
119 
120  if(distanceToEnd < minDistEnd)
121  {
122  minDistEnd = distanceToEnd;
123  endId = pointInCellID;
124  }
125 
126 
127 
128  }
129 
130  /* We found the start and end points of of the part that should be plottet for
131  the current fiber. now we need to plot them. If the endId is smaller than the startId the plot order
132  must be reversed*/
133 
134  TractType singleTract;
135  PointType point;
136 
137  if(startId < endId)
138  {
139 
140  // Calculate the intersection of the ROI with the startRoi and decide if the startId is part of the roi or must be cut of
141  mitk::ScalarType *p = fiberPolyData->GetPoint( pointsInCell[ startId ] );
142  mitk::Vector3D p0;
143  p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2];
144 
145  p = fiberPolyData->GetPoint( pointsInCell[ startId+1 ] );
146  mitk::Vector3D p1;
147  p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2];
148 
149  // Check if p and p2 are both on the same side of the plane
150  mitk::Vector3D normal = startGeometry2D->GetNormal();
151 
152  mitk::Point3D pStart;
153  pStart[0] = p0[0]; pStart[1] = p0[1]; pStart[2] = p0[2];
154 
155  mitk::Point3D pSecond;
156  pSecond[0] = p1[0]; pSecond[1] = p1[1]; pSecond[2] = p1[2];
157 
158  bool startOnPositive = startGeometry2D->IsAbove(pStart);
159  bool secondOnPositive = startGeometry2D->IsAbove(pSecond);
160 
161 
162  mitk::Vector3D onPlane;
163  onPlane[0] = startCenter[0]; onPlane[1] = startCenter[1]; onPlane[2] = startCenter[2];
164 
165 
166 
167  if(! (secondOnPositive ^ startOnPositive) )
168  {
169  /* startId and startId+1 lie on the same side of the plane, so we need
170  need startId-1 to calculate the intersection with the planar figure*/
171  p = fiberPolyData->GetPoint( pointsInCell[ startId-1 ] );
172  p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2];
173  }
174 
175 
176  mitk::ScalarType d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal );
177  mitk::Vector3D newPoint = (p0-p1);
178 
179  point[0] = d*newPoint[0] + p0[0];
180  point[1] = d*newPoint[1] + p0[1];
181  point[2] = d*newPoint[2] + p0[2];
182 
183  singleTract.push_back(point);
184 
185  if(! (secondOnPositive ^ startOnPositive) )
186  {
187  /* StartId and startId+1 lie on the same side of the plane
188  so startId is also part of the ROI*/
189 
190  mitk::ScalarType *start = fiberPolyData->GetPoint( pointsInCell[startId] );
191  point[0] = start[0]; point[1] = start[1]; point[2] = start[2];
192  singleTract.push_back(point);
193  }
194 
195 
196 
197  for( int pointInCellID( startId+1 ); pointInCellID < endId ; pointInCellID++)
198  {
199  // push back point
200  mitk::ScalarType *p = fiberPolyData->GetPoint( pointsInCell[ pointInCellID ] );
201  point[0] = p[0]; point[1] = p[1]; point[2] = p[2];
202  singleTract.push_back( point );
203 
204  }
205 
206  /* endId must be included if endId and endId-1 lie on the same side of the
207  plane defined by endRoi*/
208 
209 
210  p = fiberPolyData->GetPoint( pointsInCell[ endId ] );
211  p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2];
212 
213  p = fiberPolyData->GetPoint( pointsInCell[ endId-1 ] );
214  p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2];
215 
216  mitk::Point3D pLast;
217  pLast[0] = p0[0]; pLast[1] = p0[1]; pLast[2] = p0[2];
218 
219  mitk::Point3D pBeforeLast;
220  pBeforeLast[0] = p1[0]; pBeforeLast[1] = p1[1]; pBeforeLast[2] = p1[2];
221 
222  normal = endGeometry2D->GetNormal();
223  bool lastOnPositive = endGeometry2D->IsAbove(pLast);
224  bool secondLastOnPositive = endGeometry2D->IsAbove(pBeforeLast);
225 
226 
227  onPlane[0] = endCenter[0];
228  onPlane[1] = endCenter[1];
229  onPlane[2] = endCenter[2];
230 
231  if(! (lastOnPositive ^ secondLastOnPositive) )
232  {
233  /* endId and endId-1 lie on the same side of the plane, so we need
234  need endId+1 to calculate the intersection with the planar figure.
235  this should exist since we know that the fiber crosses the planar figure
236  endId is also part of the tract and can be inserted here */
237 
238  p = fiberPolyData->GetPoint( pointsInCell[ endId ] );
239  point[0] = p[0]; point[1] = p[1]; point[2] = p[2];
240  singleTract.push_back( point );
241 
242  p = fiberPolyData->GetPoint( pointsInCell[ endId+1 ] );
243  }
244 
245  d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal );
246 
247  newPoint = (p0-p1);
248 
249  point[0] = d*newPoint[0] + p0[0];
250  point[1] = d*newPoint[1] + p0[1];
251  point[2] = d*newPoint[2] + p0[2];
252 
253  singleTract.push_back(point);
254 
255 
256 
257  }
258  else{
259 
260  // Calculate the intersection of the ROI with the startRoi and decide if the startId is part of the roi or must be cut of
261  mitk::ScalarType *p = fiberPolyData->GetPoint( pointsInCell[ startId ] );
262  mitk::Vector3D p0;
263  p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2];
264 
265  p = fiberPolyData->GetPoint( pointsInCell[ startId-1 ] );
266  mitk::Vector3D p1;
267  p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2];
268 
269  // Check if p and p2 are both on the same side of the plane
270  mitk::Vector3D normal = startGeometry2D->GetNormal();
271 
272  mitk::Point3D pStart;
273  pStart[0] = p0[0]; pStart[1] = p0[1]; pStart[2] = p0[2];
274 
275  mitk::Point3D pSecond;
276  pSecond[0] = p1[0]; pSecond[1] = p1[1]; pSecond[2] = p1[2];
277 
278  bool startOnPositive = startGeometry2D->IsAbove(pStart);
279  bool secondOnPositive = startGeometry2D->IsAbove(pSecond);
280 
281  mitk::Vector3D onPlane;
282  onPlane[0] = startCenter[0]; onPlane[1] = startCenter[1]; onPlane[2] = startCenter[2];
283 
284 
285  if(! (secondOnPositive ^ startOnPositive) )
286  {
287  /* startId and startId+1 lie on the same side of the plane, so we need
288  need startId-1 to calculate the intersection with the planar figure*/
289  p = fiberPolyData->GetPoint( pointsInCell[ startId-1 ] );
290  p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2];
291  }
292 
293 
294  mitk::ScalarType d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal );
295  mitk::Vector3D newPoint = (p0-p1);
296 
297 
298  point[0] = d*newPoint[0] + p0[0];
299  point[1] = d*newPoint[1] + p0[1];
300  point[2] = d*newPoint[2] + p0[2];
301 
302 
303  singleTract.push_back(point);
304 
305  if(! (secondOnPositive ^ startOnPositive) )
306  {
307  /* StartId and startId+1 lie on the same side of the plane
308  so startId is also part of the ROI*/
309 
310  mitk::ScalarType *start = fiberPolyData->GetPoint( pointsInCell[startId] );
311  point[0] = start[0]; point[1] = start[1]; point[2] = start[2];
312  singleTract.push_back(point);
313  }
314 
315 
316 
317  for( int pointInCellID( startId-1 ); pointInCellID > endId ; pointInCellID--)
318  {
319  // push back point
320  mitk::ScalarType *p = fiberPolyData->GetPoint( pointsInCell[ pointInCellID ] );
321  point[0] = p[0]; point[1] = p[1]; point[2] = p[2];
322  singleTract.push_back( point );
323 
324  }
325 
326  /* endId must be included if endId and endI+1 lie on the same side of the
327  plane defined by endRoi*/
328 
329 
330  p = fiberPolyData->GetPoint( pointsInCell[ endId ] );
331  p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2];
332 
333  p = fiberPolyData->GetPoint( pointsInCell[ endId+1 ] );
334  p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2];
335 
336  mitk::Point3D pLast;
337  pLast[0] = p0[0]; pLast[1] = p0[1]; pLast[2] = p0[2];
338 
339  mitk::Point3D pBeforeLast;
340  pBeforeLast[0] = p1[0]; pBeforeLast[1] = p1[1]; pBeforeLast[2] = p1[2];
341 
342  bool lastOnPositive = endGeometry2D->IsAbove(pLast);
343  bool secondLastOnPositive = endGeometry2D->IsAbove(pBeforeLast);
344  normal = endGeometry2D->GetNormal();
345 
346 
347 
348  onPlane[0] = endCenter[0];
349  onPlane[1] = endCenter[1];
350  onPlane[2] = endCenter[2];
351 
352  if(! (lastOnPositive ^ secondLastOnPositive) )
353  {
354  /* endId and endId+1 lie on the same side of the plane, so we need
355  need endId-1 to calculate the intersection with the planar figure.
356  this should exist since we know that the fiber crosses the planar figure
357  endId is also part of the tract and can be inserted here */
358 
359  p = fiberPolyData->GetPoint( pointsInCell[ endId ] );
360  point[0] = p[0]; point[1] = p[1]; point[2] = p[2];
361  singleTract.push_back( point );
362 
363  p = fiberPolyData->GetPoint( pointsInCell[ endId-1 ] );
364  }
365 
366  d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal );
367 
368  newPoint = (p0-p1);
369 
370  point[0] = d*newPoint[0] + p0[0];
371  point[1] = d*newPoint[1] + p0[1];
372  point[2] = d*newPoint[2] + p0[2];
373 
374  singleTract.push_back(point);
375 
376  }
377 
378 
379  tracts.push_back(singleTract);
380 
381 
382  }
383 
384  return tracts;
385 }
386 
388  mitk::DataNode* startRoi, mitk::DataNode* endRoi, bool avg, int number)
389 {
390 
391  if(fib == nullptr || img == nullptr || startRoi == nullptr || endRoi == nullptr)
392  return;
393 
394 
395  m_Fib = fib;
396  m_CurrentImage = img;
397  m_CurrentStartRoi = startRoi;
398  m_CurrentEndRoi = endRoi;
399 
400 
401  DoPlotFiberBundles(fib, img, startRoi, endRoi, avg, number);
402 }
403 
404 
405 
406 void QmitkTbssRoiAnalysisWidget::ModifyPlot(int number, bool avg)
407 {
408  if(m_Fib == nullptr || m_CurrentTbssImage == nullptr || m_CurrentStartRoi == nullptr || m_CurrentEndRoi == nullptr)
409  return;
410 
412  {
414  }
415  else
416  {
418  }
419 }
420 
421 
422 
424 {
425  TractContainerType resampledTracts;
426 
427 
428 
429  for(auto it = tracts.begin(); it != tracts.end(); ++it)
430  {
431  TractType resampledTract;
432  TractType tract = *it;
433 
434  // Calculate the total length
435  mitk::ScalarType totalLength = 0;
436 
437  if(tract.size() < 2)
438  continue;
439 
440  PointType p0 = tract.at(0);
441  for(unsigned int i = 1; i<tract.size(); i++)
442  {
443  PointType p1 = tract.at(i);
444  mitk::ScalarType length = p0.EuclideanDistanceTo(p1);
445  totalLength += length;
446  p0 = p1;
447  }
448 
449  mitk::ScalarType stepSize = totalLength / number;
450 
451 
452 
453  p0 = tract.at(0);
454  PointType p1 = tract.at(1);
455  unsigned int tractCounter = 2;
456  mitk::ScalarType distance = p0.EuclideanDistanceTo(p1);
457  mitk::ScalarType locationBetween = 0;
458 
459  for(mitk::ScalarType position = 0;
460  position <= totalLength+0.001 && resampledTract.size() <= (number+1);
461  position+=stepSize)
462  {
463 
464  /* In case we walked to far we need to find the next segment we are on and on what relative position on that
465  tract we are on. Small correction for rounding errors */
466  while(locationBetween > distance+0.001)
467  {
468 
469  if(tractCounter == tract.size())
470  std::cout << "problem";
471 
472  // Determine by what distance we are no on the next segment
473  locationBetween = locationBetween - distance;
474  p0 = p1;
475  p1 = tract.at(tractCounter);
476  tractCounter++;
477 
478  distance = p0.EuclideanDistanceTo(p1);
479 
480  }
481 
482  // Direction
483  PointType::VectorType direction = p1-p0;
484  direction.Normalize();
485 
486  PointType newSample = p0 + direction*locationBetween;
487  resampledTract.push_back(newSample);
488 
489 
490  locationBetween += stepSize;
491 
492 
493  }
494 
495  resampledTracts.push_back(resampledTract);
496 
497 
498  }
499  return resampledTracts;
500 }
501 
502 
504 {
505 
506 
507  mitk::ScalarType xSum = 0.0;
508  mitk::ScalarType ySum = 0.0;
509  mitk::ScalarType zSum = 0.0;
510  for(auto it = m_CurrentTracts.begin();
511  it!=m_CurrentTracts.end(); ++it)
512  {
513  TractType tract = *it;
514  PointType p = tract.at(index);
515  xSum += p[0];
516  ySum += p[1];
517  zSum += p[2];
518  }
519 
520  int number = m_CurrentTracts.size();
521 
522  mitk::ScalarType xPos = xSum / number;
523  mitk::ScalarType yPos = ySum / number;
524  mitk::ScalarType zPos = zSum / number;
525 
526 
527  mitk::Point3D pos;
528  pos[0] = xPos;
529  pos[1] = yPos;
530  pos[2] = zPos;
531 
532  return pos;
533 }
534 
535 
536 std::vector< std::vector<mitk::ScalarType> > QmitkTbssRoiAnalysisWidget::CalculateGroupProfiles()
537 {
538  MITK_INFO << "make profiles!";
539  std::vector< std::vector<mitk::ScalarType> > profiles;
540 
541 
542  int size = m_Projections->GetVectorLength();
543  for(int s=0; s<size; s++)
544  {
545  // Iterate trough the roi
546  std::vector<mitk::ScalarType> profile;
547  RoiType::iterator it;
548  it = m_Roi.begin();
549  while(it != m_Roi.end())
550  {
551  itk::Index<3> ix = *it;
552  profile.push_back(m_Projections->GetPixel(ix).GetElement(s));
553  it++;
554  }
555 
556  profiles.push_back(profile);
557  }
558 
559 
560 
561  m_IndividualProfiles = profiles;
562  // Calculate the averages
563 
564  // Here a check could be build in to check whether all profiles have
565  // the same length, but this should normally be the case if the input
566  // data were corrected with the TBSS Module.
567 
568  std::vector< std::vector<mitk::ScalarType> > groupProfiles;
569 
570  std::vector< std::pair<std::string, int> >::iterator it;
571  it = m_Groups.begin();
572 
573  int c = 0; //the current profile number
574 
575  while(it != m_Groups.end() && profiles.size() > 0)
576  {
577  std::pair<std::string, int> p = *it;
578  int size = p.second;
579 
580  //initialize a vector of the right length with zeroes
581  std::vector<mitk::ScalarType> averageProfile;
582  for(unsigned int i=0; i<profiles.at(0).size(); i++)
583  {
584  averageProfile.push_back(0.0);
585  }
586 
587  // Average the right number of profiles
588 
589  for(int i=0; i<size; i++)
590  {
591  for(unsigned int j=0; j<averageProfile.size(); ++j)
592  {
593  averageProfile.at(j) = averageProfile.at(j) + profiles.at(c).at(j);
594  }
595  c++;
596  }
597 
598  // Divide by the number of profiles to get group average
599  for(unsigned int i=0; i<averageProfile.size(); i++)
600  {
601  averageProfile.at(i) = averageProfile.at(i) / size;
602  }
603 
604  groupProfiles.push_back(averageProfile);
605 
606  ++it;
607  }
608 
609  return groupProfiles;
610 }
611 
612 
614 {
615  std::vector <std::vector<mitk::ScalarType> > groupProfiles = CalculateGroupProfiles();
616  Plot(groupProfiles);
617 }
618 
619 void QmitkTbssRoiAnalysisWidget::Plot(std::vector <std::vector<mitk::ScalarType> > groupProfiles)
620 {
621  this->Clear();
622  m_Vals.clear();
623  std::vector<mitk::ScalarType> v1;
624 
625 
626  std::vector<mitk::ScalarType> xAxis;
627  for(unsigned int i=0; i<groupProfiles.at(0).size(); ++i)
628  {
629  xAxis.push_back((mitk::ScalarType)i);
630  }
631 
632 
633  // fill m_Vals. This might be used by the user to copy data to the clipboard
634  for(unsigned int i=0; i<groupProfiles.size(); i++)
635  {
636 
637  v1.clear();
638 
639 
640  for(unsigned int j=0; j<groupProfiles.at(i).size(); j++)
641  {
642  v1.push_back(groupProfiles.at(i).at(j));
643  }
644 
645  m_Vals.push_back(v1);
646 
647  }
648 
649  std::string title = m_Measure + " profiles on the ";
650  title.append(m_Structure);
651  this->SetPlotTitle( title.c_str() );
652  QPen pen( Qt::SolidLine );
653  pen.setWidth(2);
654 
655 
656 
657  std::vector< std::pair<std::string, int> >::iterator it;
658  it = m_Groups.begin();
659 
660  int c = 0; //the current profile number
661 
662  QColor colors[4] = {Qt::green, Qt::blue, Qt::yellow, Qt::red};
663 
664  while(it != m_Groups.end() && groupProfiles.size() > 0)
665  {
666 
667  std::pair< std::string, int > group = *it;
668 
669  pen.setColor(colors[c]);
670  int curveId = this->InsertCurve( group.first.c_str() );
671  this->SetCurveData( curveId, xAxis, groupProfiles.at(c) );
672 
673 
674  this->SetCurvePen( curveId, pen );
675 
676  c++;
677  it++;
678 
679  }
680 
681 
682  auto legend = new QwtLegend;
683  this->SetLegend(legend, QwtPlot::RightLegend, 0.5);
684 
685 
686  std::cout << m_Measure << std::endl;
687  this->m_Plot->setAxisTitle(0, m_Measure.c_str());
688  this->m_Plot->setAxisTitle(3, "Position");
689 
690  this->Replot();
691 }
692 
693 
694 std::vector< std::vector<mitk::ScalarType> > QmitkTbssRoiAnalysisWidget::CalculateGroupProfilesFibers(mitk::TbssImage::Pointer tbssImage,
695  mitk::FiberBundle *fib,
696  mitk::DataNode* startRoi,
697  mitk::DataNode* endRoi,
698  int number)
699 {
700  TractContainerType tracts = CreateTracts(fib, startRoi, endRoi);
701 
702  TractContainerType resampledTracts = ParameterizeTracts(tracts, number);
703 
704  int nTracts = resampledTracts.size();
705 
706  this->Clear();
707 
708 
709  // For every group we have m fibers * n subjects of profiles to fill
710 
711  std::vector< std::vector<mitk::ScalarType> > profiles;
712 
713  // calculate individual profiles by going through all n subjects
714  int size = m_Projections->GetVectorLength();
715  for(int s=0; s<size; s++)
716  {
717 
718  // Iterate through all tracts
719 
720  for(int t=0; t<nTracts; t++)
721  {
722  // Iterate trough the tract
723  std::vector<mitk::ScalarType> profile;
724  auto it = resampledTracts[t].begin();
725  while(it != resampledTracts[t].end())
726  {
727  PointType p = *it;
728  PointType index;
729  tbssImage->GetGeometry()->WorldToIndex(p, index);
730 
731  itk::Index<3> ix;
732  ix[0] = index[0];
733  ix[1] = index[1];
734  ix[2] = index[2];
735  // Get value from image
736 
737  profile.push_back(m_Projections->GetPixel(ix).GetElement(s));
738 
739  it++;
740  }
741  profiles.push_back(profile);
742  }
743 
744 
745  }
746 
747  m_IndividualProfiles = profiles;
748 
749  // Now create the group averages (every group contains m fibers * n_i group members
750 
751  std::vector< std::pair<std::string, int> >::iterator it;
752  it = m_Groups.begin();
753  int c = 0; //the current profile number
754 
755  // Calculate the group averages
756  std::vector< std::vector<mitk::ScalarType> > groupProfiles;
757 
758  while(it != m_Groups.end() && profiles.size() > 0)
759  {
760  std::pair<std::string, int> p = *it;
761  int size = p.second;
762 
763  //initialize a vector of the right length with zeroes
764  std::vector<mitk::ScalarType> averageProfile;
765  for(unsigned int i=0; i<profiles.at(0).size(); i++)
766  {
767  averageProfile.push_back(0.0);
768  }
769 
770  // Average the right number of profiles
771 
772  for(int i=0; i<size*nTracts; i++)
773  {
774  for(unsigned int j=0; j<averageProfile.size(); ++j)
775  {
776  averageProfile.at(j) = averageProfile.at(j) + profiles.at(c).at(j);
777  }
778  c++;
779  }
780 
781  // Divide by the number of profiles to get group average
782  for(unsigned int i=0; i<averageProfile.size(); i++)
783  {
784  averageProfile.at(i) = averageProfile.at(i) / (size*nTracts);
785  }
786 
787  groupProfiles.push_back(averageProfile);
788 
789  ++it;
790  }
791 
792  return groupProfiles;
793 }
794 
795 
797  mitk::FiberBundle *fib,
798  mitk::DataNode* startRoi,
799  mitk::DataNode* endRoi,
800  int number)
801 {
802  m_PlottingFiberBundle = false;
803  m_Fib = fib;
804  m_CurrentStartRoi = startRoi;
805  m_CurrentEndRoi = endRoi;
806  m_CurrentTbssImage = tbssImage;
807  std::vector <std::vector<mitk::ScalarType> > groupProfiles = CalculateGroupProfilesFibers(tbssImage, fib, startRoi, endRoi, number);
808  Plot(groupProfiles);
809 
810 }
811 
812 
813 template <typename T>
815 {
816 
817  m_PlottingFiberBundle = true;
818 
819  this->Clear();
820  auto it = tracts.begin();
821 
822 
823  std::vector< std::vector <mitk::ScalarType > > profiles;
824 
825  mitk::ImagePixelReadAccessor<T,3> imAccess(img,img->GetVolumeData(0));
826 
827  it = tracts.begin();
828  while(it != tracts.end())
829  {
830 
831  TractType tract = *it;
832  auto tractIt = tract.begin();
833 
834  std::vector<mitk::ScalarType> profile;
835 
836  while(tractIt != tract.end())
837  {
838  PointType p = *tractIt;
839 
840  // Get value from image
841  profile.push_back( (mitk::ScalarType) imAccess.GetPixelByWorldCoordinates(p) );
842 
843  ++tractIt;
844  }
845 
846  profiles.push_back(profile);
847  std::cout << std::endl;
848 
849  ++it;
850  }
851 
852 
853  if(profiles.size() == 0)
854  return;
855 
856  m_IndividualProfiles = profiles;
857 
858 
859  std::string title = "Fiber bundle plot";
860  this->SetPlotTitle( title.c_str() );
861 
862 
863  // initialize average profile
864  std::vector<mitk::ScalarType> averageProfile;
865  std::vector<mitk::ScalarType> profile = profiles.at(0); // can do this because we checked the size of profiles before
866  for(unsigned int i=0; i<profile.size(); ++i)
867  {
868  averageProfile.push_back(0.0);
869  }
870 
871 
872  auto profit = profiles.begin();
873 
874  int id=0;
875  while(profit != profiles.end())
876  {
877  std::vector<mitk::ScalarType> profile = *profit;
878 
879 
880 
881  std::vector<mitk::ScalarType> xAxis;
882  for(unsigned int i=0; i<profile.size(); ++i)
883  {
884  xAxis.push_back((mitk::ScalarType)i);
885  averageProfile.at(i) += profile.at(i) / profiles.size();
886  }
887 
888  int curveId = this->InsertCurve( "" );
889 
890  this->SetCurveData( curveId, xAxis, profile );
891 
892  ++profit;
893  id++;
894 
895 
896  }
897 
898  m_Average = averageProfile;
899 
900 
901  if(avg)
902  {
903 
904  // Draw the average profile
905  std::vector<mitk::ScalarType> xAxis;
906  for(unsigned int i=0; i<averageProfile.size(); ++i)
907  {
908  xAxis.push_back((mitk::ScalarType)i);
909  }
910 
911  int curveId = this->InsertCurve( "" );
912  this->SetCurveData( curveId, xAxis, averageProfile );
913 
914 
915 
916 
917  QPen pen( Qt::SolidLine );
918  pen.setWidth(3);
919  pen.setColor(Qt::red);
920 
921  this->SetCurvePen( curveId, pen );
922 
923 
924 
925  id++;
926 
927 
928  }
929 
930  this->Replot();
931 
932 
933 
934 
935 
936 }
937 
938 
940 {
941 
942  m_Plot->detachItems(QwtPlotItem::Rtti_PlotMarker, true);
943 
944 
945  QwtPlotMarker *mX = new QwtPlotMarker();
946  //mX->setLabel(QString::fromLatin1("selected point"));
947  mX->setLabelAlignment(Qt::AlignLeft | Qt::AlignBottom);
948  mX->setLabelOrientation(Qt::Vertical);
949  mX->setLineStyle(QwtPlotMarker::VLine);
950  mX->setLinePen(QPen(Qt::black, 0, Qt::SolidLine));
951  mX->setXValue(x);
952  mX->attach(m_Plot);
953 
954 
955  this->Replot();
956 
957 }
958 
960 {
961  delete m_PlotPicker;
962 
963 }
964 
965 
966 
967 
void SetPlotTitle(const QwtText &qwt_title)
void ModifyPlot(int number, bool avg)
Gives locked and index-based read access for a particular image part. The class provides several set-...
std::vector< std::pair< std::string, int > > m_Groups
#define MITK_INFO
Definition: mitkLogMacros.h:22
double ScalarType
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
std::vector< std::vector< double > > m_IndividualProfiles
virtual ImageDataItemPointer GetVolumeData(int t=0, int n=0, void *data=nullptr, ImportMemoryManagementType importMemoryManagement=CopyMemory) const
Definition: mitkImage.cpp:330
std::vector< std::vector< double > > CalculateGroupProfilesFibers(mitk::TbssImage::Pointer tbssImage, mitk::FiberBundle *fib, mitk::DataNode *startRoi, mitk::DataNode *endRoi, int number)
void DoPlotFiberBundles(mitk::FiberBundle *fib, mitk::Image *img, mitk::DataNode *startRoi, mitk::DataNode *endRoi, bool avg=false, int number=25)
Vector3D GetNormal() const
Normal of the plane.
itk::Vector< float, 3 > VectorType
std::vector< TractType > TractContainerType
virtual bool IsAbove(const Point3D &pt3d_mm, bool considerBoundingBox=false) const
Calculates, whether a point is below or above the plane. There are two different calculation methods...
std::vector< PointType > TractType
void PlotFiber4D(mitk::TbssImage::Pointer tbssImage, mitk::FiberBundle *fib, mitk::DataNode *startRoi, mitk::DataNode *endRoi, int number)
void SetCurvePen(unsigned int curveId, const QPen &pen)
mitk::Point3D GetPositionInWorld(int index)
TractContainerType ParameterizeTracts(TractContainerType tracts, int number)
#define mitkPixelTypeMultiplex3(function, ptype, param1, param2, param3)
void PlotFiberBundles(const mitk::PixelType, TractContainerType tracts, mitk::Image *img, bool avg=false)
unsigned int InsertCurve(const char *title, QColor color=QColor(Qt::black))
Image class for storing images.
Definition: mitkImage.h:76
bool SetCurveData(unsigned int curveId, const DataVector &xValues, const DataVector &yValues)
Base Class for Fiber Bundles;.
static T max(T x, T y)
Definition: svm.cpp:70
std::vector< std::vector< double > > CalculateGroupProfiles()
FiberBundle::Pointer ExtractFiberSubset(DataNode *roi, DataStorage *storage)
Base-class for geometric planar (2D) figures, such as lines, circles, rectangles, polygons...
void Plot(std::vector< std::vector< double > > groupProfiles)
std::vector< std::vector< double > > m_Vals
VectorImageType::Pointer m_Projections
Describes a two-dimensional, rectangular plane.
TractContainerType CreateTracts(mitk::FiberBundle *fib, mitk::DataNode *startRoi, mitk::DataNode *endRoi)
void PlotFiberBetweenRois(mitk::FiberBundle *fib, mitk::Image *img, mitk::DataNode *startRoi, mitk::DataNode *endRoi, bool avg=-1, int number=25)
void SetLegend(QwtLegend *legend, QwtPlot::LegendPosition pos=QwtPlot::RightLegend, double ratio=-1)
ImageDescriptor::Pointer GetImageDescriptor() const
Definition: mitkImage.h:528
Class for nodes of the DataTree.
Definition: mitkDataNode.h:66
Class for defining the data type of pixels.
Definition: mitkPixelType.h:55