diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkTbssRoiAnalysisWidget.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkTbssRoiAnalysisWidget.cpp index 40cd614fb2..ce3097adf1 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkTbssRoiAnalysisWidget.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkTbssRoiAnalysisWidget.cpp @@ -1,974 +1,955 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkTbssRoiAnalysisWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include QmitkTbssRoiAnalysisWidget::QmitkTbssRoiAnalysisWidget( QWidget * parent ) : QmitkPlotWidget(parent) { m_PlotPicker = new QwtPlotPicker(m_Plot->canvas()); m_PlotPicker->setSelectionFlags(QwtPicker::PointSelection | QwtPicker::ClickSelection | QwtPicker::DragSelection); m_PlotPicker->setTrackerMode(QwtPicker::ActiveOnly); m_PlottingFiberBundle = false; } void QmitkTbssRoiAnalysisWidget::DoPlotFiberBundles(mitk::FiberBundleX *fib, mitk::Image* img, mitk::PlanarFigure* startRoi, mitk::PlanarFigure* endRoi, bool avg, int number) { - mitk::Geometry3D* currentGeometry = fib->GetGeometry(); + // mitk::Geometry3D* currentGeometry = fib->GetGeometry(); - mitk::PlaneGeometry* startGeometry2D = dynamic_cast( const_cast(startRoi->GetGeometry2D()) ); - mitk::PlaneGeometry* endGeometry2D = dynamic_cast( const_cast(endRoi->GetGeometry2D()) ); - mitk::Point3D startCenter = startRoi->GetWorldControlPoint(0); //center Point of start roi - mitk::Point3D endCenter = endRoi->GetWorldControlPoint(0); //center Point of end roi - - mitk::FiberBundleX::Pointer inStart = fib->ExtractFiberSubset(startRoi); - mitk::FiberBundleX::Pointer inBoth = inStart->ExtractFiberSubset(endRoi); + TractContainerType tracts = CreateTracts(fib, startRoi, endRoi); + //todo: Make number of samples selectable by user + TractContainerType resampledTracts = ParameterizeTracts(tracts, number); - int num = inBoth->GetNumFibers(); + // Now we have the resampled tracts. Next we should use these points to read out the values - TractContainerType tracts; + PlotFiberBundles(resampledTracts, img, avg); + m_CurrentTracts = resampledTracts; +} - vtkSmartPointer fiberPolyData = inBoth->GetFiberPolyData(); - vtkCellArray* lines = fiberPolyData->GetLines(); - lines->InitTraversal(); +TractContainerType QmitkTbssRoiAnalysisWidget::CreateTracts(mitk::FiberBundleX *fib, + mitk::PlanarFigure *startRoi, + mitk::PlanarFigure *endRoi) +{ + mitk::PlaneGeometry* startGeometry2D = dynamic_cast( const_cast(startRoi->GetGeometry2D()) ); + mitk::PlaneGeometry* endGeometry2D = dynamic_cast( const_cast(endRoi->GetGeometry2D()) ); - // Now find out for each fiber which ROI is encountered first. If this is the startRoi, the direction is ok - // Otherwise the plot should be in the reverse direction - for( int fiberID( 0 ); fiberID < num; fiberID++ ) - { - vtkIdType numPointsInCell(0); - vtkIdType* pointsInCell(NULL); - lines->GetNextCell ( numPointsInCell, pointsInCell ); + mitk::Point3D startCenter = startRoi->GetWorldControlPoint(0); //center Point of start roi + mitk::Point3D endCenter = endRoi->GetWorldControlPoint(0); //center Point of end roi - int startId = 0; - int endId = 0; + mitk::FiberBundleX::Pointer inStart = fib->ExtractFiberSubset(startRoi); + mitk::FiberBundleX::Pointer inBoth = inStart->ExtractFiberSubset(endRoi); - float minDistStart = std::numeric_limits::max(); - float minDistEnd = std::numeric_limits::max(); + int num = inBoth->GetNumFibers(); - for( int pointInCellID( 0 ); pointInCellID < numPointsInCell ; pointInCellID++) - { + TractContainerType tracts; - double *p = fiberPolyData->GetPoint( pointsInCell[ pointInCellID ] ); - mitk::Point3D point; - point[0] = p[0]; - point[1] = p[1]; - point[2] = p[2]; + vtkSmartPointer fiberPolyData = inBoth->GetFiberPolyData(); + vtkCellArray* lines = fiberPolyData->GetLines(); + lines->InitTraversal(); - float distanceToStart = point.EuclideanDistanceTo(startCenter); - float distanceToEnd = point.EuclideanDistanceTo(endCenter); - if(distanceToStart < minDistStart) - { - minDistStart = distanceToStart; - startId = pointInCellID; - } - if(distanceToEnd < minDistEnd) - { - minDistEnd = distanceToEnd; - endId = pointInCellID; - } + // Now find out for each fiber which ROI is encountered first. If this is the startRoi, the direction is ok + // Otherwise the plot should be in the reverse direction + for( int fiberID( 0 ); fiberID < num; fiberID++ ) + { + vtkIdType numPointsInCell(0); + vtkIdType* pointsInCell(NULL); + lines->GetNextCell ( numPointsInCell, pointsInCell ); + int startId = 0; + int endId = 0; + float minDistStart = std::numeric_limits::max(); + float minDistEnd = std::numeric_limits::max(); - } - /* We found the start and end points of of the part that should be plottet for - the current fiber. now we need to plot them. If the endId is smaller than the startId the plot order - must be reversed*/ - TractType singleTract; - PointType point; + for( int pointInCellID( 0 ); pointInCellID < numPointsInCell ; pointInCellID++) + { - if(startId < endId) - { - // Calculate the intersection of the ROI with the startRoi and decide if the startId is part of the roi or must be cut of - double *p = fiberPolyData->GetPoint( pointsInCell[ startId ] ); - mitk::Vector3D p0; - p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2]; + double *p = fiberPolyData->GetPoint( pointsInCell[ pointInCellID ] ); - p = fiberPolyData->GetPoint( pointsInCell[ startId+1 ] ); - mitk::Vector3D p1; - p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; + mitk::Point3D point; + point[0] = p[0]; + point[1] = p[1]; + point[2] = p[2]; - // Check if p and p2 are both on the same side of the plane - mitk::Vector3D normal = startGeometry2D->GetNormal(); + float distanceToStart = point.EuclideanDistanceTo(startCenter); + float distanceToEnd = point.EuclideanDistanceTo(endCenter); - mitk::Point3D pStart; - pStart[0] = p0[0]; pStart[1] = p0[1]; pStart[2] = p0[2]; + if(distanceToStart < minDistStart) + { + minDistStart = distanceToStart; + startId = pointInCellID; + } - mitk::Point3D pSecond; - pSecond[0] = p1[0]; pSecond[1] = p1[1]; pSecond[2] = p1[2]; + if(distanceToEnd < minDistEnd) + { + minDistEnd = distanceToEnd; + endId = pointInCellID; + } - bool startOnPositive = startGeometry2D->IsAbove(pStart); - bool secondOnPositive = startGeometry2D->IsAbove(pSecond); - mitk::Vector3D onPlane; - onPlane[0] = startCenter[0]; onPlane[1] = startCenter[1]; onPlane[2] = startCenter[2]; + } + /* We found the start and end points of of the part that should be plottet for + the current fiber. now we need to plot them. If the endId is smaller than the startId the plot order + must be reversed*/ + TractType singleTract; + PointType point; - if(! (secondOnPositive ^ startOnPositive) ) + if(startId < endId) { - /* startId and startId+1 lie on the same side of the plane, so we need - need startId-1 to calculate the intersection with the planar figure*/ - p = fiberPolyData->GetPoint( pointsInCell[ startId-1 ] ); - p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; - } + // Calculate the intersection of the ROI with the startRoi and decide if the startId is part of the roi or must be cut of + double *p = fiberPolyData->GetPoint( pointsInCell[ startId ] ); + mitk::Vector3D p0; + p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2]; - double d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal ); - mitk::Vector3D newPoint = (p0-p1); + p = fiberPolyData->GetPoint( pointsInCell[ startId+1 ] ); + mitk::Vector3D p1; + p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; - point[0] = d*newPoint[0] + p0[0]; - point[1] = d*newPoint[1] + p0[1]; - point[2] = d*newPoint[2] + p0[2]; + // Check if p and p2 are both on the same side of the plane + mitk::Vector3D normal = startGeometry2D->GetNormal(); - singleTract.push_back(point); + mitk::Point3D pStart; + pStart[0] = p0[0]; pStart[1] = p0[1]; pStart[2] = p0[2]; - if(! (secondOnPositive ^ startOnPositive) ) - { - /* StartId and startId+1 lie on the same side of the plane - so startId is also part of the ROI*/ + mitk::Point3D pSecond; + pSecond[0] = p1[0]; pSecond[1] = p1[1]; pSecond[2] = p1[2]; - double *start = fiberPolyData->GetPoint( pointsInCell[startId] ); - point[0] = start[0]; point[1] = start[1]; point[2] = start[2]; - singleTract.push_back(point); - } + bool startOnPositive = startGeometry2D->IsAbove(pStart); + bool secondOnPositive = startGeometry2D->IsAbove(pSecond); + mitk::Vector3D onPlane; + onPlane[0] = startCenter[0]; onPlane[1] = startCenter[1]; onPlane[2] = startCenter[2]; - for( int pointInCellID( startId+1 ); pointInCellID < endId ; pointInCellID++) - { - // push back point - double *p = fiberPolyData->GetPoint( pointsInCell[ pointInCellID ] ); - point[0] = p[0]; point[1] = p[1]; point[2] = p[2]; - singleTract.push_back( point ); - } - /* endId must be included if endId and endId-1 lie on the same side of the - plane defined by endRoi*/ + if(! (secondOnPositive ^ startOnPositive) ) + { + /* startId and startId+1 lie on the same side of the plane, so we need + need startId-1 to calculate the intersection with the planar figure*/ + p = fiberPolyData->GetPoint( pointsInCell[ startId-1 ] ); + p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; + } - p = fiberPolyData->GetPoint( pointsInCell[ endId ] ); - p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2]; + double d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal ); + mitk::Vector3D newPoint = (p0-p1); - p = fiberPolyData->GetPoint( pointsInCell[ endId-1 ] ); - p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; + point[0] = d*newPoint[0] + p0[0]; + point[1] = d*newPoint[1] + p0[1]; + point[2] = d*newPoint[2] + p0[2]; - mitk::Point3D pLast; - pLast[0] = p0[0]; pLast[1] = p0[1]; pLast[2] = p0[2]; + singleTract.push_back(point); - mitk::Point3D pBeforeLast; - pBeforeLast[0] = p1[0]; pBeforeLast[1] = p1[1]; pBeforeLast[2] = p1[2]; + if(! (secondOnPositive ^ startOnPositive) ) + { + /* StartId and startId+1 lie on the same side of the plane + so startId is also part of the ROI*/ - normal = endGeometry2D->GetNormal(); - bool lastOnPositive = endGeometry2D->IsAbove(pLast); - bool secondLastOnPositive = endGeometry2D->IsAbove(pBeforeLast); + double *start = fiberPolyData->GetPoint( pointsInCell[startId] ); + point[0] = start[0]; point[1] = start[1]; point[2] = start[2]; + singleTract.push_back(point); + } - onPlane[0] = endCenter[0]; - onPlane[1] = endCenter[1]; - onPlane[2] = endCenter[2]; - if(! (lastOnPositive ^ secondLastOnPositive) ) - { - /* endId and endId-1 lie on the same side of the plane, so we need - need endId+1 to calculate the intersection with the planar figure. - this should exist since we know that the fiber crosses the planar figure - endId is also part of the tract and can be inserted here */ + for( int pointInCellID( startId+1 ); pointInCellID < endId ; pointInCellID++) + { + // push back point + double *p = fiberPolyData->GetPoint( pointsInCell[ pointInCellID ] ); + point[0] = p[0]; point[1] = p[1]; point[2] = p[2]; + singleTract.push_back( point ); - p = fiberPolyData->GetPoint( pointsInCell[ endId ] ); - point[0] = p[0]; point[1] = p[1]; point[2] = p[2]; - singleTract.push_back( point ); + } - p = fiberPolyData->GetPoint( pointsInCell[ endId+1 ] ); - } + /* endId must be included if endId and endId-1 lie on the same side of the + plane defined by endRoi*/ - d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal ); - newPoint = (p0-p1); + p = fiberPolyData->GetPoint( pointsInCell[ endId ] ); + p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2]; - point[0] = d*newPoint[0] + p0[0]; - point[1] = d*newPoint[1] + p0[1]; - point[2] = d*newPoint[2] + p0[2]; + p = fiberPolyData->GetPoint( pointsInCell[ endId-1 ] ); + p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; - singleTract.push_back(point); + mitk::Point3D pLast; + pLast[0] = p0[0]; pLast[1] = p0[1]; pLast[2] = p0[2]; + mitk::Point3D pBeforeLast; + pBeforeLast[0] = p1[0]; pBeforeLast[1] = p1[1]; pBeforeLast[2] = p1[2]; + normal = endGeometry2D->GetNormal(); + bool lastOnPositive = endGeometry2D->IsAbove(pLast); + bool secondLastOnPositive = endGeometry2D->IsAbove(pBeforeLast); - } - else{ - // Calculate the intersection of the ROI with the startRoi and decide if the startId is part of the roi or must be cut of - double *p = fiberPolyData->GetPoint( pointsInCell[ startId ] ); - mitk::Vector3D p0; - p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2]; + onPlane[0] = endCenter[0]; + onPlane[1] = endCenter[1]; + onPlane[2] = endCenter[2]; - p = fiberPolyData->GetPoint( pointsInCell[ startId-1 ] ); - mitk::Vector3D p1; - p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; + if(! (lastOnPositive ^ secondLastOnPositive) ) + { + /* endId and endId-1 lie on the same side of the plane, so we need + need endId+1 to calculate the intersection with the planar figure. + this should exist since we know that the fiber crosses the planar figure + endId is also part of the tract and can be inserted here */ + + p = fiberPolyData->GetPoint( pointsInCell[ endId ] ); + point[0] = p[0]; point[1] = p[1]; point[2] = p[2]; + singleTract.push_back( point ); - // Check if p and p2 are both on the same side of the plane - mitk::Vector3D normal = startGeometry2D->GetNormal(); + p = fiberPolyData->GetPoint( pointsInCell[ endId+1 ] ); + } - mitk::Point3D pStart; - pStart[0] = p0[0]; pStart[1] = p0[1]; pStart[2] = p0[2]; + d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal ); - mitk::Point3D pSecond; - pSecond[0] = p1[0]; pSecond[1] = p1[1]; pSecond[2] = p1[2]; + newPoint = (p0-p1); - bool startOnPositive = startGeometry2D->IsAbove(pStart); - bool secondOnPositive = startGeometry2D->IsAbove(pSecond); + point[0] = d*newPoint[0] + p0[0]; + point[1] = d*newPoint[1] + p0[1]; + point[2] = d*newPoint[2] + p0[2]; + + singleTract.push_back(point); - mitk::Vector3D onPlane; - onPlane[0] = startCenter[0]; onPlane[1] = startCenter[1]; onPlane[2] = startCenter[2]; - if(! (secondOnPositive ^ startOnPositive) ) - { - /* startId and startId+1 lie on the same side of the plane, so we need - need startId-1 to calculate the intersection with the planar figure*/ - p = fiberPolyData->GetPoint( pointsInCell[ startId-1 ] ); - p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; } + else{ + // Calculate the intersection of the ROI with the startRoi and decide if the startId is part of the roi or must be cut of + double *p = fiberPolyData->GetPoint( pointsInCell[ startId ] ); + mitk::Vector3D p0; + p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2]; - double d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal ); - mitk::Vector3D newPoint = (p0-p1); + p = fiberPolyData->GetPoint( pointsInCell[ startId-1 ] ); + mitk::Vector3D p1; + p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; + // Check if p and p2 are both on the same side of the plane + mitk::Vector3D normal = startGeometry2D->GetNormal(); - point[0] = d*newPoint[0] + p0[0]; - point[1] = d*newPoint[1] + p0[1]; - point[2] = d*newPoint[2] + p0[2]; + mitk::Point3D pStart; + pStart[0] = p0[0]; pStart[1] = p0[1]; pStart[2] = p0[2]; + mitk::Point3D pSecond; + pSecond[0] = p1[0]; pSecond[1] = p1[1]; pSecond[2] = p1[2]; - singleTract.push_back(point); + bool startOnPositive = startGeometry2D->IsAbove(pStart); + bool secondOnPositive = startGeometry2D->IsAbove(pSecond); - if(! (secondOnPositive ^ startOnPositive) ) - { - /* StartId and startId+1 lie on the same side of the plane - so startId is also part of the ROI*/ + mitk::Vector3D onPlane; + onPlane[0] = startCenter[0]; onPlane[1] = startCenter[1]; onPlane[2] = startCenter[2]; - double *start = fiberPolyData->GetPoint( pointsInCell[startId] ); - point[0] = start[0]; point[1] = start[1]; point[2] = start[2]; - singleTract.push_back(point); - } + if(! (secondOnPositive ^ startOnPositive) ) + { + /* startId and startId+1 lie on the same side of the plane, so we need + need startId-1 to calculate the intersection with the planar figure*/ + p = fiberPolyData->GetPoint( pointsInCell[ startId-1 ] ); + p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; + } - for( int pointInCellID( startId-1 ); pointInCellID > endId ; pointInCellID--) - { - // push back point - double *p = fiberPolyData->GetPoint( pointsInCell[ pointInCellID ] ); - point[0] = p[0]; point[1] = p[1]; point[2] = p[2]; - singleTract.push_back( point ); + double d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal ); + mitk::Vector3D newPoint = (p0-p1); - } - /* endId must be included if endId and endI+1 lie on the same side of the - plane defined by endRoi*/ + point[0] = d*newPoint[0] + p0[0]; + point[1] = d*newPoint[1] + p0[1]; + point[2] = d*newPoint[2] + p0[2]; - p = fiberPolyData->GetPoint( pointsInCell[ endId ] ); - p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2]; + singleTract.push_back(point); - p = fiberPolyData->GetPoint( pointsInCell[ endId+1 ] ); - p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; + if(! (secondOnPositive ^ startOnPositive) ) + { + /* StartId and startId+1 lie on the same side of the plane + so startId is also part of the ROI*/ - mitk::Point3D pLast; - pLast[0] = p0[0]; pLast[1] = p0[1]; pLast[2] = p0[2]; + double *start = fiberPolyData->GetPoint( pointsInCell[startId] ); + point[0] = start[0]; point[1] = start[1]; point[2] = start[2]; + singleTract.push_back(point); + } - mitk::Point3D pBeforeLast; - pBeforeLast[0] = p1[0]; pBeforeLast[1] = p1[1]; pBeforeLast[2] = p1[2]; - bool lastOnPositive = endGeometry2D->IsAbove(pLast); - bool secondLastOnPositive = endGeometry2D->IsAbove(pBeforeLast); - normal = endGeometry2D->GetNormal(); + for( int pointInCellID( startId-1 ); pointInCellID > endId ; pointInCellID--) + { + // push back point + double *p = fiberPolyData->GetPoint( pointsInCell[ pointInCellID ] ); + point[0] = p[0]; point[1] = p[1]; point[2] = p[2]; + singleTract.push_back( point ); + } - onPlane[0] = endCenter[0]; - onPlane[1] = endCenter[1]; - onPlane[2] = endCenter[2]; + /* endId must be included if endId and endI+1 lie on the same side of the + plane defined by endRoi*/ - if(! (lastOnPositive ^ secondLastOnPositive) ) - { - /* endId and endId+1 lie on the same side of the plane, so we need - need endId-1 to calculate the intersection with the planar figure. - this should exist since we know that the fiber crosses the planar figure - endId is also part of the tract and can be inserted here */ p = fiberPolyData->GetPoint( pointsInCell[ endId ] ); - point[0] = p[0]; point[1] = p[1]; point[2] = p[2]; - singleTract.push_back( point ); + p0[0] = p[0]; p0[1] = p[1]; p0[2] = p[2]; - p = fiberPolyData->GetPoint( pointsInCell[ endId-1 ] ); - } + p = fiberPolyData->GetPoint( pointsInCell[ endId+1 ] ); + p1[0] = p[0]; p1[1] = p[1]; p1[2] = p[2]; - d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal ); + mitk::Point3D pLast; + pLast[0] = p0[0]; pLast[1] = p0[1]; pLast[2] = p0[2]; - newPoint = (p0-p1); + mitk::Point3D pBeforeLast; + pBeforeLast[0] = p1[0]; pBeforeLast[1] = p1[1]; pBeforeLast[2] = p1[2]; - point[0] = d*newPoint[0] + p0[0]; - point[1] = d*newPoint[1] + p0[1]; - point[2] = d*newPoint[2] + p0[2]; + bool lastOnPositive = endGeometry2D->IsAbove(pLast); + bool secondLastOnPositive = endGeometry2D->IsAbove(pBeforeLast); + normal = endGeometry2D->GetNormal(); - singleTract.push_back(point); - } + onPlane[0] = endCenter[0]; + onPlane[1] = endCenter[1]; + onPlane[2] = endCenter[2]; - tracts.push_back(singleTract); + if(! (lastOnPositive ^ secondLastOnPositive) ) + { + /* endId and endId+1 lie on the same side of the plane, so we need + need endId-1 to calculate the intersection with the planar figure. + this should exist since we know that the fiber crosses the planar figure + endId is also part of the tract and can be inserted here */ + p = fiberPolyData->GetPoint( pointsInCell[ endId ] ); + point[0] = p[0]; point[1] = p[1]; point[2] = p[2]; + singleTract.push_back( point ); - } + p = fiberPolyData->GetPoint( pointsInCell[ endId-1 ] ); + } + d = ( (onPlane-p0)*normal) / ( (p0-p1) * normal ); - //todo: Make number of samples selectable by user - TractContainerType resampledTracts = ParameterizeTracts(tracts, number); + newPoint = (p0-p1); - // Now we have the resampled tracts. Next we should use these points to read out the values + point[0] = d*newPoint[0] + p0[0]; + point[1] = d*newPoint[1] + p0[1]; + point[2] = d*newPoint[2] + p0[2]; + singleTract.push_back(point); + } - PlotFiberBundles(resampledTracts, img, avg); - m_CurrentTracts = resampledTracts; + + tracts.push_back(singleTract); + + + } + + return tracts; } void QmitkTbssRoiAnalysisWidget::PlotFiberBetweenRois(mitk::FiberBundleX *fib, mitk::Image* img, mitk::PlanarFigure* startRoi, mitk::PlanarFigure* endRoi, bool avg, int number) { if(fib == NULL || img == NULL || startRoi == NULL || endRoi == NULL) return; m_Fib = fib; m_CurrentImage = img; m_CurrentStartRoi = startRoi; m_CurrentEndRoi = endRoi; DoPlotFiberBundles(fib, img, startRoi, endRoi, avg, number); } void QmitkTbssRoiAnalysisWidget::ModifyPlot(int number, bool avg) { if(m_Fib == NULL || m_CurrentImage == NULL || m_CurrentStartRoi == NULL || m_CurrentEndRoi == NULL) return; DoPlotFiberBundles(m_Fib, m_CurrentImage, m_CurrentStartRoi, m_CurrentEndRoi, avg, number); } TractContainerType QmitkTbssRoiAnalysisWidget::ParameterizeTracts(TractContainerType tracts, int number) { TractContainerType resampledTracts; for(TractContainerType::iterator it = tracts.begin(); it != tracts.end(); ++it) { TractType resampledTract; TractType tract = *it; // Calculate the total length float totalLength = 0; if(tract.size() < 2) continue; PointType p0 = tract.at(0); for(int i = 1; i distance+0.001) { if(tractCounter == tract.size()) std::cout << "problem"; // Determine by what distance we are no on the next segment locationBetween = locationBetween - distance; p0 = p1; p1 = tract.at(tractCounter); tractCounter++; distance = p0.EuclideanDistanceTo(p1); } // Direction PointType::VectorType direction = p1-p0; direction.Normalize(); PointType newSample = p0 + direction*locationBetween; resampledTract.push_back(newSample); locationBetween += stepSize; } resampledTracts.push_back(resampledTract); } return resampledTracts; } mitk::Point3D QmitkTbssRoiAnalysisWidget::GetPositionInWorld(int index) { TractContainerType tractsAtIndex; float xSum = 0.0; float ySum = 0.0; float zSum = 0.0; for(TractContainerType::iterator it = m_CurrentTracts.begin(); it!=m_CurrentTracts.end(); ++it) { TractType tract = *it; PointType p = tract.at(index); xSum += p[0]; ySum += p[1]; zSum += p[2]; } int number = m_CurrentTracts.size(); float xPos = xSum / number; float yPos = ySum / number; float zPos = zSum / number; mitk::Point3D pos; pos[0] = xPos; pos[1] = yPos; pos[2] = zPos; return pos; } -std::vector< std::vector > QmitkTbssRoiAnalysisWidget::CalculateGroupProfiles(std::string preprocessed) +std::vector< std::vector > QmitkTbssRoiAnalysisWidget::CalculateGroupProfiles() { MITK_INFO << "make profiles!"; std::vector< std::vector > profiles; - //No results were preprocessed, so they must be calculated now. - if(preprocessed == "") + + int size = m_Projections->GetVectorLength(); + for(int s=0; sGetVectorLength(); - for(int s=0; s profile; - RoiType::iterator it; - it = m_Roi.begin(); - while(it != m_Roi.end()) - { - itk::Index<3> ix = *it; - profile.push_back(m_Projections->GetPixel(ix).GetElement(s)); - it++; - } - int pSize = profile.size(); - profiles.push_back(profile); - } - } - else{ // Use preprocessed results - std::ifstream file(preprocessed.c_str()); - if(file.is_open()) + // Iterate trough the roi + std::vector profile; + RoiType::iterator it; + it = m_Roi.begin(); + while(it != m_Roi.end()) { - std::string line; - while(getline(file,line)) - { - std::vector tokens; - Tokenize(line, tokens); - std::vector::iterator it; - it = tokens.begin(); - std::vector< double > profile; - while(it != tokens.end()) - { - std::string s = *it; - profile.push_back (atof( s.c_str() ) ); - ++it; - } - profiles.push_back(profile); - } + itk::Index<3> ix = *it; + profile.push_back(m_Projections->GetPixel(ix).GetElement(s)); + it++; } + + profiles.push_back(profile); } + m_IndividualProfiles = profiles; // Calculate the averages // Here a check could be build in to check whether all profiles have // the same length, but this should normally be the case if the input // data were corrected with the TBSS Module. std::vector< std::vector > groupProfiles; std::vector< std::pair >::iterator it; it = m_Groups.begin(); int c = 0; //the current profile number - int nprof = profiles.size(); - while(it != m_Groups.end() && profiles.size() > 0) { std::pair p = *it; int size = p.second; //initialize a vector of the right length with zeroes std::vector averageProfile; for(int i=0; iClear(); - - m_Vals.clear(); std::vector v1; - std::vector > groupProfiles = CalculateGroupProfiles(preprocessed); + std::vector > groupProfiles = CalculateGroupProfiles(); std::vector xAxis; for(int i=0; iSetPlotTitle( title.c_str() ); QPen pen( Qt::SolidLine ); pen.setWidth(2); std::vector< std::pair >::iterator it; it = m_Groups.begin(); int c = 0; //the current profile number QColor colors[4] = {Qt::green, Qt::blue, Qt::yellow, Qt::red}; while(it != m_Groups.end() && groupProfiles.size() > 0) { std::pair< std::string, int > group = *it; pen.setColor(colors[c]); int curveId = this->InsertCurve( group.first.c_str() ); this->SetCurveData( curveId, xAxis, groupProfiles.at(c) ); this->SetCurvePen( curveId, pen ); c++; it++; } QwtLegend *legend = new QwtLegend; this->SetLegend(legend, QwtPlot::RightLegend, 0.5); std::cout << m_Measure << std::endl; this->m_Plot->setAxisTitle(0, m_Measure.c_str()); this->m_Plot->setAxisTitle(3, "Position"); this->Replot(); } -void QmitkTbssRoiAnalysisWidget::PlotFiber4D(); +void QmitkTbssRoiAnalysisWidget::PlotFiber4D() { } void QmitkTbssRoiAnalysisWidget::PlotFiberBundles(TractContainerType tracts, mitk::Image *img, bool avg) { this->Clear(); std::vector::iterator it = tracts.begin(); // Match points on tracts. Take the smallest tract and match all others on this one /* int min = std::numeric_limits::max(); TractType smallestTract; while(it != tracts.end()) { TractType tract = *it; if(tract.size() correspondingIndices; TractType correspondingPoints; for(int i=0; i::max(); int correspondingIndex = 0; PointType correspondingPoint; // Search for the point on the second tract with the smallest distance // to p and memorize it for(int j=0; j > profiles; it = tracts.begin(); while(it != tracts.end()) { std::cout << "Tract\n"; TractType tract = *it; TractType::iterator tractIt = tract.begin(); std::vector profile; while(tractIt != tract.end()) { PointType p = *tractIt; std::cout << p[0] << ' ' << p[1] << ' ' << p[2] << '\n'; // Get value from image profile.push_back( (double)img->GetPixelValueByWorldCoordinate(p) ); ++tractIt; } profiles.push_back(profile); std::cout << std::endl; ++it; } if(profiles.size() == 0) return; m_IndividualProfiles = profiles; std::string title = "Fiber bundle plot"; this->SetPlotTitle( title.c_str() ); // initialize average profile std::vector averageProfile; std::vector profile = profiles.at(0); // can do this because we checked the size of profiles before for(int i=0; i >::iterator profit = profiles.begin(); int id=0; while(profit != profiles.end()) { std::vector profile = *profit; std::vector xAxis; for(int i=0; iInsertCurve( QString::number(id).toStdString().c_str() ); this->SetCurveData( curveId, xAxis, profile ); ++profit; id++; } m_Average = averageProfile; if(avg) { // Draw the average profile std::vector xAxis; for(int i=0; iInsertCurve( QString::number(id).toStdString().c_str() ); this->SetCurveData( curveId, xAxis, averageProfile ); QPen pen( Qt::SolidLine ); pen.setWidth(3); pen.setColor(Qt::red); this->SetCurvePen( curveId, pen ); id++; } this->Replot(); } void QmitkTbssRoiAnalysisWidget::drawBar(int x) { m_Plot->detachItems(QwtPlotItem::Rtti_PlotMarker, true); QwtPlotMarker *mX = new QwtPlotMarker(); //mX->setLabel(QString::fromLatin1("selected point")); mX->setLabelAlignment(Qt::AlignLeft | Qt::AlignBottom); mX->setLabelOrientation(Qt::Vertical); mX->setLineStyle(QwtPlotMarker::VLine); mX->setLinePen(QPen(Qt::black, 0, Qt::SolidLine)); mX->setXValue(x); mX->attach(m_Plot); this->Replot(); } QmitkTbssRoiAnalysisWidget::~QmitkTbssRoiAnalysisWidget() { delete m_PlotPicker; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkTbssRoiAnalysisWidget.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkTbssRoiAnalysisWidget.h index ee750bb99e..c8d282da3c 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkTbssRoiAnalysisWidget.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkTbssRoiAnalysisWidget.h @@ -1,221 +1,222 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkTbssRoiAnalysisWidget_H_ #define QmitkTbssRoiAnalysisWidget_H_ #include "QmitkPlotWidget.h" #include #include "QmitkExtExports.h" #include "mitkPlanarFigure.h" #include "itkVectorImage.h" #include #include #include #include typedef itk::VectorImage VectorImageType; typedef std::vector< itk::Index<3> > RoiType; typedef itk::Point PointType; typedef std::vector< PointType> TractType; typedef std::vector< TractType > TractContainerType; /** * \brief Plot widget for TBSS Data * This widget can plot regions of interest on TBSS projection data. */ class DIFFUSIONIMAGING_EXPORT QmitkTbssRoiAnalysisWidget : public QmitkPlotWidget { Q_OBJECT public: QmitkTbssRoiAnalysisWidget( QWidget * parent); virtual ~QmitkTbssRoiAnalysisWidget(); /* \brief Set group information */ void SetGroups(std::vector< std::pair > groups) { m_Groups = groups; } /* \brief Draws the group averaged profiles */ - void DrawProfiles(std::string preprocessed); + void DrawProfiles(); void PlotFiber4D(); void PlotFiberBundles(TractContainerType tracts, mitk::Image* img, bool avg=false); /* \brief Sets the projections of the individual subjects */ void SetProjections(VectorImageType::Pointer projections) { m_Projections = projections; } /* \brief Set the region of interest*/ void SetRoi(RoiType roi) { m_Roi = roi; } /* \brief Set structure information to display in the plot */ void SetStructure(std::string structure) { m_Structure = structure; } /* \brief Set measurement type for display in the plot */ void SetMeasure(std::string measure) { m_Measure = measure; } /* \brief Draws a bar to indicate were the user clicked in the plot */ void drawBar(int x); /* \brief Returns the values of the group averaged profiles */ std::vector > GetVals() { return m_Vals; } /* \brief Returns the values of the individual subjects profiles */ std::vector > GetIndividualProfiles() { return m_IndividualProfiles; } std::vector GetAverageProfile() { return m_Average; } void SetPlottingFiber(bool b) { m_PlottingFiberBundle = b; } bool IsPlottingFiber() { return m_PlottingFiberBundle; } void PlotFiberBetweenRois(mitk::FiberBundleX *fib, mitk::Image* img, mitk::PlanarFigure* startRoi, mitk::PlanarFigure* endRoi, bool avg=-1, int number=25); // Takes an index which is an x coordinate from the plot and finds the corresponding position in world space mitk::Point3D GetPositionInWorld(int index); void ModifyPlot(int number, bool avg); QwtPlotPicker* m_PlotPicker; protected: mitk::FiberBundleX* m_Fib; std::vector< std::vector > m_Vals; std::vector< std::vector > m_IndividualProfiles; std::vector< double > m_Average; - std::vector< std::vector > CalculateGroupProfiles(std::string preprocessed); + std::vector< std::vector > CalculateGroupProfiles(); void Tokenize(const std::string& str, std::vector& tokens, const std::string& delimiters = " ") { // Skip delimiters at beginning. std::string::size_type lastPos = str.find_first_not_of(delimiters, 0); // Find first "non-delimiter". std::string::size_type pos = str.find_first_of(delimiters, lastPos); while (std::string::npos != pos || std::string::npos != lastPos) { // Found a token, add it to the vector. tokens.push_back(str.substr(lastPos, pos - lastPos)); // Skip delimiters. Note the "not_of" lastPos = str.find_first_not_of(delimiters, pos); // Find next "non-delimiter" pos = str.find_first_of(delimiters, lastPos); } } std::vector< std::pair > m_Groups; VectorImageType::Pointer m_Projections; RoiType m_Roi; std::string m_Structure; std::string m_Measure; bool m_PlottingFiberBundle; // true when the plot results from a fiber tracking result (vtk .fib file) // Resample a collection of tracts so that every tract contains #number equidistant samples TractContainerType ParameterizeTracts(TractContainerType tracts, int number); TractContainerType m_CurrentTracts; mitk::Image* m_CurrentImage; mitk::PlanarFigure* m_CurrentStartRoi; mitk::PlanarFigure* m_CurrentEndRoi; void DoPlotFiberBundles(mitk::FiberBundleX *fib, mitk::Image* img, mitk::PlanarFigure* startRoi, mitk::PlanarFigure* endRoi, bool avg=false, int number=25); - + /* \brief Creates tracts from a mitk::FiberBundleX and two planar figures indicating the start end end point */ + TractContainerType CreateTracts(mitk::FiberBundleX *fib, mitk::PlanarFigure* startRoi, mitk::PlanarFigure* endRoi); }; #endif