diff --git a/Modules/DiffusionImaging/IODataStructures/FiberBundleX/mitkFiberBundleX.cpp b/Modules/DiffusionImaging/IODataStructures/FiberBundleX/mitkFiberBundleX.cpp index f254971e40..74ba6604c6 100644 --- a/Modules/DiffusionImaging/IODataStructures/FiberBundleX/mitkFiberBundleX.cpp +++ b/Modules/DiffusionImaging/IODataStructures/FiberBundleX/mitkFiberBundleX.cpp @@ -1,1288 +1,1374 @@ /*=================================================================== 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 "mitkFiberBundleX.h" #include <mitkPlanarCircle.h> #include <mitkPlanarPolygon.h> #include <mitkPlanarFigureComposite.h> #include <vtkPointData.h> #include <vtkDataArray.h> #include <vtkUnsignedCharArray.h> #include <vtkPolyLine.h> #include <vtkCellArray.h> #include <vtkCellData.h> #include <vtkIdFilter.h> #include <vtkClipPolyData.h> #include <vtkPlane.h> #include <vtkDoubleArray.h> #include <vtkKochanekSpline.h> #include <vtkParametricFunctionSource.h> #include <vtkParametricSpline.h> #include <vtkPolygon.h> #include <vtkCleanPolyData.h> #include <math.h> const char* mitk::FiberBundleX::COLORCODING_ORIENTATION_BASED = "Color_Orient"; //const char* mitk::FiberBundleX::COLORCODING_FA_AS_OPACITY = "Color_Orient_FA_Opacity"; const char* mitk::FiberBundleX::COLORCODING_FA_BASED = "FA_Values"; const char* mitk::FiberBundleX::COLORCODING_CUSTOM = "custom"; const char* mitk::FiberBundleX::FIBER_ID_ARRAY = "Fiber_IDs"; mitk::FiberBundleX::FiberBundleX( vtkPolyData* fiberPolyData ) : m_CurrentColorCoding(NULL) , m_NumFibers(0) { m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New(); if (fiberPolyData != NULL) { vtkSmartPointer<vtkCleanPolyData> cleaner = vtkSmartPointer<vtkCleanPolyData>::New(); cleaner->SetInput(fiberPolyData); cleaner->Update(); fiberPolyData = cleaner->GetOutput(); m_FiberPolyData->DeepCopy(fiberPolyData); this->DoColorCodingOrientationBased(); } if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED)) MITK_DEBUG << "ok"; vtkUnsignedCharArray* tmpColors = (vtkUnsignedCharArray*) m_FiberPolyData->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED); if (tmpColors!=NULL) { int tmpColorss = tmpColors->GetNumberOfTuples(); int tmpColorc = tmpColors->GetNumberOfComponents(); } m_NumFibers = m_FiberPolyData->GetNumberOfLines(); this->UpdateFiberGeometry(); this->SetColorCoding(COLORCODING_ORIENTATION_BASED); this->GenerateFiberIds(); } mitk::FiberBundleX::~FiberBundleX() { } mitk::FiberBundleX::Pointer mitk::FiberBundleX::GetDeepCopy() { mitk::FiberBundleX::Pointer newFib = mitk::FiberBundleX::New(m_FiberPolyData); if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED)) MITK_DEBUG << "ok"; vtkUnsignedCharArray* tmpColors = (vtkUnsignedCharArray*) m_FiberPolyData->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED); int tmpColorss = tmpColors->GetNumberOfTuples(); int tmpColorc = tmpColors->GetNumberOfComponents(); newFib->SetColorCoding(m_CurrentColorCoding); return newFib; } vtkSmartPointer<vtkPolyData> mitk::FiberBundleX::GeneratePolyDataByIds(std::vector<long> fiberIds) { MITK_DEBUG << "\n=====FINAL RESULT: fib_id ======\n"; MITK_DEBUG << "Number of new Fibers: " << fiberIds.size(); // iterate through the vectorcontainer hosting all desired fiber Ids vtkSmartPointer<vtkPolyData> newFiberPolyData = vtkSmartPointer<vtkPolyData>::New(); vtkSmartPointer<vtkCellArray> newLineSet = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkPoints> newPointSet = vtkSmartPointer<vtkPoints>::New(); // if FA array available, initialize fa double array // if color orient array is available init color array vtkSmartPointer<vtkDoubleArray> faValueArray; vtkSmartPointer<vtkUnsignedCharArray> colorsT; //colors and alpha value for each single point, RGBA = 4 components unsigned char rgba[4] = {0,0,0,0}; int componentSize = sizeof(rgba); if (m_FiberIdDataSet->GetPointData()->HasArray(COLORCODING_FA_BASED)){ MITK_DEBUG << "FA VALUES AVAILABLE, init array for new fiberbundle"; faValueArray = vtkSmartPointer<vtkDoubleArray>::New(); } if (m_FiberIdDataSet->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED)){ MITK_DEBUG << "colorValues available, init array for new fiberbundle"; colorsT = vtkUnsignedCharArray::New(); colorsT->SetNumberOfComponents(componentSize); colorsT->SetName(COLORCODING_ORIENTATION_BASED); } std::vector<long>::iterator finIt = fiberIds.begin(); while ( finIt != fiberIds.end() ) { if (*finIt < 0 || *finIt>GetNumFibers()){ MITK_INFO << "FiberID can not be negative or >NumFibers!!! check id Extraction!" << *finIt; break; } vtkSmartPointer<vtkCell> fiber = m_FiberIdDataSet->GetCell(*finIt);//->DeepCopy(fiber); vtkSmartPointer<vtkPoints> fibPoints = fiber->GetPoints(); vtkSmartPointer<vtkPolyLine> newFiber = vtkSmartPointer<vtkPolyLine>::New(); newFiber->GetPointIds()->SetNumberOfIds( fibPoints->GetNumberOfPoints() ); for(int i=0; i<fibPoints->GetNumberOfPoints(); i++) { // MITK_DEBUG << "id: " << fiber->GetPointId(i); // MITK_DEBUG << fibPoints->GetPoint(i)[0] << " | " << fibPoints->GetPoint(i)[1] << " | " << fibPoints->GetPoint(i)[2]; newFiber->GetPointIds()->SetId(i, newPointSet->GetNumberOfPoints()); newPointSet->InsertNextPoint(fibPoints->GetPoint(i)[0], fibPoints->GetPoint(i)[1], fibPoints->GetPoint(i)[2]); if (m_FiberIdDataSet->GetPointData()->HasArray(COLORCODING_FA_BASED)){ // MITK_DEBUG << m_FiberIdDataSet->GetPointData()->GetArray(FA_VALUE_ARRAY)->GetTuple(fiber->GetPointId(i)); } if (m_FiberIdDataSet->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED)){ // MITK_DEBUG << "ColorValue: " << m_FiberIdDataSet->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED)->GetTuple(fiber->GetPointId(i))[0]; } } newLineSet->InsertNextCell(newFiber); ++finIt; } newFiberPolyData->SetPoints(newPointSet); newFiberPolyData->SetLines(newLineSet); MITK_DEBUG << "new fiberbundle polydata points: " << newFiberPolyData->GetNumberOfPoints(); MITK_DEBUG << "new fiberbundle polydata lines: " << newFiberPolyData->GetNumberOfLines(); MITK_DEBUG << "=====================\n"; // mitk::FiberBundleX::Pointer newFib = mitk::FiberBundleX::New(newFiberPolyData); return newFiberPolyData; } // merge two fiber bundles mitk::FiberBundleX::Pointer mitk::FiberBundleX::AddBundle(mitk::FiberBundleX* fib) { if (fib==NULL) { MITK_WARN << "trying to call AddBundle with NULL argument"; return NULL; } vtkSmartPointer<vtkPolyData> vNewPolyData = vtkSmartPointer<vtkPolyData>::New(); vtkSmartPointer<vtkCellArray> vNewLines = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkPoints> vNewPoints = vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkCellArray> vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); // add current fiber bundle int numFibers = GetNumFibers(); for( int i=0; i<numFibers; i++ ) { vtkIdType numPoints(0); vtkIdType* points(NULL); vLines->GetNextCell ( numPoints, points ); vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New(); for( int j=0; j<numPoints; j++) { vtkIdType id = vNewPoints->InsertNextPoint(m_FiberPolyData->GetPoint(points[j])); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } vLines = fib->m_FiberPolyData->GetLines(); vLines->InitTraversal(); // add new fiber bundle numFibers = fib->GetNumFibers(); for( int i=0; i<numFibers; i++ ) { vtkIdType numPoints(0); vtkIdType* points(NULL); vLines->GetNextCell ( numPoints, points ); vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New(); for( int j=0; j<numPoints; j++) { vtkIdType id = vNewPoints->InsertNextPoint(fib->m_FiberPolyData->GetPoint(points[j])); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } // initialize polydata vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundleX::Pointer newFib = mitk::FiberBundleX::New(vNewPolyData); return newFib; } // subtract two fiber bundles mitk::FiberBundleX::Pointer mitk::FiberBundleX::SubtractBundle(mitk::FiberBundleX* fib) { vtkSmartPointer<vtkPolyData> vNewPolyData = vtkSmartPointer<vtkPolyData>::New(); vtkSmartPointer<vtkCellArray> vNewLines = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkPoints> vNewPoints = vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkCellArray> vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); // iterate over current fibers int numFibers = GetNumFibers(); for( int i=0; i<numFibers; i++ ) { vtkIdType numPoints(0); vtkIdType* points(NULL); vLines->GetNextCell ( numPoints, points ); vtkSmartPointer<vtkCellArray> vLines2 = fib->m_FiberPolyData->GetLines(); vLines2->InitTraversal(); int numFibers2 = fib->GetNumFibers(); bool contained = false; for( int i2=0; i2<numFibers2; i2++ ) { vtkIdType numPoints2(0); vtkIdType* points2(NULL); vLines2->GetNextCell ( numPoints2, points2 ); // check endpoints itk::Point<float, 3> point_start = GetItkPoint(m_FiberPolyData->GetPoint(points[0])); itk::Point<float, 3> point_end = GetItkPoint(m_FiberPolyData->GetPoint(points[numPoints-1])); itk::Point<float, 3> point2_start = GetItkPoint(fib->m_FiberPolyData->GetPoint(points2[0])); itk::Point<float, 3> point2_end = GetItkPoint(fib->m_FiberPolyData->GetPoint(points2[numPoints2-1])); if (point_start.SquaredEuclideanDistanceTo(point2_start)<=mitk::eps && point_end.SquaredEuclideanDistanceTo(point2_end)<=mitk::eps || point_start.SquaredEuclideanDistanceTo(point2_end)<=mitk::eps && point_end.SquaredEuclideanDistanceTo(point2_start)<=mitk::eps) { // further checking ??? if (numPoints2==numPoints) contained = true; } } // add to result because fiber is not subtracted if (!contained) { vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New(); for( int j=0; j<numPoints; j++) { vtkIdType id = vNewPoints->InsertNextPoint(m_FiberPolyData->GetPoint(points[j])); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } } if(vNewLines->GetNumberOfCells()==0) return NULL; // initialize polydata vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundleX::Pointer newFib = mitk::FiberBundleX::New(vNewPolyData); return newFib; } itk::Point<float, 3> mitk::FiberBundleX::GetItkPoint(double point[3]) { itk::Point<float, 3> itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } /* * set polydata (additional flag to recompute fiber geometry, default = true) */ void mitk::FiberBundleX::SetFiberPolyData(vtkSmartPointer<vtkPolyData> fiberPD, bool updateGeometry) { if (fiberPD == NULL) this->m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New(); else { m_FiberPolyData->DeepCopy(fiberPD); DoColorCodingOrientationBased(); } m_NumFibers = m_FiberPolyData->GetNumberOfLines(); if (updateGeometry) UpdateFiberGeometry(); SetColorCoding(COLORCODING_ORIENTATION_BASED); GenerateFiberIds(); } /* * return vtkPolyData */ vtkSmartPointer<vtkPolyData> mitk::FiberBundleX::GetFiberPolyData() { return m_FiberPolyData; } void mitk::FiberBundleX::DoColorCodingOrientationBased() { //===== FOR WRITING A TEST ======================== // colorT size == tupelComponents * tupelElements // compare color results // to cover this code 100% also polydata needed, where colorarray already exists // + one fiber with exactly 1 point // + one fiber with 0 points //================================================= /* make sure that processing colorcoding is only called when necessary */ if ( m_FiberPolyData->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED) && m_FiberPolyData->GetNumberOfPoints() == m_FiberPolyData->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED)->GetNumberOfTuples() ) { // fiberstructure is already colorcoded MITK_DEBUG << " NO NEED TO REGENERATE COLORCODING! " ; this->ResetFiberOpacity(); this->SetColorCoding(COLORCODING_ORIENTATION_BASED); return; } /* Finally, execute color calculation */ vtkPoints* extrPoints = NULL; extrPoints = m_FiberPolyData->GetPoints(); int numOfPoints = 0; if (extrPoints!=NULL) numOfPoints = extrPoints->GetNumberOfPoints(); //colors and alpha value for each single point, RGBA = 4 components unsigned char rgba[4] = {0,0,0,0}; // int componentSize = sizeof(rgba); int componentSize = 4; vtkSmartPointer<vtkUnsignedCharArray> colorsT = vtkUnsignedCharArray::New(); colorsT->Allocate(numOfPoints * componentSize); colorsT->SetNumberOfComponents(componentSize); colorsT->SetName(COLORCODING_ORIENTATION_BASED); /* checkpoint: does polydata contain any fibers */ int numOfFibers = m_FiberPolyData->GetNumberOfLines(); if (numOfFibers < 1) { MITK_DEBUG << "\n ========= Number of Fibers is 0 and below ========= \n"; return; } /* extract single fibers of fiberBundle */ vtkCellArray* fiberList = m_FiberPolyData->GetLines(); fiberList->InitTraversal(); for (int fi=0; fi<numOfFibers; ++fi) { vtkIdType* idList; // contains the point id's of the line vtkIdType pointsPerFiber; // number of points for current line fiberList->GetNextCell(pointsPerFiber, idList); // MITK_DEBUG << "Fib#: " << fi << " of " << numOfFibers << " pnts in fiber: " << pointsPerFiber ; /* single fiber checkpoints: is number of points valid */ if (pointsPerFiber > 1) { /* operate on points of single fiber */ for (int i=0; i <pointsPerFiber; ++i) { /* process all points except starting and endpoint * for calculating color value take current point, previous point and next point */ if (i<pointsPerFiber-1 && i > 0) { /* The color value of the current point is influenced by the previous point and next point. */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+1])[2]); vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]); vnl_vector_fixed< double, 3 > diff1; diff1 = currentPntvtk - nextPntvtk; vnl_vector_fixed< double, 3 > diff2; diff2 = currentPntvtk - prevPntvtk; vnl_vector_fixed< double, 3 > diff; diff = (diff1 - diff2) / 2.0; diff.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff[2])); rgba[3] = (unsigned char) (255.0); } else if (i==0) { /* First point has no previous point, therefore only diff1 is taken */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+1])[2]); vnl_vector_fixed< double, 3 > diff1; diff1 = currentPntvtk - nextPntvtk; diff1.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff1[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff1[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff1[2])); rgba[3] = (unsigned char) (255.0); } else if (i==pointsPerFiber-1) { /* Last point has no next point, therefore only diff2 is taken */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]); vnl_vector_fixed< double, 3 > diff2; diff2 = currentPntvtk - prevPntvtk; diff2.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff2[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff2[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff2[2])); rgba[3] = (unsigned char) (255.0); } colorsT->InsertTupleValue(idList[i], rgba); } //end for loop } else if (pointsPerFiber == 1) { /* a single point does not define a fiber (use vertex mechanisms instead */ continue; // colorsT->InsertTupleValue(0, rgba); } else { MITK_DEBUG << "Fiber with 0 points detected... please check your tractography algorithm!" ; continue; } }//end for loop m_FiberPolyData->GetPointData()->AddArray(colorsT); /*========================= - this is more relevant for renderer than for fiberbundleX datastructure - think about sourcing this to a explicit method which coordinates colorcoding */ this->SetColorCoding(COLORCODING_ORIENTATION_BASED); // =========================== //mini test, shall be ported to MITK TESTINGS! if (colorsT->GetSize() != numOfPoints*componentSize) MITK_DEBUG << "ALLOCATION ERROR IN INITIATING COLOR ARRAY"; } void mitk::FiberBundleX::DoColorCodingFaBased() { if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_FA_BASED) != 1 ) return; this->SetColorCoding(COLORCODING_FA_BASED); MITK_DEBUG << "FBX: done CC FA based"; this->GenerateFiberIds(); } void mitk::FiberBundleX::DoUseFaFiberOpacity() { if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_FA_BASED) != 1 ) return; if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED) != 1 ) return; vtkDoubleArray* FAValArray = (vtkDoubleArray*) m_FiberPolyData->GetPointData()->GetArray(COLORCODING_FA_BASED); vtkUnsignedCharArray* ColorArray = dynamic_cast<vtkUnsignedCharArray*> (m_FiberPolyData->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED)); for(long i=0; i<ColorArray->GetNumberOfTuples(); i++) { double faValue = FAValArray->GetValue(i); faValue = faValue * 255.0; ColorArray->SetComponent(i,3, (unsigned char) faValue ); } this->SetColorCoding(COLORCODING_ORIENTATION_BASED); MITK_DEBUG << "FBX: done CC OPACITY"; this->GenerateFiberIds(); } void mitk::FiberBundleX::ResetFiberOpacity() { vtkUnsignedCharArray* ColorArray = dynamic_cast<vtkUnsignedCharArray*> (m_FiberPolyData->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED)); if (ColorArray==NULL) return; for(long i=0; i<ColorArray->GetNumberOfTuples(); i++) ColorArray->SetComponent(i,3, 255.0 ); } void mitk::FiberBundleX::SetFAMap(mitk::Image::Pointer FAimage) { MITK_DEBUG << "SetFAMap"; vtkSmartPointer<vtkDoubleArray> faValues = vtkDoubleArray::New(); faValues->SetName(COLORCODING_FA_BASED); faValues->Allocate(m_FiberPolyData->GetNumberOfPoints()); // MITK_DEBUG << faValues->GetNumberOfTuples(); // MITK_DEBUG << faValues->GetSize(); faValues->SetNumberOfValues(m_FiberPolyData->GetNumberOfPoints()); // MITK_DEBUG << faValues->GetNumberOfTuples(); // MITK_DEBUG << faValues->GetSize(); vtkPoints* pointSet = m_FiberPolyData->GetPoints(); for(long i=0; i<m_FiberPolyData->GetNumberOfPoints(); ++i) { Point3D px; px[0] = pointSet->GetPoint(i)[0]; px[1] = pointSet->GetPoint(i)[1]; px[2] = pointSet->GetPoint(i)[2]; double faPixelValue = 1-FAimage->GetPixelValueByWorldCoordinate(px); // faValues->InsertNextTuple1(faPixelValue); faValues->InsertValue(i, faPixelValue); // MITK_DEBUG << faPixelValue; // MITK_DEBUG << faValues->GetValue(i); } m_FiberPolyData->GetPointData()->AddArray(faValues); this->GenerateFiberIds(); if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_FA_BASED)) MITK_DEBUG << "FA VALUE ARRAY SET"; // vtkDoubleArray* valueArray = (vtkDoubleArray*) m_FiberPolyData->GetPointData()->GetArray(FA_VALUE_ARRAY); // for(long i=0; i<m_FiberPolyData->GetNumberOfPoints(); i++) // { // MITK_DEBUG << "value at pos "<< i << ": " << valueArray->GetValue(i); // } } void mitk::FiberBundleX::GenerateFiberIds() { if (m_FiberPolyData == NULL) return; vtkSmartPointer<vtkIdFilter> idFiberFilter = vtkSmartPointer<vtkIdFilter>::New(); idFiberFilter->SetInput(m_FiberPolyData); idFiberFilter->CellIdsOn(); // idFiberFilter->PointIdsOn(); // point id's are not needed idFiberFilter->SetIdsArrayName(FIBER_ID_ARRAY); idFiberFilter->FieldDataOn(); idFiberFilter->Update(); m_FiberIdDataSet = idFiberFilter->GetOutput(); MITK_DEBUG << "Generating Fiber Ids...[done] | " << m_FiberIdDataSet->GetNumberOfCells(); } mitk::FiberBundleX::Pointer mitk::FiberBundleX::ExtractFiberSubset(mitk::PlanarFigure* pf) { if (pf==NULL) return NULL; std::vector<long> tmp = ExtractFiberIdSubset(pf); if (tmp.size()<=0) return mitk::FiberBundleX::New(); vtkSmartPointer<vtkPolyData> pTmp = GeneratePolyDataByIds(tmp); return mitk::FiberBundleX::New(pTmp); } std::vector<long> mitk::FiberBundleX::ExtractFiberIdSubset(mitk::PlanarFigure* pf) { MITK_DEBUG << "Extracting fibers!"; // vector which is returned, contains all extracted FiberIds std::vector<long> FibersInROI; if (pf==NULL) return FibersInROI; /* Handle type of planarfigure */ // if incoming pf is a pfc mitk::PlanarFigureComposite::Pointer pfcomp= dynamic_cast<mitk::PlanarFigureComposite*>(pf); if (!pfcomp.IsNull()) { // process requested boolean operation of PFC switch (pfcomp->getOperationType()) { case 0: { MITK_DEBUG << "AND PROCESSING"; //AND //temporarly store results of the child in this vector, we need that to accumulate the std::vector<long> childResults = this->ExtractFiberIdSubset(pfcomp->getChildAt(0)); MITK_DEBUG << "first roi got fibers in ROI: " << childResults.size(); MITK_DEBUG << "sorting..."; std::sort(childResults.begin(), childResults.end()); MITK_DEBUG << "sorting done"; std::vector<long> AND_Assamblage(childResults.size()); //std::vector<unsigned long> AND_Assamblage; fill(AND_Assamblage.begin(), AND_Assamblage.end(), -1); //AND_Assamblage.reserve(childResults.size()); //max size AND can reach anyway std::vector<long>::iterator it; for (int i=1; i<pfcomp->getNumberOfChildren(); ++i) { std::vector<long> tmpChild = this->ExtractFiberIdSubset(pfcomp->getChildAt(i)); MITK_DEBUG << "ROI " << i << " has fibers in ROI: " << tmpChild.size(); sort(tmpChild.begin(), tmpChild.end()); it = std::set_intersection(childResults.begin(), childResults.end(), tmpChild.begin(), tmpChild.end(), AND_Assamblage.begin() ); } MITK_DEBUG << "resize Vector"; long i=0; while (i < AND_Assamblage.size() && AND_Assamblage[i] != -1){ //-1 represents a placeholder in the array ++i; } AND_Assamblage.resize(i); MITK_DEBUG << "returning AND vector, size: " << AND_Assamblage.size(); return AND_Assamblage; // break; } case 1: { //OR std::vector<long> OR_Assamblage = this->ExtractFiberIdSubset(pfcomp->getChildAt(0)); std::vector<long>::iterator it; MITK_DEBUG << OR_Assamblage.size(); for (int i=1; i<pfcomp->getNumberOfChildren(); ++i) { it = OR_Assamblage.end(); std::vector<long> tmpChild = this->ExtractFiberIdSubset(pfcomp->getChildAt(i)); OR_Assamblage.insert(it, tmpChild.begin(), tmpChild.end()); MITK_DEBUG << "ROI " << i << " has fibers in ROI: " << tmpChild.size() << " OR Assamblage: " << OR_Assamblage.size(); } sort(OR_Assamblage.begin(), OR_Assamblage.end()); it = unique(OR_Assamblage.begin(), OR_Assamblage.end()); OR_Assamblage.resize( it - OR_Assamblage.begin() ); MITK_DEBUG << "returning OR vector, size: " << OR_Assamblage.size(); return OR_Assamblage; } case 2: { //NOT //get IDs of all fibers std::vector<long> childResults; childResults.reserve(this->GetNumFibers()); vtkSmartPointer<vtkDataArray> idSet = m_FiberIdDataSet->GetCellData()->GetArray(FIBER_ID_ARRAY); MITK_DEBUG << "m_NumOfFib: " << this->GetNumFibers() << " cellIdNum: " << idSet->GetNumberOfTuples(); for(long i=0; i<this->GetNumFibers(); i++) { MITK_DEBUG << "i: " << i << " idset: " << idSet->GetTuple(i)[0]; childResults.push_back(idSet->GetTuple(i)[0]); } std::sort(childResults.begin(), childResults.end()); std::vector<long> NOT_Assamblage(childResults.size()); //fill it with -1, otherwise 0 will be stored and 0 can also be an ID of fiber! fill(NOT_Assamblage.begin(), NOT_Assamblage.end(), -1); std::vector<long>::iterator it; for (long i=0; i<pfcomp->getNumberOfChildren(); ++i) { std::vector<long> tmpChild = ExtractFiberIdSubset(pfcomp->getChildAt(i)); sort(tmpChild.begin(), tmpChild.end()); it = std::set_difference(childResults.begin(), childResults.end(), tmpChild.begin(), tmpChild.end(), NOT_Assamblage.begin() ); } MITK_DEBUG << "resize Vector"; long i=0; while (NOT_Assamblage[i] != -1){ //-1 represents a placeholder in the array ++i; } NOT_Assamblage.resize(i); return NOT_Assamblage; } default: MITK_DEBUG << "we have an UNDEFINED composition... ERROR" ; break; } } else { mitk::Geometry2D::ConstPointer pfgeometry = pf->GetGeometry2D(); const mitk::PlaneGeometry* planeGeometry = dynamic_cast<const mitk::PlaneGeometry*> (pfgeometry.GetPointer()); Vector3D planeNormal = planeGeometry->GetNormal(); planeNormal.Normalize(); Point3D planeOrigin = planeGeometry->GetOrigin(); MITK_DEBUG << "planeOrigin: " << planeOrigin[0] << " | " << planeOrigin[1] << " | " << planeOrigin[2] << endl; MITK_DEBUG << "planeNormal: " << planeNormal[0] << " | " << planeNormal[1] << " | " << planeNormal[2] << endl; std::vector<int> PointsOnPlane; // contains all pointIds which are crossing the cutting plane std::vector<int> PointsInROI; // based on PointsOnPlane, all ROI relevant point IDs are stored here /* Define cutting plane by ROI (PlanarFigure) */ vtkSmartPointer<vtkPlane> plane = vtkSmartPointer<vtkPlane>::New(); plane->SetOrigin(planeOrigin[0],planeOrigin[1],planeOrigin[2]); plane->SetNormal(planeNormal[0],planeNormal[1],planeNormal[2]); //same plane but opposite normal direction. so point cloud will be reduced -> better performance // vtkSmartPointer<vtkPlane> planeR = vtkSmartPointer<vtkPlane>::New(); //define new origin along the normal but close to the original one // OriginNew = OriginOld + 1*Normal // Vector3D extendedNormal; // int multiplyFactor = 1; // extendedNormal[0] = planeNormal[0] * multiplyFactor; // extendedNormal[1] = planeNormal[1] * multiplyFactor; // extendedNormal[2] = planeNormal[2] * multiplyFactor; // Point3D RplaneOrigin = planeOrigin - extendedNormal; // planeR->SetOrigin(RplaneOrigin[0],RplaneOrigin[1],RplaneOrigin[2]); // planeR->SetNormal(-planeNormal[0],-planeNormal[1],-planeNormal[2]); // MITK_DEBUG << "RPlaneOrigin: " << RplaneOrigin[0] << " | " << RplaneOrigin[1] // << " | " << RplaneOrigin[2]; /* get all points/fibers cutting the plane */ MITK_DEBUG << "start clipping"; vtkSmartPointer<vtkClipPolyData> clipper = vtkSmartPointer<vtkClipPolyData>::New(); clipper->SetInput(m_FiberIdDataSet); clipper->SetClipFunction(plane); clipper->GenerateClipScalarsOn(); clipper->GenerateClippedOutputOn(); vtkSmartPointer<vtkPolyData> clipperout = clipper->GetClippedOutput(); MITK_DEBUG << "end clipping"; /* for some reason clipperoutput is not initialized for futher processing * so far only writing out clipped polydata provides requested */ // MITK_DEBUG << "writing clipper output"; // vtkSmartPointer<vtkPolyDataWriter> writerC = vtkSmartPointer<vtkPolyDataWriter>::New(); // writerC->SetInput(clipperout1); // writerC->SetFileName("/vtkOutput/Clipping.vtk"); // writerC->SetFileTypeToASCII(); // writerC->Write(); // MITK_DEBUG << "writing done"; MITK_DEBUG << "init and update clipperoutput"; clipperout->GetPointData()->Initialize(); clipperout->Update(); MITK_DEBUG << "init and update clipperoutput completed"; // MITK_DEBUG << "start clippingRecursive"; // vtkSmartPointer<vtkClipPolyData> Rclipper = vtkSmartPointer<vtkClipPolyData>::New(); // Rclipper->SetInput(clipperout1); // Rclipper->SetClipFunction(planeR); // Rclipper->GenerateClipScalarsOn(); // Rclipper->GenerateClippedOutputOn(); // vtkSmartPointer<vtkPolyData> clipperout = Rclipper->GetClippedOutput(); // MITK_DEBUG << "end clipping recursive"; // MITK_DEBUG << "writing clipper output 2"; // vtkSmartPointer<vtkPolyDataWriter> writerC1 = vtkSmartPointer<vtkPolyDataWriter>::New(); // writerC1->SetInput(clipperout); // writerC1->SetFileName("/vtkOutput/RClipping.vtk"); // writerC1->SetFileTypeToASCII(); // writerC1->Write(); // MITK_DEBUG << "init and update clipperoutput"; // clipperout->GetPointData()->Initialize(); // clipperout->Update(); // MITK_DEBUG << "init and update clipperoutput completed"; MITK_DEBUG << "STEP 1: find all points which have distance 0 to the given plane"; /*======STEP 1====== * extract all points, which are crossing the plane */ // Scalar values describe the distance between each remaining point to the given plane. Values sorted by point index vtkSmartPointer<vtkDataArray> distanceList = clipperout->GetPointData()->GetScalars(); vtkIdType sizeOfList = distanceList->GetNumberOfTuples(); PointsOnPlane.reserve(sizeOfList); /* use reserve for high-performant push_back, no hidden copy procedures are processed then! * size of list can be optimized by reducing allocation, but be aware of iterator and vector size*/ for (int i=0; i<sizeOfList; ++i) { double *distance = distanceList->GetTuple(i); // check if point is on plane. // 0.01 due to some approximation errors when calculating distance if (distance[0] >= -0.01 && distance[0] <= 0.01) PointsOnPlane.push_back(i); } // DEBUG print out all interesting points, stop where array starts with value -1. after -1 no more interesting idx are set! // std::vector<int>::iterator rit = PointsOnPlane.begin(); // while (rit != PointsOnPlane.end() ) { // std::cout << "interesting point: " << *rit << " coord: " << clipperout->GetPoint(*rit)[0] << " | " << clipperout->GetPoint(*rit)[1] << " | " << clipperout->GetPoint(*rit)[2] << endl; // rit++; // } MITK_DEBUG << "Num Of points on plane: " << PointsOnPlane.size(); MITK_DEBUG << "Step 2: extract Interesting points with respect to given extraction planarFigure"; PointsInROI.reserve(PointsOnPlane.size()); /*=======STEP 2===== * extract ROI relevant pointIds */ mitk::PlanarCircle::Pointer circleName = mitk::PlanarCircle::New(); mitk::PlanarPolygon::Pointer polyName = mitk::PlanarPolygon::New(); if ( pf->GetNameOfClass() == circleName->GetNameOfClass() ) { //calculate circle radius mitk::Point3D V1w = pf->GetWorldControlPoint(0); //centerPoint mitk::Point3D V2w = pf->GetWorldControlPoint(1); //radiusPoint double distPF = V1w.EuclideanDistanceTo(V2w); for (int i=0; i<PointsOnPlane.size(); i++) { //distance between circle radius and given point double XdistPnt = sqrt((double) (clipperout->GetPoint(PointsOnPlane[i])[0] - V1w[0]) * (clipperout->GetPoint(PointsOnPlane[i])[0] - V1w[0]) + (clipperout->GetPoint(PointsOnPlane[i])[1] - V1w[1]) * (clipperout->GetPoint(PointsOnPlane[i])[1] - V1w[1]) + (clipperout->GetPoint(PointsOnPlane[i])[2] - V1w[2]) * (clipperout->GetPoint(PointsOnPlane[i])[2] - V1w[2])) ; if( XdistPnt <= distPF) PointsInROI.push_back(PointsOnPlane[i]); } } else if ( pf->GetNameOfClass() == polyName->GetNameOfClass() ) { //create vtkPolygon using controlpoints from planarFigure polygon vtkSmartPointer<vtkPolygon> polygonVtk = vtkPolygon::New(); //get the control points from pf and insert them to vtkPolygon unsigned int nrCtrlPnts = pf->GetNumberOfControlPoints(); for (int i=0; i<nrCtrlPnts; ++i) { polygonVtk->GetPoints()->InsertNextPoint((double)pf->GetWorldControlPoint(i)[0], (double)pf->GetWorldControlPoint(i)[1], (double)pf->GetWorldControlPoint(i)[2] ); } //prepare everything for using pointInPolygon function double n[3]; polygonVtk->ComputeNormal(polygonVtk->GetPoints()->GetNumberOfPoints(), static_cast<double*>(polygonVtk->GetPoints()->GetData()->GetVoidPointer(0)), n); double bounds[6]; polygonVtk->GetPoints()->GetBounds(bounds); for (int i=0; i<PointsOnPlane.size(); i++) { double checkIn[3] = {clipperout->GetPoint(PointsOnPlane[i])[0], clipperout->GetPoint(PointsOnPlane[i])[1], clipperout->GetPoint(PointsOnPlane[i])[2]}; int isInPolygon = polygonVtk->PointInPolygon(checkIn, polygonVtk->GetPoints()->GetNumberOfPoints() , static_cast<double*>(polygonVtk->GetPoints()->GetData()->GetVoidPointer(0)), bounds, n); if( isInPolygon ) PointsInROI.push_back(PointsOnPlane[i]); } } MITK_DEBUG << "Step3: Identify fibers"; // we need to access the fiberId Array, so make sure that this array is available if (!clipperout->GetCellData()->HasArray(FIBER_ID_ARRAY)) { MITK_DEBUG << "ERROR: FiberID array does not exist, no correlation between points and fiberIds possible! Make sure calling GenerateFiberIds()"; return FibersInROI; // FibersInRoi is empty then } if (PointsInROI.size()<=0) return FibersInROI; // prepare a structure where each point id is represented as an indexId. // vector looks like: | pntId | fiberIdx | std::vector< long > pointindexFiberMap; // walk through the whole subline section and create an vector sorted by point index vtkCellArray *clipperlines = clipperout->GetLines(); clipperlines->InitTraversal(); long numOfLineCells = clipperlines->GetNumberOfCells(); long numofClippedPoints = clipperout->GetNumberOfPoints(); pointindexFiberMap.resize(numofClippedPoints); //prepare resulting vector FibersInROI.reserve(PointsInROI.size()); MITK_DEBUG << "\n===== Pointindex based structure initialized ======\n"; // go through resulting "sub"lines which are stored as cells, "i" corresponds to current line id. for (int i=0, ic=0 ; i<numOfLineCells; i++, ic+=3) { //ic is the index counter for the cells hosting the desired information, eg. 2 | 45 | 46. each cell consits of 3 items. vtkIdType npts; vtkIdType *pts; clipperlines->GetCell(ic, npts, pts); // go through point ids in hosting subline, "j" corresponds to current pointindex in current line i. eg. idx[0]=45; idx[1]=46 for (long j=0; j<npts; j++) { // MITK_DEBUG << "writing fiber id: " << clipperout->GetCellData()->GetArray(FIBER_ID_ARRAY)->GetTuple(i)[0] << " to pointId: " << pts[j]; pointindexFiberMap[ pts[j] ] = clipperout->GetCellData()->GetArray(FIBER_ID_ARRAY)->GetTuple(i)[0]; // MITK_DEBUG << "in array: " << pointindexFiberMap[ pts[j] ]; } } MITK_DEBUG << "\n===== Pointindex based structure finalized ======\n"; // get all Points in ROI with according fiberID for (long k = 0; k < PointsInROI.size(); k++) { //MITK_DEBUG << "point " << PointsInROI[k] << " belongs to fiber " << pointindexFiberMap[ PointsInROI[k] ]; if (pointindexFiberMap[ PointsInROI[k] ]<=GetNumFibers() && pointindexFiberMap[ PointsInROI[k] ]>=0) FibersInROI.push_back(pointindexFiberMap[ PointsInROI[k] ]); else MITK_INFO << "ERROR in ExtractFiberIdSubset; impossible fiber id detected"; } } // detecting fiberId duplicates MITK_DEBUG << "check for duplicates"; sort(FibersInROI.begin(), FibersInROI.end()); bool hasDuplicats = false; for(long i=0; i<FibersInROI.size()-1; ++i) { if(FibersInROI[i] == FibersInROI[i+1]) hasDuplicats = true; } if(hasDuplicats) { std::vector<long>::iterator it; it = unique (FibersInROI.begin(), FibersInROI.end()); FibersInROI.resize( it - FibersInROI.begin() ); } return FibersInROI; } void mitk::FiberBundleX::UpdateFiberGeometry() { if (m_NumFibers<=0) // no fibers present; apply default geometry { mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetImageGeometry(true); float b[] = {0, 1, 0, 1, 0, 1}; geometry->SetFloatBounds(b); SetGeometry(geometry); return; } float min = itk::NumericTraits<float>::NonpositiveMin(); float max = itk::NumericTraits<float>::max(); float b[] = {max, min, max, min, max, min}; vtkCellArray* cells = m_FiberPolyData->GetLines(); cells->InitTraversal(); for (int i=0; i<m_FiberPolyData->GetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int p = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; j<p; j++) { double p[3]; points->GetPoint(j, p); if (p[0]<b[0]) b[0]=p[0]; if (p[0]>b[1]) b[1]=p[0]; if (p[1]<b[2]) b[2]=p[1]; if (p[1]>b[3]) b[3]=p[1]; if (p[2]<b[4]) b[4]=p[2]; if (p[2]>b[5]) b[5]=p[2]; } } // provide some border margin for(int i=0; i<=4; i+=2) b[i] -=10; for(int i=1; i<=5; i+=2) b[i] +=10; mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetFloatBounds(b); this->SetGeometry(geometry); } QStringList mitk::FiberBundleX::GetAvailableColorCodings() { QStringList availableColorCodings; int numColors = m_FiberPolyData->GetPointData()->GetNumberOfArrays(); for(int i=0; i<numColors; i++) { availableColorCodings.append(m_FiberPolyData->GetPointData()->GetArrayName(i)); } //this controlstructure shall be implemented by the calling method if (availableColorCodings.isEmpty()) MITK_DEBUG << "no colorcodings available in fiberbundleX"; // for(int i=0; i<availableColorCodings.size(); i++) // { // MITK_DEBUG << availableColorCodings.at(i).toLocal8Bit().constData(); // } return availableColorCodings; } char* mitk::FiberBundleX::GetCurrentColorCoding() { return m_CurrentColorCoding; } void mitk::FiberBundleX::SetColorCoding(const char* requestedColorCoding) { if (requestedColorCoding==NULL) return; MITK_DEBUG << "SetColorCoding:" << requestedColorCoding; if( strcmp (COLORCODING_ORIENTATION_BASED,requestedColorCoding) == 0 ) { this->m_CurrentColorCoding = (char*) COLORCODING_ORIENTATION_BASED; } else if( strcmp (COLORCODING_FA_BASED,requestedColorCoding) == 0 ) { this->m_CurrentColorCoding = (char*) COLORCODING_FA_BASED; } else if( strcmp (COLORCODING_CUSTOM,requestedColorCoding) == 0 ) { this->m_CurrentColorCoding = (char*) COLORCODING_CUSTOM; } else { MITK_DEBUG << "FIBERBUNDLE X: UNKNOWN COLORCODING in FIBERBUNDLEX Datastructure"; this->m_CurrentColorCoding = (char*) COLORCODING_CUSTOM; //will cause blank colorcoding of fibers } } -void mitk::FiberBundleX::DoFiberSmoothing(int pointsPerCm) +void mitk::FiberBundleX::MirrorFibers(unsigned int axis) { + if (axis>2) + return; + + vtkSmartPointer<vtkPoints> vtkNewPoints = vtkPoints::New(); + vtkSmartPointer<vtkCellArray> vtkNewCells = vtkCellArray::New(); + + vtkSmartPointer<vtkCellArray> vLines = m_FiberPolyData->GetLines(); + vLines->InitTraversal(); + for (int i=0; i<m_NumFibers; i++) + { + vtkIdType numPoints(0); + vtkIdType* pointIds(NULL); + vLines->GetNextCell ( numPoints, pointIds ); + + vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New(); + for (int j=0; j<numPoints; j++) + { + double* p = m_FiberPolyData->GetPoint(pointIds[j]); + p[axis] = -p[axis]; + vtkIdType id = vtkNewPoints->InsertNextPoint(p); + container->GetPointIds()->InsertNextId(id); + } + vtkNewCells->InsertNextCell(container); + } + + m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New(); + m_FiberPolyData->SetPoints(vtkNewPoints); + m_FiberPolyData->SetLines(vtkNewCells); + UpdateColorCoding(); + UpdateFiberGeometry(); +} + +bool mitk::FiberBundleX::RemoveShortFibers(float lengthInMM) +{ + if (lengthInMM<=0) + return false; + + vtkSmartPointer<vtkPoints> vtkNewPoints = vtkPoints::New(); + vtkSmartPointer<vtkCellArray> vtkNewCells = vtkCellArray::New(); + + vtkSmartPointer<vtkCellArray> vLines = m_FiberPolyData->GetLines(); + vLines->InitTraversal(); + for (int i=0; i<m_NumFibers; i++) + { + vtkIdType numPoints(0); + vtkIdType* pointIds(NULL); + vLines->GetNextCell ( numPoints, pointIds ); + // calculate fiber length + float length = 0; + itk::Point<double> lastP; + for (int j=0; j<numPoints; j++) + { + double* p = m_FiberPolyData->GetPoint(pointIds[j]); + if (j>0) + length += sqrt(pow(p[0]-lastP[0], 2)+pow(p[1]-lastP[1], 2)+pow(p[2]-lastP[2], 2)); + lastP[0] = p[0]; + lastP[1] = p[1]; + lastP[2] = p[2]; + } + + if (length>=lengthInMM) + { + vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New(); + for (int j=0; j<numPoints; j++) + { + double* p = m_FiberPolyData->GetPoint(pointIds[j]); + vtkIdType id = vtkNewPoints->InsertNextPoint(p); + container->GetPointIds()->InsertNextId(id); + } + vtkNewCells->InsertNextCell(container); + } + } + + if (vtkNewCells->GetNumberOfCells()<=0) + return false; + + m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New(); + m_FiberPolyData->SetPoints(vtkNewPoints); + m_FiberPolyData->SetLines(vtkNewCells); + UpdateColorCoding(); + UpdateFiberGeometry(); + return true; +} + +void mitk::FiberBundleX::DoFiberSmoothing(int pointsPerCm) +{ vtkSmartPointer<vtkPoints> vtkSmoothPoints = vtkPoints::New(); //in smoothpoints the interpolated points representing a fiber are stored. //in vtkcells all polylines are stored, actually all id's of them are stored vtkSmartPointer<vtkCellArray> vtkSmoothCells = vtkCellArray::New(); //cellcontainer for smoothed lines vtkSmartPointer<vtkCellArray> vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); vtkIdType pointHelperCnt = 0; for (int i=0; i<m_NumFibers; i++) { vtkIdType numPoints(0); vtkIdType* pointIds(NULL); vLines->GetNextCell ( numPoints, pointIds ); vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New(); float length = 0; itk::Point<double> lastP; for (int j=0; j<numPoints; j++) { double* p = m_FiberPolyData->GetPoint(pointIds[j]); points->InsertNextPoint(p); if (j>0) length += sqrt(pow(p[0]-lastP[0], 2)+pow(p[1]-lastP[1], 2)+pow(p[2]-lastP[2], 2)); lastP[0] = p[0]; lastP[1] = p[1]; lastP[2] = p[2]; } length /=10; int sampling = pointsPerCm*length; /////PROCESS POLYLINE SMOOTHING///// vtkSmartPointer<vtkKochanekSpline> xSpline = vtkKochanekSpline::New(); vtkSmartPointer<vtkKochanekSpline> ySpline = vtkKochanekSpline::New(); vtkSmartPointer<vtkKochanekSpline> zSpline = vtkKochanekSpline::New(); vtkSmartPointer<vtkParametricSpline> spline = vtkParametricSpline::New(); spline->SetXSpline(xSpline); spline->SetYSpline(ySpline); spline->SetZSpline(zSpline); spline->SetPoints(points); vtkSmartPointer<vtkParametricFunctionSource> functionSource = vtkParametricFunctionSource::New(); functionSource->SetParametricFunction(spline); functionSource->SetUResolution(sampling); functionSource->SetVResolution(sampling); functionSource->SetWResolution(sampling); functionSource->Update(); vtkPolyData* outputFunction = functionSource->GetOutput(); vtkPoints* tmpSmoothPnts = outputFunction->GetPoints(); //smoothPoints of current fiber vtkSmartPointer<vtkPolyLine> smoothLine = vtkPolyLine::New(); smoothLine->GetPointIds()->SetNumberOfIds(tmpSmoothPnts->GetNumberOfPoints()); for (int j=0; j<smoothLine->GetNumberOfPoints(); j++) { smoothLine->GetPointIds()->SetId(j, j+pointHelperCnt); vtkSmoothPoints->InsertNextPoint(tmpSmoothPnts->GetPoint(j)); } vtkSmoothCells->InsertNextCell(smoothLine); pointHelperCnt += tmpSmoothPnts->GetNumberOfPoints(); } m_FiberPolyData = vtkSmartPointer<vtkPolyData>::New(); m_FiberPolyData->SetPoints(vtkSmoothPoints); m_FiberPolyData->SetLines(vtkSmoothCells); UpdateColorCoding(); UpdateFiberGeometry(); } // Resample fiber to get equidistant points void mitk::FiberBundleX::ResampleFibers(float pointDistance) { vtkSmartPointer<vtkPolyData> newPoly = vtkSmartPointer<vtkPolyData>::New(); vtkSmartPointer<vtkCellArray> newCellArray = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkCellArray> vLines = m_FiberPolyData->GetLines(); vLines->InitTraversal(); int numberOfLines = m_NumFibers; for (int i=0; i<numberOfLines; i++) { vtkIdType numPoints(0); vtkIdType* points(NULL); vLines->GetNextCell ( numPoints, points ); vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New(); double* point = m_FiberPolyData->GetPoint(points[0]); vtkIdType pointId = newPoints->InsertNextPoint(point); container->GetPointIds()->InsertNextId(pointId); float dtau = 0; int cur_p = 1; itk::Vector<float,3> dR; float normdR = 0; for (;;) { while (dtau <= pointDistance && cur_p < numPoints) { itk::Vector<float,3> v1; point = m_FiberPolyData->GetPoint(points[cur_p-1]); v1[0] = point[0]; v1[1] = point[1]; v1[2] = point[2]; itk::Vector<float,3> v2; point = m_FiberPolyData->GetPoint(points[cur_p]); v2[0] = point[0]; v2[1] = point[1]; v2[2] = point[2]; dR = v2 - v1; normdR = std::sqrt(dR.GetSquaredNorm()); dtau += normdR; cur_p++; } if (dtau >= pointDistance) { itk::Vector<float,3> v1; point = m_FiberPolyData->GetPoint(points[cur_p-1]); v1[0] = point[0]; v1[1] = point[1]; v1[2] = point[2]; itk::Vector<float,3> v2 = v1 - dR*( (dtau-pointDistance)/normdR ); pointId = newPoints->InsertNextPoint(v2.GetDataPointer()); container->GetPointIds()->InsertNextId(pointId); } else { point = m_FiberPolyData->GetPoint(points[numPoints-1]); pointId = newPoints->InsertNextPoint(point); container->GetPointIds()->InsertNextId(pointId); break; } dtau = dtau-pointDistance; } newCellArray->InsertNextCell(container); } newPoly->SetPoints(newPoints); newPoly->SetLines(newCellArray); m_FiberPolyData = newPoly; UpdateFiberGeometry(); UpdateColorCoding(); } // reapply selected colorcoding in case polydata structure has changed void mitk::FiberBundleX::UpdateColorCoding() { char* cc = GetCurrentColorCoding(); if( strcmp (COLORCODING_ORIENTATION_BASED,cc) == 0 ) DoColorCodingOrientationBased(); else if( strcmp (COLORCODING_FA_BASED,cc) == 0 ) DoColorCodingFaBased(); } // reapply selected colorcoding in case polydata structure has changed bool mitk::FiberBundleX::Equals(mitk::FiberBundleX* fib) { if (fib==NULL) return false; mitk::FiberBundleX::Pointer tempFib = this->SubtractBundle(fib); mitk::FiberBundleX::Pointer tempFib2 = fib->SubtractBundle(this); if (tempFib.IsNull() && tempFib2.IsNull()) return true; return false; } /* ESSENTIAL IMPLEMENTATION OF SUPERCLASS METHODS */ void mitk::FiberBundleX::UpdateOutputInformation() { } void mitk::FiberBundleX::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::FiberBundleX::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::FiberBundleX::VerifyRequestedRegion() { return true; } void mitk::FiberBundleX::SetRequestedRegion( itk::DataObject *data ) { } diff --git a/Modules/DiffusionImaging/IODataStructures/FiberBundleX/mitkFiberBundleX.h b/Modules/DiffusionImaging/IODataStructures/FiberBundleX/mitkFiberBundleX.h index a6a6f5e76f..05ea707efb 100644 --- a/Modules/DiffusionImaging/IODataStructures/FiberBundleX/mitkFiberBundleX.h +++ b/Modules/DiffusionImaging/IODataStructures/FiberBundleX/mitkFiberBundleX.h @@ -1,122 +1,125 @@ /*=================================================================== 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 _MITK_FiberBundleX_H #define _MITK_FiberBundleX_H //includes for MITK datastructure #include <mitkBaseData.h> #include "MitkDiffusionImagingExports.h" #include <mitkImage.h> //includes storing fiberdata #include <vtkSmartPointer.h> //may be replaced by class precompile argument #include <vtkPolyData.h> // may be replaced by class #include <vtkPoints.h> // my be replaced by class #include <vtkDataSet.h> #include <QStringList> #include <mitkPlanarFigure.h> namespace mitk { /** * \brief Base Class for Fiber Bundles; */ class MitkDiffusionImaging_EXPORT FiberBundleX : public BaseData { public: // fiber colorcodings static const char* COLORCODING_ORIENTATION_BASED; static const char* COLORCODING_FA_BASED; static const char* COLORCODING_CUSTOM; static const char* FIBER_ID_ARRAY; virtual void UpdateOutputInformation(); virtual void SetRequestedRegionToLargestPossibleRegion(); virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(); virtual bool VerifyRequestedRegion(); virtual void SetRequestedRegion( itk::DataObject *data ); mitkClassMacro( FiberBundleX, BaseData ) itkNewMacro( Self ) mitkNewMacro1Param(Self, vtkSmartPointer<vtkPolyData>) // custom constructor // colorcoding related methods void SetColorCoding(const char*); void SetFAMap(mitk::Image::Pointer); void DoColorCodingOrientationBased(); void DoColorCodingFaBased(); void DoUseFaFiberOpacity(); void ResetFiberOpacity(); // fiber smoothing/resampling void ResampleFibers(float pointDistance = 1); void DoFiberSmoothing(int pointsPerCm); + bool RemoveShortFibers(float lengthInMM); + void MirrorFibers(unsigned int axis); // add/subtract fibers FiberBundleX::Pointer AddBundle(FiberBundleX* fib); FiberBundleX::Pointer SubtractBundle(FiberBundleX* fib); // fiber subset extraction - FiberBundleX::Pointer ExtractFiberSubset(PlanarFigure *pf); - std::vector<long> ExtractFiberIdSubset(PlanarFigure* pf); - vtkSmartPointer<vtkPolyData> GeneratePolyDataByIds( std::vector<long> ); + FiberBundleX::Pointer ExtractFiberSubset(PlanarFigure *pf); + std::vector<long> ExtractFiberIdSubset(PlanarFigure* pf); + vtkSmartPointer<vtkPolyData> GeneratePolyDataByIds( std::vector<long> ); // TODO: make protected + void GenerateFiberIds(); // TODO: make protected // get/set data void SetFiberPolyData(vtkSmartPointer<vtkPolyData>, bool updateGeometry = true); vtkSmartPointer<vtkPolyData> GetFiberPolyData(); QStringList GetAvailableColorCodings(); char* GetCurrentColorCoding(); itkGetMacro(NumFibers, int) // copy fiber bundle mitk::FiberBundleX::Pointer GetDeepCopy(); + // compare fiber bundles bool Equals(FiberBundleX* fib); - void GenerateFiberIds(); protected: FiberBundleX( vtkPolyData* fiberPolyData = NULL ); virtual ~FiberBundleX(); itk::Point<float, 3> GetItkPoint(double point[3]); // calculate geometry from fiber extent void UpdateFiberGeometry(); // calculate colorcoding values according to m_CurrentColorCoding void UpdateColorCoding(); private: // actual fiber container vtkSmartPointer<vtkPolyData> m_FiberPolyData; // contains fiber ids vtkSmartPointer<vtkDataSet> m_FiberIdDataSet; char* m_CurrentColorCoding; int m_NumFibers; }; } // namespace mitk #endif /* _MITK_FiberBundleX_H */ diff --git a/Modules/DiffusionImaging/Testing/mitkFiberBundleXTest.cpp b/Modules/DiffusionImaging/Testing/mitkFiberBundleXTest.cpp index 52ca547666..8a3fdfda4b 100644 --- a/Modules/DiffusionImaging/Testing/mitkFiberBundleXTest.cpp +++ b/Modules/DiffusionImaging/Testing/mitkFiberBundleXTest.cpp @@ -1,97 +1,100 @@ /*=================================================================== 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 "mitkTestingMacros.h" #include <mitkDiffusionImagingObjectFactory.h> #include <mitkFiberBundleX.h> #include <mitkFiberBundleXReader.h> #include <mitkBaseDataIOFactory.h> #include <mitkBaseData.h> #include <itksys/SystemTools.hxx> #include <mitkTestingConfig.h> #include <math.h> /**Documentation * Test for fiber bundle reader and writer */ int mitkFiberBundleXTest(int argc, char* argv[]) { MITK_TEST_BEGIN("mitkFiberBundleXTest"); MITK_TEST_CONDITION_REQUIRED(argc>1,"check for fielename") mitk::FiberBundleXReader::Pointer reader = mitk::FiberBundleXReader::New(); mitk::FiberBundleX::Pointer fib1, fib2; // first test: did this work? // using MITK_TEST_CONDITION_REQUIRED makes the test stop after failure, since // it makes no sense to continue without an object. MITK_TEST_CONDITION_REQUIRED(reader.IsNotNull(),"reader instantiation") try{ RegisterDiffusionImagingObjectFactory(); // test if fib1 can be read const std::string s1="", s2=""; std::vector<mitk::BaseData::Pointer> fibInfile = mitk::BaseDataIO::LoadBaseDataFromFile( argv[1], s1, s2, false ); mitk::BaseData::Pointer baseData = fibInfile.at(0); fib1 = dynamic_cast<mitk::FiberBundleX*>(baseData.GetPointer()); MITK_TEST_CONDITION_REQUIRED(fib1.IsNotNull(),"check if reader 1 returned null") fibInfile = mitk::BaseDataIO::LoadBaseDataFromFile( argv[1], s1, s2, false ); baseData = fibInfile.at(0); fib2 = dynamic_cast<mitk::FiberBundleX*>(baseData.GetPointer()); MITK_TEST_CONDITION_REQUIRED(fib2.IsNotNull(),"check if reader 2 returned null") MITK_TEST_CONDITION_REQUIRED(fib1->Equals(fib2),"check if equals method is working"); int randNum = rand()%20; - MITK_INFO << "DoFiberSmoothing " << randNum; fib2->DoFiberSmoothing(randNum); + MITK_INFO << "DoFiberSmoothing(" << randNum << ")" << randNum; fib2->DoFiberSmoothing(randNum); MITK_TEST_CONDITION_REQUIRED(!fib1->Equals(fib2),"check if fiber resampling method does something"); mitk::FiberBundleX::Pointer fib3 = fib1->AddBundle(fib2); MITK_TEST_CONDITION_REQUIRED(!fib1->Equals(fib3),"check if A+B!=A"); fib3 = fib3->SubtractBundle(fib2); MITK_TEST_CONDITION_REQUIRED(fib1->Equals(fib3),"check if A+B-B==A"); fib1->AddBundle(NULL); MITK_INFO << "GenerateFiberIds"; fib1->GenerateFiberIds(); MITK_INFO << "GetFiberPolyData"; fib1->GetFiberPolyData(); MITK_INFO << "GetAvailableColorCodings"; fib1->GetAvailableColorCodings(); MITK_INFO << "GetCurrentColorCoding"; fib1->GetCurrentColorCoding(); MITK_INFO << "SetFiberPolyData"; fib1->SetFiberPolyData(NULL); MITK_INFO << "ExtractFiberSubset"; fib1->ExtractFiberSubset(NULL); MITK_INFO << "ExtractFiberIdSubset"; fib1->ExtractFiberIdSubset(NULL); std::vector< long > tmp; MITK_INFO << "GeneratePolyDataByIds"; fib1->GeneratePolyDataByIds(tmp); MITK_INFO << "SetColorCoding"; fib1->SetColorCoding(NULL); MITK_INFO << "SetFAMap"; fib1->SetFAMap(NULL); MITK_INFO << "DoColorCodingOrientationBased"; fib1->DoColorCodingOrientationBased(); MITK_INFO << "DoColorCodingFaBased"; fib1->DoColorCodingFaBased(); MITK_INFO << "DoUseFaFiberOpacity"; fib1->DoUseFaFiberOpacity(); MITK_INFO << "ResetFiberOpacity"; fib1->ResetFiberOpacity(); + + float randFloat = rand()%300; + MITK_INFO << "RemoveShortFibers(" << randFloat << ")"; fib1->RemoveShortFibers(randFloat); } catch(...) { //this means that a wrong exception (i.e. no itk:Exception) has been thrown std::cout << "Wrong exception (i.e. no itk:Exception) caught during write [FAILED]" << std::endl; return EXIT_FAILURE; } // always end with this! MITK_TEST_END(); } diff --git a/Modules/DiffusionImaging/Tractography/itkGibbsTrackingFilter.cpp b/Modules/DiffusionImaging/Tractography/itkGibbsTrackingFilter.cpp index b74a54a9bf..4ee60e05b9 100644 --- a/Modules/DiffusionImaging/Tractography/itkGibbsTrackingFilter.cpp +++ b/Modules/DiffusionImaging/Tractography/itkGibbsTrackingFilter.cpp @@ -1,653 +1,661 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) -Copyright (c) German Cancer Research Center, +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 +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 "itkGibbsTrackingFilter.h" #include <itkProgressReporter.h> #include <mitkQBallImage.h> #include "itkPointShell.h" #include "GibbsTracking/BuildFibres.cpp" #pragma GCC visibility push(default) #include <itkEventObject.h> #pragma GCC visibility pop #include <QMutexLocker> #include <vnl/vnl_matrix_fixed.h> #include <vnl/vnl_vector_fixed.h> #include <fstream> #include <QCoreApplication> #include <itkRescaleIntensityImageFilter.h> #include <itkOrientationDistributionFunction.h> #include <itkImageDuplicator.h> #include <mitkStandardFileLocations.h> #include <itkDiffusionQballGeneralizedFaImageFilter.h> struct LessDereference { template <class T> bool operator()(const T * lhs, const T * rhs) const { return *lhs < *rhs; } }; namespace itk{ template< class TInputOdfImage, class TInputROIImage > GibbsTrackingFilter< TInputOdfImage, TInputROIImage > ::GibbsTrackingFilter(): m_TempStart(0.1), m_TempEnd(0.001), m_NumIt(500000), m_ParticleWeight(0), m_ParticleWidth(0), m_ParticleLength(0), m_ChempotConnection(10), m_ChempotParticle(0), m_InexBalance(0), m_Chempot2(0.2), m_FiberLength(10), m_AbortTracking(false), m_NumConnections(0), m_NumParticles(0), m_NumAcceptedFibers(0), m_CurrentStep(0), m_SubtractMean(true), m_BuildFibers(false), m_Sampler(NULL), m_Steps(10), m_Memory(0), m_ProposalAcceptance(0), m_GfaImage(NULL), m_CurvatureHardThreshold(0.7), m_Meanval_sq(0.0) { //this->m_MeasurementFrame.set_identity(); this->SetNumberOfRequiredInputs(2); //Filter needs a DWI image + a Mask Image } template< class TInputOdfImage, class TInputROIImage > GibbsTrackingFilter< TInputOdfImage, TInputROIImage > ::~GibbsTrackingFilter(){ delete BESSEL_APPROXCOEFF; if (m_Sampler!=NULL) delete m_Sampler; } template< class TInputOdfImage, class TInputROIImage > void GibbsTrackingFilter< TInputOdfImage, TInputROIImage > ::ComputeFiberCorrelationOriginal(){ float bD = 15; vnl_matrix_fixed<double, 3, QBALL_ODFSIZE> bDir = *itk::PointShell<QBALL_ODFSIZE, vnl_matrix_fixed<double, 3, QBALL_ODFSIZE> >::DistributePointShell(); const int N = QBALL_ODFSIZE; vnl_matrix_fixed<double, N, N> C = bDir.transpose()*bDir; vnl_matrix_fixed<double, N, N> Q = C; for(int i=0; i<N; i++) { for(int j=0; j<N; j++) { C(i,j) = abs(C(i,j)); Q(i,j) = exp(-bD * C(i,j) * C(i,j)); } } vnl_matrix_fixed<double, N, N> P = Q*Q; std::vector<const double *> pointer; pointer.reserve(N*N); double * start = C.data_block(); double * end = start + N*N; for (double * iter = start; iter != end; ++iter) { pointer.push_back(iter); } std::sort(pointer.begin(), pointer.end(), LessDereference()); vnl_vector_fixed<double,N*N> alpha; vnl_vector_fixed<double,N*N> beta; for (int i=0; i<N*N; i++) { alpha(i) = *pointer[i]; beta(i) = *(P.data_block()+(pointer[i]-start)); } double nfac = sqrt(beta(N*N-1)); beta = beta / (nfac*nfac); Q = Q / nfac; double sum = 0; for(int i=0; i<N; i++) { sum += Q(0,i); } // if left to default 0 // then mean is not substracted in order to correct odf integral m_Meanval_sq = (sum*sum)/N; vnl_vector_fixed<double,N*N> alpha_0; vnl_vector_fixed<double,N*N> alpha_2; vnl_vector_fixed<double,N*N> alpha_4; vnl_vector_fixed<double,N*N> alpha_6; for(int i=0; i<N*N; i++) { alpha_0(i) = 1; alpha_2(i) = alpha(i)*alpha(i); alpha_4(i) = alpha_2(i)*alpha_2(i); alpha_6(i) = alpha_4(i)*alpha_2(i); } vnl_matrix_fixed<double, N*N, 4> T; T.set_column(0,alpha_0); T.set_column(1,alpha_2); T.set_column(2,alpha_4); T.set_column(3,alpha_6); vnl_vector_fixed<double,4> coeff = vnl_matrix_inverse<double>(T).pinverse()*beta; BESSEL_APPROXCOEFF = new float[4]; BESSEL_APPROXCOEFF[0] = coeff(0); BESSEL_APPROXCOEFF[1] = coeff(1); BESSEL_APPROXCOEFF[2] = coeff(2); BESSEL_APPROXCOEFF[3] = coeff(3); // // OLD // BESSEL_APPROXCOEFF[0] = 0,1982; // BESSEL_APPROXCOEFF[1] = 0.3415; // BESSEL_APPROXCOEFF[2] = -0.9515; // BESSEL_APPROXCOEFF[3] = 1.3423; } template< class TInputOdfImage, class TInputROIImage > void GibbsTrackingFilter< TInputOdfImage, TInputROIImage > ::ComputeFiberCorrelation(){ // float bD = 15; // vnl_matrix_fixed<double, 3, QBALL_ODFSIZE> bDir = // *itk::PointShell<QBALL_ODFSIZE, vnl_matrix_fixed<double, 3, QBALL_ODFSIZE> >::DistributePointShell(); // const int N = QBALL_ODFSIZE; // vnl_matrix_fixed<double, QBALL_ODFSIZE, 3> temp = bDir.transpose(); // vnl_matrix_fixed<double, N, N> C = temp*bDir; // vnl_matrix_fixed<double, N, N> Q = C; // vnl_vector_fixed<double, N> mean; // for(int i=0; i<N; i++) // { // double tempMean = 0; // for(int j=0; j<N; j++) // { // C(i,j) = abs(C(i,j)); // Q(i,j) = exp(-bD * C(i,j) * C(i,j)); // tempMean += Q(i,j); // } // mean[i] = tempMean/N; // } // vnl_matrix_fixed<double, N, N> repMean; // for (int i=0; i<N; i++) // repMean.set_row(i, mean); // Q -= repMean; // vnl_matrix_fixed<double, N, N> P = Q*Q; // std::vector<const double *> pointer; // pointer.reserve(N*N); // double * start = C.data_block(); // double * end = start + N*N; // for (double * iter = start; iter != end; ++iter) // { // pointer.push_back(iter); // } // std::sort(pointer.begin(), pointer.end(), LessDereference()); // vnl_vector_fixed<double,N*N> alpha; // vnl_vector_fixed<double,N*N> beta; // for (int i=0; i<N*N; i++) { // alpha(i) = *pointer[i]; // beta(i) = *(P.data_block()+(pointer[i]-start)); // } // double nfac = sqrt(beta(N*N-1)); // beta = beta / (nfac*nfac); // Q = Q / nfac; // double sum = 0; // for(int i=0; i<N; i++) // { // sum += Q(0,i); // } // // if left to default 0 // // then mean is not substracted in order to correct odf integral // // this->m_Meanval_sq = (sum*sum)/N; // vnl_vector_fixed<double,N*N> alpha_0; // vnl_vector_fixed<double,N*N> alpha_2; // vnl_vector_fixed<double,N*N> alpha_4; // vnl_vector_fixed<double,N*N> alpha_6; // for(int i=0; i<N*N; i++) // { // alpha_0(i) = 1; // alpha_2(i) = alpha(i)*alpha(i); // alpha_4(i) = alpha_2(i)*alpha_2(i); // alpha_6(i) = alpha_4(i)*alpha_2(i); // } // vnl_matrix_fixed<double, N*N, 4> T; // T.set_column(0,alpha_0); // T.set_column(1,alpha_2); // T.set_column(2,alpha_4); // T.set_column(3,alpha_6); // vnl_vector_fixed<double,4> coeff = vnl_matrix_inverse<double>(T).pinverse()*beta; // MITK_INFO << "itkGibbsTrackingFilter: Bessel oefficients: " << coeff; BESSEL_APPROXCOEFF = new float[4]; // BESSEL_APPROXCOEFF[0] = coeff(0); // BESSEL_APPROXCOEFF[1] = coeff(1); // BESSEL_APPROXCOEFF[2] = coeff(2); // BESSEL_APPROXCOEFF[3] = coeff(3); BESSEL_APPROXCOEFF[0] = -0.1714; BESSEL_APPROXCOEFF[1] = 0.5332; BESSEL_APPROXCOEFF[2] = -1.4889; BESSEL_APPROXCOEFF[3] = 2.0389; } // build fibers from tracking result template< class TInputOdfImage, class TInputROIImage > void GibbsTrackingFilter< TInputOdfImage, TInputROIImage > ::BuildFibers(float* points, int numPoints) { double spacing[3]; spacing[0] = m_ItkQBallImage->GetSpacing().GetElement(0); spacing[1] = m_ItkQBallImage->GetSpacing().GetElement(1); spacing[2] = m_ItkQBallImage->GetSpacing().GetElement(2); m_FiberPolyData = FiberPolyDataType::New(); // initialize array of particles FiberBuilder fiberBuilder(points, numPoints, spacing, m_ItkQBallImage); // label the particles according to fiber affiliation and return polydata m_FiberPolyData = fiberBuilder.iterate(m_FiberLength); m_NumAcceptedFibers = m_FiberPolyData->GetNumberOfLines(); MITK_INFO << "itkGibbsTrackingFilter: " << m_NumAcceptedFibers << " accepted"; } // fill output fiber bundle datastructure template< class TInputOdfImage, class TInputROIImage > typename GibbsTrackingFilter< TInputOdfImage, TInputROIImage >::FiberPolyDataType GibbsTrackingFilter< TInputOdfImage, TInputROIImage > ::GetFiberBundle() { if (!m_AbortTracking) { m_BuildFibers = true; while (m_BuildFibers){} } return m_FiberPolyData; } // get memory allocated for particle grid template< class TInputOdfImage, class TInputROIImage > float GibbsTrackingFilter< TInputOdfImage, TInputROIImage > ::GetMemoryUsage() { if (m_Sampler!=NULL) return m_Sampler->m_ParticleGrid.GetMemoryUsage(); return 0; } template< class TInputOdfImage, class TInputROIImage > bool GibbsTrackingFilter< TInputOdfImage, TInputROIImage > ::EstimateParticleWeight() { MITK_INFO << "itkGibbsTrackingFilter: estimating particle weight"; typedef itk::DiffusionQballGeneralizedFaImageFilter<float,float,QBALL_ODFSIZE> GfaFilterType; GfaFilterType::Pointer gfaFilter = GfaFilterType::New(); gfaFilter->SetInput(m_ItkQBallImage); gfaFilter->SetComputationMethod(GfaFilterType::GFA_STANDARD); gfaFilter->Update(); m_GfaImage = gfaFilter->GetOutput(); float samplingStart = 1.0; float samplingStop = 0.66; // copy GFA image (original should not be changed) typedef itk::ImageDuplicator< GfaImageType > DuplicateFilterType; DuplicateFilterType::Pointer duplicator = DuplicateFilterType::New(); duplicator->SetInputImage( m_GfaImage ); duplicator->Update(); m_GfaImage = duplicator->GetOutput(); //// GFA iterator //// typedef ImageRegionIterator< GfaImageType > GfaIteratorType; GfaIteratorType gfaIt(m_GfaImage, m_GfaImage->GetLargestPossibleRegion() ); //// Mask iterator //// typedef ImageRegionConstIterator< MaskImageType > MaskIteratorType; MaskIteratorType maskIt(m_MaskImage, m_MaskImage->GetLargestPossibleRegion() ); // set unmasked region of gfa image to 0 gfaIt.GoToBegin(); maskIt.GoToBegin(); while( !gfaIt.IsAtEnd() ) { if(maskIt.Get()<=0) gfaIt.Set(0); ++gfaIt; ++maskIt; } // rescale gfa image to [0,1] typedef itk::RescaleIntensityImageFilter< GfaImageType, GfaImageType > RescaleFilterType; RescaleFilterType::Pointer rescaleFilter = RescaleFilterType::New(); rescaleFilter->SetInput( m_GfaImage ); rescaleFilter->SetOutputMaximum( samplingStart ); rescaleFilter->SetOutputMinimum( 0 ); rescaleFilter->Update(); m_GfaImage = rescaleFilter->GetOutput(); gfaIt = GfaIteratorType(m_GfaImage, m_GfaImage->GetLargestPossibleRegion() ); //// Input iterator //// typedef ImageRegionConstIterator< InputQBallImageType > InputIteratorType; InputIteratorType git(m_ItkQBallImage, m_ItkQBallImage->GetLargestPossibleRegion() ); float upper = 0; int count = 0; for(float thr=samplingStart; thr>samplingStop; thr-=0.01) { git.GoToBegin(); gfaIt.GoToBegin(); while( !gfaIt.IsAtEnd() ) { if(gfaIt.Get()>thr) { itk::OrientationDistributionFunction<float, QBALL_ODFSIZE> odf(git.Get().GetDataPointer()); upper += odf.GetMaxValue()-odf.GetMeanValue(); ++count; } ++gfaIt; ++git; } } if (count>0) upper /= count; else return false; m_ParticleWeight = upper/6; return true; } // perform global tracking template< class TInputOdfImage, class TInputROIImage > void GibbsTrackingFilter< TInputOdfImage, TInputROIImage > ::GenerateData(){ // input qball image m_ItkQBallImage = dynamic_cast<InputQBallImageType*>(this->GetInput(0)); m_NumAcceptedFibers = 0; // approximationscoeffizienten der // teilchenkorrelationen im orientierungsraum // 4er vektor //ComputeFiberCorrelationOriginal(); ComputeFiberCorrelation(); // image sizes and spacing int qBallImageSize[4] = {QBALL_ODFSIZE, m_ItkQBallImage->GetLargestPossibleRegion().GetSize().GetElement(0), m_ItkQBallImage->GetLargestPossibleRegion().GetSize().GetElement(1), m_ItkQBallImage->GetLargestPossibleRegion().GetSize().GetElement(2)}; double qBallImageSpacing[3] = {m_ItkQBallImage->GetSpacing().GetElement(0),m_ItkQBallImage->GetSpacing().GetElement(1),m_ItkQBallImage->GetSpacing().GetElement(2)}; // make sure image has enough slices if (qBallImageSize[1]<3 || qBallImageSize[2]<3 || qBallImageSize[3]<3) { MITK_INFO << "itkGibbsTrackingFilter: image size < 3 not supported"; m_AbortTracking = true; } // calculate rotation matrix vnl_matrix_fixed<double, 3, 3> directionMatrix = m_ItkQBallImage->GetDirection().GetVnlMatrix(); vnl_vector_fixed<double, 3> d0 = directionMatrix.get_column(0); d0.normalize(); vnl_vector_fixed<double, 3> d1 = directionMatrix.get_column(1); d1.normalize(); vnl_vector_fixed<double, 3> d2 = directionMatrix.get_column(2); d2.normalize(); directionMatrix.set_column(0, d0); directionMatrix.set_column(1, d1); directionMatrix.set_column(2, d2); vnl_matrix_fixed<double, 3, 3> I = directionMatrix*directionMatrix.transpose(); if(!I.is_identity(mitk::eps)){ MITK_INFO << "itkGibbsTrackingFilter: image direction is not a rotation matrix. Tracking not possible!"; m_AbortTracking = true; } // generate local working copy of image buffer int bufferSize = qBallImageSize[0]*qBallImageSize[1]*qBallImageSize[2]*qBallImageSize[3]; float* qBallImageBuffer = (float*) m_ItkQBallImage->GetBufferPointer(); float* workingQballImage = new float[bufferSize]; for (int i=0; i<bufferSize; i++) workingQballImage[i] = qBallImageBuffer[i]; // perform mean subtraction on odfs if (m_SubtractMean) { float sum = 0; for (int i=0; i<bufferSize; i++) { if (qBallImageSize[0]>0 && i%qBallImageSize[0] == 0 && i>0) { sum /= qBallImageSize[0]; for (int j=i-qBallImageSize[0]; j<i; j++){ workingQballImage[j] -= sum; } sum = 0; } sum += workingQballImage[i]; } } // mask image int maskImageSize[3]; float *mask; if(m_MaskImage.IsNotNull()) { mask = (float*) m_MaskImage->GetBufferPointer(); maskImageSize[0] = m_MaskImage->GetLargestPossibleRegion().GetSize().GetElement(0); maskImageSize[1] = m_MaskImage->GetLargestPossibleRegion().GetSize().GetElement(1); maskImageSize[2] = m_MaskImage->GetLargestPossibleRegion().GetSize().GetElement(2); } else { mask = 0; maskImageSize[0] = qBallImageSize[1]; maskImageSize[1] = qBallImageSize[2]; maskImageSize[2] = qBallImageSize[3]; } int mask_oversamp_mult = maskImageSize[0]/qBallImageSize[1]; // load lookuptable QString applicationDir = QCoreApplication::applicationDirPath(); applicationDir.append("/"); mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch( applicationDir.toStdString().c_str(), false ); applicationDir.append("../"); mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch( applicationDir.toStdString().c_str(), false ); applicationDir.append("../../"); mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch( applicationDir.toStdString().c_str(), false ); std::string lutPath = mitk::StandardFileLocations::GetInstance()->FindFile("FiberTrackingLUTBaryCoords.bin"); ifstream BaryCoords; BaryCoords.open(lutPath.c_str(), ios::in | ios::binary); float* coords; if (BaryCoords.is_open()) { float tmp; coords = new float [1630818]; BaryCoords.seekg (0, ios::beg); for (int i=0; i<1630818; i++) { BaryCoords.read((char *)&tmp, sizeof(tmp)); coords[i] = tmp; } BaryCoords.close(); } else { MITK_INFO << "itkGibbsTrackingFilter: unable to open barycoords file"; m_AbortTracking = true; } ifstream Indices; lutPath = mitk::StandardFileLocations::GetInstance()->FindFile("FiberTrackingLUTIndices.bin"); Indices.open(lutPath.c_str(), ios::in | ios::binary); int* ind; if (Indices.is_open()) { int tmp; ind = new int [1630818]; Indices.seekg (0, ios::beg); for (int i=0; i<1630818; i++) { Indices.read((char *)&tmp, 4); ind[i] = tmp; } Indices.close(); } else { MITK_INFO << "itkGibbsTrackingFilter: unable to open indices file"; m_AbortTracking = true; } // initialize sphere interpolator with lookuptables SphereInterpolator *sinterp = new SphereInterpolator(coords, ind, QBALL_ODFSIZE, 301, 0.5); // get paramters float minSpacing; if(qBallImageSpacing[0]<qBallImageSpacing[1] && qBallImageSpacing[0]<qBallImageSpacing[2]) minSpacing = qBallImageSpacing[0]; else if (qBallImageSpacing[1] < qBallImageSpacing[2]) minSpacing = qBallImageSpacing[1]; else minSpacing = qBallImageSpacing[2]; if(m_ParticleLength == 0) m_ParticleLength = 1.5*minSpacing; if(m_ParticleWidth == 0) m_ParticleWidth = 0.5*minSpacing; if(m_ParticleWeight == 0) if (!EstimateParticleWeight()) { MITK_INFO << "itkGibbsTrackingFilter: could not estimate particle weight!"; m_ParticleWeight = 0.0001; } - MITK_INFO << "itkGibbsTrackingFilter: particle Weight: " << m_ParticleWeight; - MITK_INFO << "itkGibbsTrackingFilter: iterations: " << m_NumIt; m_CurrentStep = 0; m_Memory = 0; float cellsize = 2*m_ParticleLength; float alpha = log(m_TempEnd/m_TempStart); m_Steps = m_NumIt/10000; if (m_Steps<10) m_Steps = 10; if (m_Steps>m_NumIt) { MITK_INFO << "itkGibbsTrackingFilter: not enough iterations!"; m_AbortTracking = true; } - MITK_INFO << "itkGibbsTrackingFilter: steps: " << m_Steps; if (m_CurvatureHardThreshold < mitk::eps) m_CurvatureHardThreshold = 0; - MITK_INFO << "itkGibbsTrackingFilter: curvature threshold: " << m_CurvatureHardThreshold; unsigned long singleIts = (unsigned long)((1.0*m_NumIt) / (1.0*m_Steps)); // setup metropolis hastings sampler MITK_INFO << "itkGibbsTrackingFilter: setting up MH-sampler"; if (m_Sampler!=NULL) delete m_Sampler; m_Sampler = new RJMCMC(NULL, 0, workingQballImage, qBallImageSize, qBallImageSpacing, cellsize); // setup energy computer MITK_INFO << "itkGibbsTrackingFilter: setting up Energy-computer"; EnergyComputer encomp(workingQballImage,qBallImageSize,qBallImageSpacing,sinterp,&(m_Sampler->m_ParticleGrid),mask,mask_oversamp_mult, directionMatrix); encomp.setParameters(m_ParticleWeight,m_ParticleWidth,m_ChempotConnection*m_ParticleLength*m_ParticleLength,m_ParticleLength,m_CurvatureHardThreshold,m_InexBalance,m_Chempot2, m_Meanval_sq); m_Sampler->SetEnergyComputer(&encomp); m_Sampler->SetParameters(m_TempStart,singleIts,m_ParticleLength,m_CurvatureHardThreshold,m_ChempotParticle); + + MITK_INFO << "itkGibbsTrackingFilter: Iterations: " << m_NumIt; + MITK_INFO << "itkGibbsTrackingFilter: steps: " << m_Steps; + MITK_INFO << "itkGibbsTrackingFilter: Particle weight: " << m_ParticleWeight; + MITK_INFO << "itkGibbsTrackingFilter: Particle width: " << m_ParticleWidth; + MITK_INFO << "itkGibbsTrackingFilter: Particle length: " << m_ParticleLength; + MITK_INFO << "itkGibbsTrackingFilter: Min. fiber length: " << m_ParticleLength; + MITK_INFO << "itkGibbsTrackingFilter: Start temperature: " << m_TempStart; + MITK_INFO << "itkGibbsTrackingFilter: End temperature: " << m_TempEnd; + MITK_INFO << "itkGibbsTrackingFilter: Energy balance: " << m_InexBalance; + MITK_INFO << "itkGibbsTrackingFilter: Curvature threshold: " << m_CurvatureHardThreshold; + // main loop for( int step = 0; step < m_Steps; step++ ) { if (m_AbortTracking) break; m_CurrentStep = step+1; float temperature = m_TempStart * exp(alpha*(((1.0)*step)/((1.0)*m_Steps))); m_Sampler->SetTemperature(temperature); m_Sampler->Iterate(&m_ProposalAcceptance, &m_NumConnections, &m_NumParticles, &m_AbortTracking); MITK_INFO << "itkGibbsTrackingFilter: proposal acceptance: " << 100*m_ProposalAcceptance << "%"; MITK_INFO << "itkGibbsTrackingFilter: particles: " << m_NumParticles; MITK_INFO << "itkGibbsTrackingFilter: connections: " << m_NumConnections; MITK_INFO << "itkGibbsTrackingFilter: progress: " << 100*(float)step/m_Steps << "%"; if (m_BuildFibers) { int numPoints = m_Sampler->m_ParticleGrid.pcnt; float* points = new float[numPoints*m_Sampler->m_NumAttributes]; m_Sampler->WriteOutParticles(points); BuildFibers(points, numPoints); delete points; m_BuildFibers = false; } } int numPoints = m_Sampler->m_ParticleGrid.pcnt; float* points = new float[numPoints*m_Sampler->m_NumAttributes]; m_Sampler->WriteOutParticles(points); BuildFibers(points, numPoints); delete points; delete sinterp; delete coords; delete ind; delete workingQballImage; m_AbortTracking = true; m_BuildFibers = false; MITK_INFO << "itkGibbsTrackingFilter: done generate data"; } } diff --git a/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.cpp b/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.cpp new file mode 100644 index 0000000000..e39f3987dd --- /dev/null +++ b/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.cpp @@ -0,0 +1,348 @@ +/*=================================================================== + +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 __itkStreamlineTrackingFilter_txx +#define __itkStreamlineTrackingFilter_txx + +#include <time.h> +#include <stdio.h> +#include <stdlib.h> + +#include "itkStreamlineTrackingFilter.h" +#include <itkImageRegionConstIterator.h> +#include <itkImageRegionConstIteratorWithIndex.h> +#include <itkImageRegionIterator.h> + +#define _USE_MATH_DEFINES +#include <math.h> + +namespace itk { + +//#define QBALL_RECON_PI M_PI + +template< class TTensorPixelType, class TPDPixelType> +StreamlineTrackingFilter< TTensorPixelType, +TPDPixelType> +::StreamlineTrackingFilter(): + m_FaThreshold(0.2), + m_StepSize(0.2), + m_MaxLength(10000), + m_SeedsPerVoxel(1) +{ + // At least 1 inputs is necessary for a vector image. + // For images added one at a time we need at least six + this->SetNumberOfRequiredInputs( 1 ); +} + +template< class TTensorPixelType, + class TPDPixelType> +void StreamlineTrackingFilter< TTensorPixelType, +TPDPixelType> +::BeforeThreadedGenerateData() +{ + m_FiberPolyData = FiberPolyDataType::New(); + m_Points = vtkPoints::New(); + m_Cells = vtkCellArray::New(); + + typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); + m_ImageSize[0] = inputImage->GetLargestPossibleRegion().GetSize().GetElement(0); + m_ImageSize[1] = inputImage->GetLargestPossibleRegion().GetSize().GetElement(1); + m_ImageSize[2] = inputImage->GetLargestPossibleRegion().GetSize().GetElement(2); + + m_PolyDataContainer = itk::VectorContainer< int, FiberPolyDataType >::New(); + for (int i=0; i<this->GetNumberOfThreads(); i++) + { + FiberPolyDataType poly = FiberPolyDataType::New(); + m_PolyDataContainer->InsertElement(i, poly); + } + + if (m_MaskImage.IsNull()) + { + itk::Vector<double, 3> spacing = inputImage->GetSpacing(); + itk::Point<double, 3> origin = inputImage->GetOrigin(); + itk::Matrix<double, 3, 3> direction = inputImage->GetDirection(); + ImageRegion<3> imageRegion = inputImage->GetLargestPossibleRegion(); + + // initialize crossings image + m_MaskImage = ItkUcharImgType::New(); + m_MaskImage->SetSpacing( spacing ); + m_MaskImage->SetOrigin( origin ); + m_MaskImage->SetDirection( direction ); + m_MaskImage->SetRegions( imageRegion ); + m_MaskImage->Allocate(); + m_MaskImage->FillBuffer(1); + } + std::cout << "starting streamline tracking" << std::endl; +} + +template< class TTensorPixelType, + class TPDPixelType> +void StreamlineTrackingFilter< TTensorPixelType, +TPDPixelType> +::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, + int threadId) +{ + FiberPolyDataType poly = m_PolyDataContainer->GetElement(threadId); + vtkSmartPointer<vtkPoints> Points = vtkPoints::New(); + vtkSmartPointer<vtkCellArray> Cells = vtkCellArray::New(); + + typedef itk::DiffusionTensor3D<TTensorPixelType> TensorType; + typedef ImageRegionConstIterator< InputImageType > InputIteratorType; + typedef ImageRegionConstIterator< ItkUcharImgType > MaskIteratorType; + typedef typename InputImageType::PixelType InputTensorType; + typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); + + InputIteratorType it(inputImage, outputRegionForThread ); + MaskIteratorType mit(m_MaskImage, outputRegionForThread ); + it.GoToBegin(); + mit.GoToBegin(); + while( !it.IsAtEnd() ) + { + if (mit.Value()==0) + { + ++mit; + ++it; + continue; + } + + typename TensorType::EigenValuesArrayType eigenvalues; + typename TensorType::EigenVectorsMatrixType eigenvectors; + + for (int s=0; s<m_SeedsPerVoxel; s++) + { + unsigned long counter = 0; + vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New(); + std::vector< vtkIdType > pointISs; + typename InputImageType::IndexType index = it.GetIndex(); + itk::ContinuousIndex<double, 3> pos; + itk::ContinuousIndex<double, 3> start; + + if (m_SeedsPerVoxel>1) + { + pos[0] = index[0]+(double)(rand()%99-49)/100; + pos[1] = index[1]+(double)(rand()%99-49)/100; + pos[2] = index[2]+(double)(rand()%99-49)/100; + } + else + { + pos[0] = index[0]; + pos[1] = index[1]; + pos[2] = index[2]; + } + start = pos; + + int step = 0; + vnl_vector_fixed<double,3> dirOld; dirOld.fill(0.0); + // do forward tracking + while (step < m_MaxLength) + { + ++step; + + index[0] = round(pos[0]); + index[1] = round(pos[1]); + index[2] = round(pos[2]); + + if (index[0] < 0 || index[0]>=m_ImageSize[0]) + break; + if (index[1] < 0 || index[1]>=m_ImageSize[1]) + break; + if (index[2] < 0 || index[2]>=m_ImageSize[2]) + break; + + typename InputImageType::PixelType tensor = inputImage->GetPixel(index); + if(tensor.GetTrace()!=0 && tensor.GetFractionalAnisotropy()>m_FaThreshold) + { + tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors); + + int eIndex = 2; + if( (eigenvalues[0] >= eigenvalues[1]) && (eigenvalues[0] >= eigenvalues[2]) ) + eIndex = 0; + else if(eigenvalues[1] >= eigenvalues[2]) + eIndex = 1; + + vnl_vector_fixed<double,3> dir; + dir[0] = eigenvectors(eIndex, 0); + dir[1] = eigenvectors(eIndex, 1); + dir[2] = eigenvectors(eIndex, 2); + dir.normalize(); + + if (!dirOld.is_zero()) + { + float angle = dot_product(dirOld, dir); + if (angle<0) + dir *= -1; + angle = fabs(dot_product(dirOld, dir)); + if (angle<0.7) + break; + } + dirOld = dir; + + dir *= m_StepSize; + + itk::Point<double> worldPos; + inputImage->TransformContinuousIndexToPhysicalPoint( pos, worldPos ); + + vtkIdType id = Points->InsertNextPoint(worldPos.GetDataPointer()); + pointISs.push_back(id); + counter++; + + pos[0] += dir[0]; + pos[1] += dir[1]; + pos[2] += dir[2]; + } + } + + // insert reverse IDs + while (!pointISs.empty()) + { + container->GetPointIds()->InsertNextId(pointISs.back()); + pointISs.pop_back(); + } + + // do backward tracking + index = it.GetIndex(); + pos = start; + dirOld.fill(0.0); + while (step < m_MaxLength) + { + ++step; + + index[0] = round(pos[0]); + index[1] = round(pos[1]); + index[2] = round(pos[2]); + + if (index[0] < 0 || index[0]>=m_ImageSize[0]) + break; + if (index[1] < 0 || index[1]>=m_ImageSize[1]) + break; + if (index[2] < 0 || index[2]>=m_ImageSize[2]) + break; + + typename InputImageType::PixelType tensor = inputImage->GetPixel(index); + if(tensor.GetTrace()!=0 && tensor.GetFractionalAnisotropy()>m_FaThreshold) + { + tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors); + + int eIndex = 2; + if( (eigenvalues[0] >= eigenvalues[1]) && (eigenvalues[0] >= eigenvalues[2]) ) + eIndex = 0; + else if(eigenvalues[1] >= eigenvalues[2]) + eIndex = 1; + + vnl_vector_fixed<double,3> dir; + dir[0] = eigenvectors(eIndex, 0); + dir[1] = eigenvectors(eIndex, 1); + dir[2] = eigenvectors(eIndex, 2); + dir.normalize(); + dir *= -1; // reverse direction + + if (!dirOld.is_zero()) + { + float angle = dot_product(dirOld, dir); + if (angle<0) + dir *= -1; + angle = fabs(dot_product(dirOld, dir)); + if (angle<0.7) + break; + } + dirOld = dir; + + dir *= m_StepSize; + + itk::Point<double> worldPos; + inputImage->TransformContinuousIndexToPhysicalPoint( pos, worldPos ); + + vtkIdType id = Points->InsertNextPoint(worldPos.GetDataPointer()); + container->GetPointIds()->InsertNextId(id); + counter++; + + pos[0] += dir[0]; + pos[1] += dir[1]; + pos[2] += dir[2]; + } + } + + if (counter>0) + Cells->InsertNextCell(container); + } + ++mit; + ++it; + } + + poly->SetPoints(Points); + poly->SetLines(Cells); + + std::cout << "Thread " << threadId << " finished tracking" << std::endl; +} + +template< class TTensorPixelType, + class TPDPixelType> +vtkSmartPointer< vtkPolyData > StreamlineTrackingFilter< TTensorPixelType, +TPDPixelType> +::AddPolyData(FiberPolyDataType poly1, FiberPolyDataType poly2) +{ + vtkSmartPointer<vtkPolyData> vNewPolyData = vtkSmartPointer<vtkPolyData>::New(); + vtkSmartPointer<vtkCellArray> vNewLines = poly1->GetLines(); + vtkSmartPointer<vtkPoints> vNewPoints = poly1->GetPoints(); + + vtkSmartPointer<vtkCellArray> vLines = poly2->GetLines(); + vLines->InitTraversal(); + for( int i=0; i<vLines->GetNumberOfCells(); i++ ) + { + vtkIdType numPoints(0); + vtkIdType* points(NULL); + vLines->GetNextCell ( numPoints, points ); + + vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New(); + for( int j=0; j<numPoints; j++) + { + vtkIdType id = vNewPoints->InsertNextPoint(poly2->GetPoint(points[j])); + container->GetPointIds()->InsertNextId(id); + } + vNewLines->InsertNextCell(container); + } + + // initialize polydata + vNewPolyData->SetPoints(vNewPoints); + vNewPolyData->SetLines(vNewLines); + + return vNewPolyData; +} +template< class TTensorPixelType, + class TPDPixelType> +void StreamlineTrackingFilter< TTensorPixelType, +TPDPixelType> +::AfterThreadedGenerateData() +{ + MITK_INFO << "Generating polydata "; + m_FiberPolyData = m_PolyDataContainer->GetElement(0); + for (int i=1; i<this->GetNumberOfThreads(); i++) + { + m_FiberPolyData = AddPolyData(m_FiberPolyData, m_PolyDataContainer->GetElement(i)); + } + MITK_INFO << "done"; +} + +template< class TTensorPixelType, + class TPDPixelType> +void StreamlineTrackingFilter< TTensorPixelType, +TPDPixelType> +::PrintSelf(std::ostream& os, Indent indent) const +{ +} + +} +#endif // __itkDiffusionQballPrincipleDirectionsImageFilter_txx diff --git a/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.h b/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.h new file mode 100644 index 0000000000..d6aaa4b759 --- /dev/null +++ b/Modules/DiffusionImaging/Tractography/itkStreamlineTrackingFilter.h @@ -0,0 +1,107 @@ +/*=================================================================== + +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. + +===================================================================*/ + +/*=================================================================== + +This file is based heavily on a corresponding ITK filter. + +===================================================================*/ +#ifndef __itkStreamlineTrackingFilter_h_ +#define __itkStreamlineTrackingFilter_h_ + +#include "MitkDiffusionImagingExports.h" +#include <itkImageToImageFilter.h> +#include <itkVectorContainer.h> +#include <itkVectorImage.h> +#include <itkDiffusionTensor3D.h> +#include <vtkSmartPointer.h> +#include <vtkPolyData.h> +#include <vtkCellArray.h> +#include <vtkPoints.h> +#include <vtkPolyLine.h> + +namespace itk{ + /** \class StreamlineTrackingFilter + */ + + template< class TTensorPixelType, class TPDPixelType=double> + class StreamlineTrackingFilter : + public ImageToImageFilter< Image< DiffusionTensor3D<TTensorPixelType>, 3 >, + Image< Vector< TPDPixelType, 3 >, 3 > > + { + + public: + + typedef StreamlineTrackingFilter Self; + typedef SmartPointer<Self> Pointer; + typedef SmartPointer<const Self> ConstPointer; + typedef ImageToImageFilter< Image< DiffusionTensor3D<TTensorPixelType>, 3 >, Image< Vector< TPDPixelType, 3 >, 3 > > Superclass; + + /** Method for creation through the object factory. */ + itkNewMacro(Self) + + /** Runtime information support. */ + itkTypeMacro(StreamlineTrackingFilter, ImageToImageFilter) + + typedef TTensorPixelType TensorComponentType; + typedef TPDPixelType DirectionPixelType; + typedef typename Superclass::InputImageType InputImageType; + typedef typename Superclass::OutputImageType OutputImageType; + typedef typename Superclass::OutputImageRegionType OutputImageRegionType; + typedef itk::Image<unsigned char, 3> ItkUcharImgType; + + typedef vtkSmartPointer< vtkPolyData > FiberPolyDataType; + + itkGetMacro( FiberPolyData, FiberPolyDataType ) + itkSetMacro( MaskImage, ItkUcharImgType::Pointer) + itkSetMacro( SeedsPerVoxel, int) + itkSetMacro( FaThreshold, float) + + protected: + StreamlineTrackingFilter(); + ~StreamlineTrackingFilter() {} + void PrintSelf(std::ostream& os, Indent indent) const; + + void BeforeThreadedGenerateData(); + void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, int threadId); + void AfterThreadedGenerateData(); + + FiberPolyDataType AddPolyData(FiberPolyDataType poly1, FiberPolyDataType poly2); + + FiberPolyDataType m_FiberPolyData; + vtkSmartPointer<vtkPoints> m_Points; + vtkSmartPointer<vtkCellArray> m_Cells; + float m_FaThreshold; + float m_StepSize; + int m_MaxLength; + int m_SeedsPerVoxel; + int m_ImageSize[3]; + ItkUcharImgType::Pointer m_MaskImage; + + itk::VectorContainer< int, FiberPolyDataType >::Pointer m_PolyDataContainer; + + private: + + }; + +} + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkStreamlineTrackingFilter.cpp" +#endif + +#endif //__itkStreamlineTrackingFilter_h_ + diff --git a/Modules/DiffusionImaging/files.cmake b/Modules/DiffusionImaging/files.cmake index 73b96d2312..cfadef37e8 100644 --- a/Modules/DiffusionImaging/files.cmake +++ b/Modules/DiffusionImaging/files.cmake @@ -1,227 +1,228 @@ set(CPP_FILES # DicomImport DicomImport/mitkDicomDiffusionImageReader.cpp DicomImport/mitkGroupDiffusionHeadersFilter.cpp DicomImport/mitkDicomDiffusionImageHeaderReader.cpp DicomImport/mitkGEDicomDiffusionImageHeaderReader.cpp DicomImport/mitkPhilipsDicomDiffusionImageHeaderReader.cpp DicomImport/mitkSiemensDicomDiffusionImageHeaderReader.cpp DicomImport/mitkSiemensMosaicDicomDiffusionImageHeaderReader.cpp # DataStructures IODataStructures/mitkDiffusionImagingObjectFactory.cpp # DataStructures -> DWI IODataStructures/DiffusionWeightedImages/mitkDiffusionImageHeaderInformation.cpp IODataStructures/DiffusionWeightedImages/mitkDiffusionImageSource.cpp IODataStructures/DiffusionWeightedImages/mitkNrrdDiffusionImageReader.cpp IODataStructures/DiffusionWeightedImages/mitkNrrdDiffusionImageWriter.cpp IODataStructures/DiffusionWeightedImages/mitkNrrdDiffusionImageIOFactory.cpp IODataStructures/DiffusionWeightedImages/mitkNrrdDiffusionImageWriterFactory.cpp IODataStructures/DiffusionWeightedImages/mitkDiffusionImageSerializer.cpp # DataStructures -> QBall IODataStructures/QBallImages/mitkQBallImageSource.cpp IODataStructures/QBallImages/mitkNrrdQBallImageReader.cpp IODataStructures/QBallImages/mitkNrrdQBallImageWriter.cpp IODataStructures/QBallImages/mitkNrrdQBallImageIOFactory.cpp IODataStructures/QBallImages/mitkNrrdQBallImageWriterFactory.cpp IODataStructures/QBallImages/mitkQBallImage.cpp IODataStructures/QBallImages/mitkQBallImageSerializer.cpp # DataStructures -> Tensor IODataStructures/TensorImages/mitkTensorImageSource.cpp IODataStructures/TensorImages/mitkNrrdTensorImageReader.cpp IODataStructures/TensorImages/mitkNrrdTensorImageWriter.cpp IODataStructures/TensorImages/mitkNrrdTensorImageIOFactory.cpp IODataStructures/TensorImages/mitkNrrdTensorImageWriterFactory.cpp IODataStructures/TensorImages/mitkTensorImage.cpp IODataStructures/TensorImages/mitkTensorImageSerializer.cpp # DataStructures -> FiberBundleX IODataStructures/FiberBundleX/mitkFiberBundleX.cpp IODataStructures/FiberBundleX/mitkFiberBundleXWriter.cpp IODataStructures/FiberBundleX/mitkFiberBundleXReader.cpp IODataStructures/FiberBundleX/mitkFiberBundleXIOFactory.cpp IODataStructures/FiberBundleX/mitkFiberBundleXWriterFactory.cpp IODataStructures/FiberBundleX/mitkFiberBundleXSerializer.cpp IODataStructures/FiberBundleX/mitkFiberBundleXThreadMonitor.cpp # DataStructures -> PlanarFigureComposite IODataStructures/PlanarFigureComposite/mitkPlanarFigureComposite.cpp # DataStructures -> Tbss IODataStructures/TbssImages/mitkTbssImageSource.cpp IODataStructures/TbssImages/mitkTbssRoiImageSource.cpp IODataStructures/TbssImages/mitkNrrdTbssImageReader.cpp IODataStructures/TbssImages/mitkNrrdTbssImageIOFactory.cpp IODataStructures/TbssImages/mitkNrrdTbssRoiImageReader.cpp IODataStructures/TbssImages/mitkNrrdTbssRoiImageIOFactory.cpp IODataStructures/TbssImages/mitkTbssImage.cpp IODataStructures/TbssImages/mitkTbssRoiImage.cpp IODataStructures/TbssImages/mitkNrrdTbssImageWriter.cpp IODataStructures/TbssImages/mitkNrrdTbssImageWriterFactory.cpp IODataStructures/TbssImages/mitkNrrdTbssRoiImageWriter.cpp IODataStructures/TbssImages/mitkNrrdTbssRoiImageWriterFactory.cpp IODataStructures/TbssImages/mitkTbssImporter.cpp # DataStructures Connectomics IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetwork.cpp IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetworkReader.cpp IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetworkIOFactory.cpp IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetworkSerializer.cpp IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetworkWriter.cpp IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetworkWriterFactory.cpp IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetworkDefinitions.cpp IODataStructures/ConnectomicsNetwork/mitkConnectomicsConstantsManager.cpp # Rendering Rendering/vtkMaskedProgrammableGlyphFilter.cpp Rendering/mitkCompositeMapper.cpp Rendering/mitkVectorImageVtkGlyphMapper3D.cpp Rendering/vtkOdfSource.cxx Rendering/vtkThickPlane.cxx Rendering/mitkOdfNormalizationMethodProperty.cpp Rendering/mitkOdfScaleByProperty.cpp Rendering/mitkFiberBundleXMapper2D.cpp Rendering/mitkFiberBundleXMapper3D.cpp Rendering/mitkFiberBundleXThreadMonitorMapper3D.cpp Rendering/mitkTbssImageMapper.cpp Rendering/mitkPlanarCircleMapper3D.cpp Rendering/mitkPlanarPolygonMapper3D.cpp Rendering/mitkConnectomicsNetworkMapper3D.cpp # Interactions Interactions/mitkFiberBundleInteractor.cpp # Algorithms Algorithms/mitkPartialVolumeAnalysisHistogramCalculator.cpp Algorithms/mitkPartialVolumeAnalysisClusteringCalculator.cpp Algorithms/mitkTractAnalyzer.cpp # Algorithms Connectomics Algorithms/Connectomics/mitkConnectomicsNetworkCreator.cpp Algorithms/Connectomics/mitkConnectomicsHistogramBase.cpp Algorithms/Connectomics/mitkConnectomicsDegreeHistogram.cpp Algorithms/Connectomics/mitkConnectomicsShortestPathHistogram.cpp Algorithms/Connectomics/mitkConnectomicsBetweennessHistogram.cpp Algorithms/Connectomics/mitkConnectomicsHistogramCache.cpp Algorithms/Connectomics/mitkConnectomicsSyntheticNetworkGenerator.cpp Algorithms/Connectomics/mitkConnectomicsSimulatedAnnealingPermutationBase.cpp Algorithms/Connectomics/mitkConnectomicsSimulatedAnnealingPermutationModularity.cpp Algorithms/Connectomics/mitkConnectomicsSimulatedAnnealingManager.cpp Algorithms/Connectomics/mitkConnectomicsSimulatedAnnealingCostFunctionBase.cpp Algorithms/Connectomics/mitkConnectomicsSimulatedAnnealingCostFunctionModularity.cpp # Tractography Tractography/itkStochasticTractographyFilter.h # Function Collection mitkDiffusionFunctionCollection.cpp ) set(H_FILES # function Collection mitkDiffusionFunctionCollection.h - + # Rendering Rendering/mitkDiffusionImageMapper.h Rendering/mitkTbssImageMapper.h Rendering/mitkOdfVtkMapper2D.h Rendering/mitkFiberBundleXMapper3D.h Rendering/mitkFiberBundleXMapper2D.h Rendering/mitkFiberBundleXThreadMonitorMapper3D.h Rendering/mitkPlanarCircleMapper3D.h Rendering/mitkPlanarPolygonMapper3D.h Rendering/mitkConnectomicsNetworkMapper3D.h # Reconstruction Reconstruction/itkDiffusionQballReconstructionImageFilter.h Reconstruction/mitkTeemDiffusionTensor3DReconstructionImageFilter.h Reconstruction/itkAnalyticalDiffusionQballReconstructionImageFilter.h Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.h Reconstruction/itkPointShell.h Reconstruction/itkOrientationDistributionFunction.h Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h Reconstruction/itkRegularizedIVIMLocalVariationImageFilter.h Reconstruction/itkRegularizedIVIMReconstructionFilter.h Reconstruction/itkRegularizedIVIMReconstructionSingleIteration.h # IO Datastructures IODataStructures/DiffusionWeightedImages/mitkDiffusionImage.h IODataStructures/TbssImages/mitkTbssImporter.h # DataStructures -> FiberBundleX IODataStructures/FiberBundleX/mitkFiberBundleX.h IODataStructures/FiberBundleX/mitkFiberBundleXWriter.h IODataStructures/FiberBundleX/mitkFiberBundleXReader.h IODataStructures/FiberBundleX/mitkFiberBundleXIOFactory.h IODataStructures/FiberBundleX/mitkFiberBundleXWriterFactory.h IODataStructures/FiberBundleX/mitkFiberBundleXSerializer.h IODataStructures/FiberBundleX/mitkFiberBundleXThreadMonitor.h # Datastructures Connectomics IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetwork.h IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetworkReader.h IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetworkIOFactory.h IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetworkSerializer.h IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetworkWriter.h IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetworkWriterFactory.h IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetworkDefinitions.h IODataStructures/ConnectomicsNetwork/mitkConnectomicsConstantsManager.h # Tractography Tractography/itkGibbsTrackingFilter.h Tractography/itkStochasticTractographyFilter.h + Tractography/itkStreamlineTrackingFilter.h # Algorithms Algorithms/itkDiffusionQballGeneralizedFaImageFilter.h Algorithms/itkDiffusionQballPrepareVisualizationImageFilter.h Algorithms/itkTensorDerivedMeasurementsFilter.h Algorithms/itkBrainMaskExtractionImageFilter.h Algorithms/itkB0ImageExtractionImageFilter.h Algorithms/itkB0ImageExtractionToSeparateImageFilter.h Algorithms/itkTensorImageToDiffusionImageFilter.h Algorithms/itkTensorToL2NormImageFilter.h Algorithms/itkTractDensityImageFilter.h Algorithms/itkTractsToFiberEndingsImageFilter.h Algorithms/itkTractsToRgbaImageFilter.h Algorithms/itkGaussianInterpolateImageFunction.h Algorithms/mitkPartialVolumeAnalysisHistogramCalculator.h Algorithms/mitkPartialVolumeAnalysisClusteringCalculator.h Algorithms/itkDiffusionTensorPrincipleDirectionImageFilter.h Algorithms/itkCartesianToPolarVectorImageFilter.h Algorithms/itkPolarToCartesianVectorImageFilter.h Algorithms/itkDistanceMapFilter.h Algorithms/itkProjectionFilter.h Algorithms/itkSkeletonizationFilter.h Algorithms/itkReduceDirectionGradientsFilter.h Algorithms/itkResidualImageFilter.h Algorithms/itkExtractChannelFromRgbaImageFilter.h # Algorithms Connectomics Algorithms/Connectomics/mitkConnectomicsNetworkCreator.h Algorithms/Connectomics/mitkConnectomicsHistogramBase.h Algorithms/Connectomics/mitkConnectomicsDegreeHistogram.h Algorithms/Connectomics/mitkConnectomicsShortestPathHistogram.h Algorithms/Connectomics/mitkConnectomicsBetweennessHistogram.h Algorithms/Connectomics/mitkConnectomicsHistogramCache.h Algorithms/Connectomics/mitkConnectomicsSyntheticNetworkGenerator.h Algorithms/Connectomics/mitkConnectomicsSimulatedAnnealingPermutationBase.h Algorithms/Connectomics/mitkConnectomicsSimulatedAnnealingPermutationModularity.h Algorithms/Connectomics/mitkConnectomicsSimulatedAnnealingManager.h Algorithms/Connectomics/mitkConnectomicsSimulatedAnnealingCostFunctionBase.h Algorithms/Connectomics/mitkConnectomicsSimulatedAnnealingCostFunctionModularity.h Algorithms/itkTensorReconstructionWithEigenvalueCorrectionFilter.h - + ) set( TOOL_FILES ) if(WIN32) endif(WIN32) #MITK_MULTIPLEX_PICTYPE( Algorithms/mitkImageRegistrationMethod-TYPE.cpp ) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake index 68930fafcd..dcdcef089d 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake @@ -1,121 +1,124 @@ set(SRC_CPP_FILES QmitkODFDetailsWidget.cpp QmitkODFRenderWidget.cpp QmitkPartialVolumeAnalysisWidget.cpp QmitkIVIMWidget.cpp QmitkTbssRoiAnalysisWidget.cpp QmitkResidualAnalysisWidget.cpp QmitkResidualViewWidget.cpp ) set(INTERNAL_CPP_FILES mitkPluginActivator.cpp QmitkQBallReconstructionView.cpp QmitkPreprocessingView.cpp QmitkDiffusionDicomImportView.cpp QmitkDiffusionQuantificationView.cpp QmitkTensorReconstructionView.cpp QmitkDiffusionImagingPublicPerspective.cpp QmitkControlVisualizationPropertiesView.cpp QmitkODFDetailsView.cpp QmitkGibbsTrackingView.cpp QmitkStochasticFiberTrackingView.cpp + QmitkStreamlineTrackingView.cpp QmitkFiberProcessingView.cpp QmitkFiberBundleDeveloperView.cpp QmitkPartialVolumeAnalysisView.cpp QmitkIVIMView.cpp QmitkTractbasedSpatialStatisticsView.cpp QmitkTbssTableModel.cpp QmitkTbssMetaTableModel.cpp QmitkTbssSkeletonizationView.cpp Connectomics/QmitkBrainNetworkAnalysisView.cpp Connectomics/QmitkNetworkHistogramCanvas.cpp ) set(UI_FILES src/internal/QmitkQBallReconstructionViewControls.ui src/internal/QmitkPreprocessingViewControls.ui src/internal/QmitkDiffusionDicomImportViewControls.ui src/internal/QmitkDiffusionQuantificationViewControls.ui src/internal/QmitkTensorReconstructionViewControls.ui src/internal/QmitkControlVisualizationPropertiesViewControls.ui src/internal/QmitkODFDetailsViewControls.ui src/internal/QmitkGibbsTrackingViewControls.ui src/internal/QmitkStochasticFiberTrackingViewControls.ui + src/internal/QmitkStreamlineTrackingViewControls.ui src/internal/QmitkFiberProcessingViewControls.ui src/internal/QmitkFiberBundleDeveloperViewControls.ui src/internal/QmitkPartialVolumeAnalysisViewControls.ui src/internal/QmitkIVIMViewControls.ui src/internal/QmitkTractbasedSpatialStatisticsViewControls.ui src/internal/QmitkTbssSkeletonizationViewControls.ui src/internal/Connectomics/QmitkBrainNetworkAnalysisViewControls.ui ) set(MOC_H_FILES src/internal/mitkPluginActivator.h src/internal/QmitkQBallReconstructionView.h src/internal/QmitkPreprocessingView.h src/internal/QmitkDiffusionDicomImportView.h src/internal/QmitkDiffusionImagingPublicPerspective.h src/internal/QmitkDiffusionQuantificationView.h src/internal/QmitkTensorReconstructionView.h src/internal/QmitkControlVisualizationPropertiesView.h src/internal/QmitkODFDetailsView.h src/QmitkODFRenderWidget.h src/QmitkODFDetailsWidget.h src/internal/QmitkGibbsTrackingView.h src/internal/QmitkStochasticFiberTrackingView.h + src/internal/QmitkStreamlineTrackingView.h src/internal/QmitkFiberProcessingView.h src/internal/QmitkFiberBundleDeveloperView.h src/internal/QmitkPartialVolumeAnalysisView.h src/QmitkPartialVolumeAnalysisWidget.h src/internal/QmitkIVIMView.h src/internal/QmitkTractbasedSpatialStatisticsView.h src/internal/QmitkTbssSkeletonizationView.h src/QmitkTbssRoiAnalysisWidget.h src/QmitkResidualAnalysisWidget.h src/QmitkResidualViewWidget.h src/internal/Connectomics/QmitkBrainNetworkAnalysisView.h src/internal/Connectomics/QmitkNetworkHistogramCanvas.h ) set(CACHED_RESOURCE_FILES # list of resource files which can be used by the plug-in # system without loading the plug-ins shared library, # for example the icon used in the menu and tabs for the # plug-in views in the workbench plugin.xml resources/preprocessing.png resources/dwiimport.png resources/quantification.png resources/reconodf.png resources/recontensor.png resources/vizControls.png resources/OdfDetails.png resources/GibbsTracking.png resources/FiberBundleOperations.png resources/PartialVolumeAnalysis_24.png resources/IVIM_48.png resources/stochFB.png resources/tbss.png resources/QmitkBrainNetworkAnalysisViewIcon_48.png resources/arrow.png ) set(QRC_FILES # uncomment the following line if you want to use Qt resources resources/QmitkDiffusionImaging.qrc #resources/QmitkTractbasedSpatialStatisticsView.qrc ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/plugin.xml b/Plugins/org.mitk.gui.qt.diffusionimaging/plugin.xml index e8b9846c4b..76277778da 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/plugin.xml +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/plugin.xml @@ -1,125 +1,132 @@ <?xml version="1.0" encoding="UTF-8"?> <?BlueBerry version="0.1"?> <plugin> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.qballreconstruction" name="Q-Balls" icon="resources/reconodf.png" class="QmitkQBallReconstructionView" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.diffusiondicomimport" name="DICOM Import" class="QmitkDiffusionDicomImport" icon="resources/dwiimport.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.diffusionpreprocessing" name="Preprocessing" class="QmitkPreprocessingView" icon="resources/preprocessing.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.diffusionquantification" name="Quantification" class="QmitkDiffusionQuantificationView" icon="resources/quantification.png"/> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.tensorreconstruction" name="Tensors" icon="resources/recontensor.png" class="QmitkTensorReconstructionView" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.controlvisualizationpropertiesview" name="Visualization" icon="resources/vizControls.png" class="QmitkControlVisualizationPropertiesView" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.ivim" name="IVIM" class="QmitkIVIMView" icon="resources/IVIM_48.png" /> </extension> <extension point="org.blueberry.ui.perspectives"> <perspective id="org.mitk.perspectives.publicdiffusionimaging" name="Diffusion Imaging Public" class="QmitkDiffusionImagingPublicPerspective" icon="resources/reconodf.png"/> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.odfdetails" name="ODF Details" class="QmitkODFDetailsView" icon="resources/OdfDetails.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.gibbstracking" name="Gibbs Tracking" class="QmitkGibbsTrackingView" icon="resources/GibbsTracking.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.stochasticfibertracking" name="Stochastic Tracking" class="QmitkStochasticFiberTrackingView" icon="resources/stochFB.png" /> </extension> + <extension point="org.blueberry.ui.views"> + <view id="org.mitk.views.streamlinetracking" + name="Streamline Tracking" + class="QmitkStreamlineTrackingView" + icon="resources/stochFB.png" /> + </extension> + <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.fiberprocessing" name="Fiber Processing" class="QmitkFiberProcessingView" icon="resources/FiberBundleOperations.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.fiberbundledeveloper" name="FiberDevTool" class="QmitkFiberBundleDeveloperView" icon="resources/FiberBundleOperations.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.partialvolumeanalysisview" name="PV Analysis" class="QmitkPartialVolumeAnalysisView" icon="resources/PartialVolumeAnalysis_24.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.tbssskeletonization" name="Tbss Skeletonization" class="QmitkTbssSkeletonizationView" icon="resources/tbss.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.tractbasedspatialstatistics" name="Tract-based spatial statistics" class="QmitkTractbasedSpatialStatisticsView" icon="resources/tbss.png" /> </extension> <extension point="org.blueberry.ui.views"> <view id="org.mitk.views.brainnetworkanalysis" name="Brain Network Analysis" class="QmitkBrainNetworkAnalysisView" icon="resources/QmitkBrainNetworkAnalysisViewIcon_48.png" /> </extension> </plugin> diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp index 397b9cef81..2fb8a396fd 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp @@ -1,1766 +1,1797 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) -Copyright (c) German Cancer Research Center, +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 +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. ===================================================================*/ // Blueberry #include <berryISelectionService.h> #include <berryIWorkbenchWindow.h> // Qmitk #include "QmitkFiberProcessingView.h" #include <QmitkStdMultiWidget.h> // Qt #include <QMessageBox> // MITK #include <mitkNodePredicateProperty.h> #include <mitkImageCast.h> #include <mitkPointSet.h> #include <mitkPlanarCircle.h> #include <mitkPlanarPolygon.h> #include <mitkPlanarRectangle.h> #include <mitkPlanarFigureInteractor.h> #include <mitkGlobalInteraction.h> #include <mitkImageAccessByItk.h> #include <mitkDataNodeObject.h> #include <mitkDiffusionImage.h> +#include <mitkTensorImage.h> // ITK #include <itkResampleImageFilter.h> #include <itkGaussianInterpolateImageFunction.h> #include <itkImageRegionIteratorWithIndex.h> #include <itkTractsToFiberEndingsImageFilter.h> #include <itkTractDensityImageFilter.h> #include <itkImageRegion.h> #include <itkTractsToRgbaImageFilter.h> #include <math.h> const std::string QmitkFiberProcessingView::VIEW_ID = "org.mitk.views.fiberprocessing"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace mitk; QmitkFiberProcessingView::QmitkFiberProcessingView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) , m_EllipseCounter(0) , m_PolygonCounter(0) , m_UpsamplingFactor(5) { } // Destructor QmitkFiberProcessingView::~QmitkFiberProcessingView() { } void QmitkFiberProcessingView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkFiberProcessingViewControls; m_Controls->setupUi( parent ); m_Controls->doExtractFibersButton->setDisabled(true); m_Controls->PFCompoANDButton->setDisabled(true); m_Controls->PFCompoORButton->setDisabled(true); m_Controls->PFCompoNOTButton->setDisabled(true); m_Controls->m_PlanarFigureButtonsFrame->setEnabled(false); m_Controls->m_RectangleButton->setVisible(false); connect( m_Controls->doExtractFibersButton, SIGNAL(clicked()), this, SLOT(DoFiberExtraction()) ); connect( m_Controls->m_CircleButton, SIGNAL( clicked() ), this, SLOT( OnDrawCircle() ) ); connect( m_Controls->m_PolygonButton, SIGNAL( clicked() ), this, SLOT( OnDrawPolygon() ) ); connect(m_Controls->PFCompoANDButton, SIGNAL(clicked()), this, SLOT(GenerateAndComposite()) ); connect(m_Controls->PFCompoORButton, SIGNAL(clicked()), this, SLOT(GenerateOrComposite()) ); connect(m_Controls->PFCompoNOTButton, SIGNAL(clicked()), this, SLOT(GenerateNotComposite()) ); - connect(m_Controls->m_JoinBundles, SIGNAL(clicked()), this, SLOT(JoinBundles()) ); connect(m_Controls->m_SubstractBundles, SIGNAL(clicked()), this, SLOT(SubstractBundles()) ); connect(m_Controls->m_GenerateRoiImage, SIGNAL(clicked()), this, SLOT(GenerateRoiImage()) ); - connect(m_Controls->m_Extract3dButton, SIGNAL(clicked()), this, SLOT(Extract3d())); connect( m_Controls->m_ProcessFiberBundleButton, SIGNAL(clicked()), this, SLOT(ProcessSelectedBundles()) ); connect( m_Controls->m_ResampleFibersButton, SIGNAL(clicked()), this, SLOT(ResampleSelectedBundles()) ); connect(m_Controls->m_FaColorFibersButton, SIGNAL(clicked()), this, SLOT(DoFaColorCoding())); + connect( m_Controls->m_PruneFibersButton, SIGNAL(clicked()), this, SLOT(PruneBundle()) ); + connect( m_Controls->m_MirrorFibersButton, SIGNAL(clicked()), this, SLOT(MirrorFibers()) ); + } } void QmitkFiberProcessingView::Extract3d() { std::vector<mitk::DataNode*> nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::FiberBundleX::Pointer fib = mitk::FiberBundleX::New(); mitk::Surface::Pointer roi = mitk::Surface::New(); bool fibB = false; bool roiB = false; for (int i=0; i<nodes.size(); i++) { if (dynamic_cast<mitk::FiberBundleX*>(nodes.at(i)->GetData())) { fib = dynamic_cast<mitk::FiberBundleX*>(nodes.at(i)->GetData()); fibB = true; } else if (dynamic_cast<mitk::Surface*>(nodes.at(i)->GetData())) { roi = dynamic_cast<mitk::Surface*>(nodes.at(i)->GetData()); roiB = true; } } if (!fibB) return; if (!roiB) return; vtkSmartPointer<vtkPolyData> polyRoi = roi->GetVtkPolyData(); vtkSmartPointer<vtkPolyData> polyFib = fib->GetFiberPolyData(); vtkSmartPointer<vtkSelectEnclosedPoints> selectEnclosedPoints = vtkSmartPointer<vtkSelectEnclosedPoints>::New(); selectEnclosedPoints->SetInput(polyFib); selectEnclosedPoints->SetSurface(polyRoi); selectEnclosedPoints->Update(); vtkSmartPointer<vtkPolyData> newPoly = vtkSmartPointer<vtkPolyData>::New(); vtkSmartPointer<vtkCellArray> newCellArray = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkPolyData> newPolyComplement = vtkSmartPointer<vtkPolyData>::New(); vtkSmartPointer<vtkCellArray> newCellArrayComplement = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkPoints> newPointsComplement = vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkCellArray> vLines = polyFib->GetLines(); vLines->InitTraversal(); int numberOfLines = vLines->GetNumberOfCells(); // each line for (int j=0; j<numberOfLines; j++) { vtkIdType numPoints(0); vtkIdType* points(NULL); vLines->GetNextCell ( numPoints, points ); bool isPassing = false; // each point of this line for (int k=0; k<numPoints; k++) { // is point inside polydata ? if (selectEnclosedPoints->IsInside(points[k])) { isPassing = true; // fill new polydata vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New(); for (int k=0; k<numPoints; k++) { double* point = polyFib->GetPoint(points[k]); vtkIdType pointId = newPoints->InsertNextPoint(point); container->GetPointIds()->InsertNextId(pointId); } newCellArray->InsertNextCell(container); break; } } if (!isPassing) { vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New(); for (int k=0; k<numPoints; k++) { double* point = polyFib->GetPoint(points[k]); vtkIdType pointId = newPointsComplement->InsertNextPoint(point); container->GetPointIds()->InsertNextId(pointId); } newCellArrayComplement->InsertNextCell(container); } } newPoly->SetPoints(newPoints); newPoly->SetLines(newCellArray); mitk::FiberBundleX::Pointer fb = mitk::FiberBundleX::New(newPoly); DataNode::Pointer newNode = DataNode::New(); newNode->SetData(fb); newNode->SetName("passing surface"); GetDefaultDataStorage()->Add(newNode); newPolyComplement->SetPoints(newPointsComplement); newPolyComplement->SetLines(newCellArrayComplement); mitk::FiberBundleX::Pointer fbComplement = mitk::FiberBundleX::New(newPolyComplement); DataNode::Pointer newNodeComplement = DataNode::New(); newNodeComplement->SetData(fbComplement); newNodeComplement->SetName("not passing surface"); GetDefaultDataStorage()->Add(newNodeComplement); } void QmitkFiberProcessingView::GenerateRoiImage(){ if (m_SelectedPF.empty()) return; mitk::Geometry3D::Pointer geometry; if (!m_SelectedFB.empty()) { mitk::FiberBundleX::Pointer fib = dynamic_cast<mitk::FiberBundleX*>(m_SelectedFB.front()->GetData()); geometry = fib->GetGeometry(); } else return; mitk::Vector3D spacing = geometry->GetSpacing(); spacing /= m_UpsamplingFactor; mitk::Point3D newOrigin = geometry->GetOrigin(); mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); newOrigin[0] += bounds.GetElement(0); newOrigin[1] += bounds.GetElement(2); newOrigin[2] += bounds.GetElement(4); itk::Matrix<double, 3, 3> direction; itk::ImageRegion<3> imageRegion; for (int i=0; i<3; i++) for (int j=0; j<3; j++) direction[j][i] = geometry->GetMatrixColumn(i)[j]/spacing[j]; imageRegion.SetSize(0, geometry->GetExtent(0)*m_UpsamplingFactor); imageRegion.SetSize(1, geometry->GetExtent(1)*m_UpsamplingFactor); imageRegion.SetSize(2, geometry->GetExtent(2)*m_UpsamplingFactor); m_PlanarFigureImage = itkUCharImageType::New(); m_PlanarFigureImage->SetSpacing( spacing ); // Set the image spacing m_PlanarFigureImage->SetOrigin( newOrigin ); // Set the image origin m_PlanarFigureImage->SetDirection( direction ); // Set the image direction m_PlanarFigureImage->SetRegions( imageRegion ); m_PlanarFigureImage->Allocate(); m_PlanarFigureImage->FillBuffer( 0 ); Image::Pointer tmpImage = Image::New(); tmpImage->InitializeByItk(m_PlanarFigureImage.GetPointer()); tmpImage->SetVolume(m_PlanarFigureImage->GetBufferPointer()); for (int i=0; i<m_SelectedPF.size(); i++) CompositeExtraction(m_SelectedPF.at(i), tmpImage); DataNode::Pointer node = DataNode::New(); tmpImage = Image::New(); tmpImage->InitializeByItk(m_PlanarFigureImage.GetPointer()); tmpImage->SetVolume(m_PlanarFigureImage->GetBufferPointer()); node->SetData(tmpImage); node->SetName("ROI Image"); this->GetDefaultDataStorage()->Add(node); } void QmitkFiberProcessingView::CompositeExtraction(mitk::DataNode::Pointer node, mitk::Image* image) { if (dynamic_cast<mitk::PlanarFigure*>(node.GetPointer()->GetData()) && !dynamic_cast<mitk::PlanarFigureComposite*>(node.GetPointer()->GetData())) { m_PlanarFigure = dynamic_cast<mitk::PlanarFigure*>(node.GetPointer()->GetData()); AccessFixedDimensionByItk_2( image, InternalReorientImagePlane, 3, m_PlanarFigure->GetGeometry(), -1); // itk::Image< unsigned char, 3 >::Pointer outimage = itk::Image< unsigned char, 3 >::New(); // outimage->SetSpacing( m_PlanarFigure->GetGeometry()->GetSpacing()/m_UpsamplingFactor ); // Set the image spacing // mitk::Point3D origin = m_PlanarFigure->GetGeometry()->GetOrigin(); // mitk::Point3D indexOrigin; // m_PlanarFigure->GetGeometry()->WorldToIndex(origin, indexOrigin); // indexOrigin[0] = indexOrigin[0] - .5 * (1.0-1.0/m_UpsamplingFactor); // indexOrigin[1] = indexOrigin[1] - .5 * (1.0-1.0/m_UpsamplingFactor); // indexOrigin[2] = indexOrigin[2] - .5 * (1.0-1.0/m_UpsamplingFactor); // mitk::Point3D newOrigin; // m_PlanarFigure->GetGeometry()->IndexToWorld(indexOrigin, newOrigin); // outimage->SetOrigin( newOrigin ); // Set the image origin // itk::Matrix<double, 3, 3> matrix; // for (int i=0; i<3; i++) // for (int j=0; j<3; j++) // matrix[j][i] = m_PlanarFigure->GetGeometry()->GetMatrixColumn(i)[j]/m_PlanarFigure->GetGeometry()->GetSpacing().GetElement(i); // outimage->SetDirection( matrix ); // Set the image direction // itk::ImageRegion<3> upsampledRegion; // upsampledRegion.SetSize(0, m_PlanarFigure->GetGeometry()->GetParametricExtentInMM(0)/m_PlanarFigure->GetGeometry()->GetSpacing()[0]); // upsampledRegion.SetSize(1, m_PlanarFigure->GetGeometry()->GetParametricExtentInMM(1)/m_PlanarFigure->GetGeometry()->GetSpacing()[1]); // upsampledRegion.SetSize(2, 1); // typename itk::Image< unsigned char, 3 >::RegionType::SizeType upsampledSize = upsampledRegion.GetSize(); // for (unsigned int n = 0; n < 2; n++) // { // upsampledSize[n] = upsampledSize[n] * m_UpsamplingFactor; // } // upsampledRegion.SetSize( upsampledSize ); // outimage->SetRegions( upsampledRegion ); // outimage->Allocate(); // this->m_InternalImage = mitk::Image::New(); // this->m_InternalImage->InitializeByItk( outimage.GetPointer() ); // this->m_InternalImage->SetVolume( outimage->GetBufferPointer() ); AccessFixedDimensionByItk_2( m_InternalImage, InternalCalculateMaskFromPlanarFigure, 3, 2, node->GetName() ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkFiberProcessingView::InternalReorientImagePlane( const itk::Image< TPixel, VImageDimension > *image, mitk::Geometry3D* planegeo3D, int additionalIndex ) { MITK_INFO << "InternalReorientImagePlane() start"; typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::Image< float, VImageDimension > FloatImageType; typedef itk::ResampleImageFilter<ImageType, FloatImageType, double> ResamplerType; typename ResamplerType::Pointer resampler = ResamplerType::New(); mitk::PlaneGeometry* planegeo = dynamic_cast<mitk::PlaneGeometry*>(planegeo3D); float upsamp = m_UpsamplingFactor; float gausssigma = 0.5; // Spacing typename ResamplerType::SpacingType spacing = planegeo->GetSpacing(); spacing[0] = image->GetSpacing()[0] / upsamp; spacing[1] = image->GetSpacing()[1] / upsamp; spacing[2] = image->GetSpacing()[2]; resampler->SetOutputSpacing( spacing ); // Size typename ResamplerType::SizeType size; size[0] = planegeo->GetParametricExtentInMM(0) / spacing[0]; size[1] = planegeo->GetParametricExtentInMM(1) / spacing[1]; size[2] = 1; resampler->SetSize( size ); // Origin typename mitk::Point3D orig = planegeo->GetOrigin(); typename mitk::Point3D corrorig; planegeo3D->WorldToIndex(orig,corrorig); corrorig[0] += 0.5/upsamp; corrorig[1] += 0.5/upsamp; corrorig[2] += 0; planegeo3D->IndexToWorld(corrorig,corrorig); resampler->SetOutputOrigin(corrorig ); // Direction typename ResamplerType::DirectionType direction; typename mitk::AffineTransform3D::MatrixType matrix = planegeo->GetIndexToWorldTransform()->GetMatrix(); for(int c=0; c<matrix.ColumnDimensions; c++) { double sum = 0; for(int r=0; r<matrix.RowDimensions; r++) { sum += matrix(r,c)*matrix(r,c); } for(int r=0; r<matrix.RowDimensions; r++) { direction(r,c) = matrix(r,c)/sqrt(sum); } } resampler->SetOutputDirection( direction ); // Gaussian interpolation if(gausssigma != 0) { double sigma[3]; for( unsigned int d = 0; d < 3; d++ ) { sigma[d] = gausssigma * image->GetSpacing()[d]; } double alpha = 2.0; typedef itk::GaussianInterpolateImageFunction<ImageType, double> GaussianInterpolatorType; typename GaussianInterpolatorType::Pointer interpolator = GaussianInterpolatorType::New(); interpolator->SetInputImage( image ); interpolator->SetParameters( sigma, alpha ); resampler->SetInterpolator( interpolator ); } else { // typedef typename itk::BSplineInterpolateImageFunction<ImageType, double> // InterpolatorType; typedef typename itk::LinearInterpolateImageFunction<ImageType, double> InterpolatorType; typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); interpolator->SetInputImage( image ); resampler->SetInterpolator( interpolator ); } // Other resampling options resampler->SetInput( image ); resampler->SetDefaultPixelValue(0); MITK_INFO << "Resampling requested image plane ... "; resampler->Update(); MITK_INFO << " ... done"; if(additionalIndex < 0) { this->m_InternalImage = mitk::Image::New(); this->m_InternalImage->InitializeByItk( resampler->GetOutput() ); this->m_InternalImage->SetVolume( resampler->GetOutput()->GetBufferPointer() ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkFiberProcessingView::InternalCalculateMaskFromPlanarFigure( itk::Image< TPixel, VImageDimension > *image, unsigned int axis, std::string nodeName ) { MITK_INFO << "InternalCalculateMaskFromPlanarFigure() start"; typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::CastImageFilter< ImageType, itkUCharImageType > CastFilterType; // Generate mask image as new image with same header as input image and // initialize with "1". itkUCharImageType::Pointer newMaskImage = itkUCharImageType::New(); newMaskImage->SetSpacing( image->GetSpacing() ); // Set the image spacing newMaskImage->SetOrigin( image->GetOrigin() ); // Set the image origin newMaskImage->SetDirection( image->GetDirection() ); // Set the image direction newMaskImage->SetRegions( image->GetLargestPossibleRegion() ); newMaskImage->Allocate(); newMaskImage->FillBuffer( 1 ); // Generate VTK polygon from (closed) PlanarFigure polyline // (The polyline points are shifted by -0.5 in z-direction to make sure // that the extrusion filter, which afterwards elevates all points by +0.5 // in z-direction, creates a 3D object which is cut by the the plane z=0) const Geometry2D *planarFigureGeometry2D = m_PlanarFigure->GetGeometry2D(); const PlanarFigure::PolyLineType planarFigurePolyline = m_PlanarFigure->GetPolyLine( 0 ); const Geometry3D *imageGeometry3D = m_InternalImage->GetGeometry( 0 ); vtkPolyData *polyline = vtkPolyData::New(); polyline->Allocate( 1, 1 ); // Determine x- and y-dimensions depending on principal axis int i0, i1; switch ( axis ) { case 0: i0 = 1; i1 = 2; break; case 1: i0 = 0; i1 = 2; break; case 2: default: i0 = 0; i1 = 1; break; } // Create VTK polydata object of polyline contour vtkPoints *points = vtkPoints::New(); PlanarFigure::PolyLineType::const_iterator it; std::vector<vtkIdType> indices; unsigned int numberOfPoints = 0; for ( it = planarFigurePolyline.begin(); it != planarFigurePolyline.end(); ++it ) { Point3D point3D; // Convert 2D point back to the local index coordinates of the selected // image Point2D point2D = it->Point; planarFigureGeometry2D->WorldToIndex(point2D, point2D); point2D[0] -= 0.5/m_UpsamplingFactor; point2D[1] -= 0.5/m_UpsamplingFactor; planarFigureGeometry2D->IndexToWorld(point2D, point2D); planarFigureGeometry2D->Map( point2D, point3D ); // Polygons (partially) outside of the image bounds can not be processed // further due to a bug in vtkPolyDataToImageStencil if ( !imageGeometry3D->IsInside( point3D ) ) { float bounds[2] = {0,0}; bounds[0] = this->m_InternalImage->GetLargestPossibleRegion().GetSize().GetElement(i0); bounds[1] = this->m_InternalImage->GetLargestPossibleRegion().GetSize().GetElement(i1); imageGeometry3D->WorldToIndex( point3D, point3D ); // if (point3D[i0]<0) // point3D[i0] = 0.5; // else if (point3D[i0]>bounds[0]) // point3D[i0] = bounds[0]-0.5; // if (point3D[i1]<0) // point3D[i1] = 0.5; // else if (point3D[i1]>bounds[1]) // point3D[i1] = bounds[1]-0.5; if (point3D[i0]<0) point3D[i0] = 0.0; else if (point3D[i0]>bounds[0]) point3D[i0] = bounds[0]-0.001; if (point3D[i1]<0) point3D[i1] = 0.0; else if (point3D[i1]>bounds[1]) point3D[i1] = bounds[1]-0.001; points->InsertNextPoint( point3D[i0], point3D[i1], -0.5 ); numberOfPoints++; } else { imageGeometry3D->WorldToIndex( point3D, point3D ); // Add point to polyline array points->InsertNextPoint( point3D[i0], point3D[i1], -0.5 ); numberOfPoints++; } } polyline->SetPoints( points ); points->Delete(); vtkIdType *ptIds = new vtkIdType[numberOfPoints]; for ( vtkIdType i = 0; i < numberOfPoints; ++i ) { ptIds[i] = i; } polyline->InsertNextCell( VTK_POLY_LINE, numberOfPoints, ptIds ); // Extrude the generated contour polygon vtkLinearExtrusionFilter *extrudeFilter = vtkLinearExtrusionFilter::New(); extrudeFilter->SetInput( polyline ); extrudeFilter->SetScaleFactor( 1 ); extrudeFilter->SetExtrusionTypeToNormalExtrusion(); extrudeFilter->SetVector( 0.0, 0.0, 1.0 ); // Make a stencil from the extruded polygon vtkPolyDataToImageStencil *polyDataToImageStencil = vtkPolyDataToImageStencil::New(); polyDataToImageStencil->SetInput( extrudeFilter->GetOutput() ); // Export from ITK to VTK (to use a VTK filter) typedef itk::VTKImageImport< itkUCharImageType > ImageImportType; typedef itk::VTKImageExport< itkUCharImageType > ImageExportType; typename ImageExportType::Pointer itkExporter = ImageExportType::New(); itkExporter->SetInput( newMaskImage ); vtkImageImport *vtkImporter = vtkImageImport::New(); this->ConnectPipelines( itkExporter, vtkImporter ); vtkImporter->Update(); // Apply the generated image stencil to the input image vtkImageStencil *imageStencilFilter = vtkImageStencil::New(); imageStencilFilter->SetInputConnection( vtkImporter->GetOutputPort() ); imageStencilFilter->SetStencil( polyDataToImageStencil->GetOutput() ); imageStencilFilter->ReverseStencilOff(); imageStencilFilter->SetBackgroundValue( 0 ); imageStencilFilter->Update(); // Export from VTK back to ITK vtkImageExport *vtkExporter = vtkImageExport::New(); vtkExporter->SetInputConnection( imageStencilFilter->GetOutputPort() ); vtkExporter->Update(); typename ImageImportType::Pointer itkImporter = ImageImportType::New(); this->ConnectPipelines( vtkExporter, itkImporter ); itkImporter->Update(); // calculate cropping bounding box m_InternalImageMask3D = itkImporter->GetOutput(); m_InternalImageMask3D->SetDirection(image->GetDirection()); itk::ImageRegionConstIterator<itkUCharImageType> itmask(m_InternalImageMask3D, m_InternalImageMask3D->GetLargestPossibleRegion()); itk::ImageRegionIterator<ImageType> itimage(image, image->GetLargestPossibleRegion()); itmask = itmask.Begin(); itimage = itimage.Begin(); typename ImageType::SizeType lowersize = {{9999999999,9999999999,9999999999}}; typename ImageType::SizeType uppersize = {{0,0,0}}; while( !itmask.IsAtEnd() ) { if(itmask.Get() == 0) { itimage.Set(0); } else { typename ImageType::IndexType index = itimage.GetIndex(); typename ImageType::SizeType signedindex; signedindex[0] = index[0]; signedindex[1] = index[1]; signedindex[2] = index[2]; lowersize[0] = signedindex[0] < lowersize[0] ? signedindex[0] : lowersize[0]; lowersize[1] = signedindex[1] < lowersize[1] ? signedindex[1] : lowersize[1]; lowersize[2] = signedindex[2] < lowersize[2] ? signedindex[2] : lowersize[2]; uppersize[0] = signedindex[0] > uppersize[0] ? signedindex[0] : uppersize[0]; uppersize[1] = signedindex[1] > uppersize[1] ? signedindex[1] : uppersize[1]; uppersize[2] = signedindex[2] > uppersize[2] ? signedindex[2] : uppersize[2]; } ++itmask; ++itimage; } typename ImageType::IndexType index; index[0] = lowersize[0]; index[1] = lowersize[1]; index[2] = lowersize[2]; typename ImageType::SizeType size; size[0] = uppersize[0] - lowersize[0] + 1; size[1] = uppersize[1] - lowersize[1] + 1; size[2] = uppersize[2] - lowersize[2] + 1; itk::ImageRegion<3> cropRegion = itk::ImageRegion<3>(index, size); // crop internal mask typedef itk::RegionOfInterestImageFilter< itkUCharImageType, itkUCharImageType > ROIMaskFilterType; typename ROIMaskFilterType::Pointer roi2 = ROIMaskFilterType::New(); roi2->SetRegionOfInterest(cropRegion); roi2->SetInput(m_InternalImageMask3D); roi2->Update(); m_InternalImageMask3D = roi2->GetOutput(); Image::Pointer tmpImage = Image::New(); tmpImage->InitializeByItk(m_InternalImageMask3D.GetPointer()); tmpImage->SetVolume(m_InternalImageMask3D->GetBufferPointer()); Image::Pointer tmpImage2 = Image::New(); tmpImage2->InitializeByItk(m_PlanarFigureImage.GetPointer()); const Geometry3D *pfImageGeometry3D = tmpImage2->GetGeometry( 0 ); const Geometry3D *intImageGeometry3D = tmpImage->GetGeometry( 0 ); typedef itk::ImageRegionIteratorWithIndex<itkUCharImageType> IteratorType; IteratorType imageIterator (m_InternalImageMask3D, m_InternalImageMask3D->GetRequestedRegion()); imageIterator.GoToBegin(); while ( !imageIterator.IsAtEnd() ) { unsigned char val = imageIterator.Value(); if (val>0) { itk::Index<3> index = imageIterator.GetIndex(); Point3D point; point[0] = index[0]; point[1] = index[1]; point[2] = index[2]; intImageGeometry3D->IndexToWorld(point, point); pfImageGeometry3D->WorldToIndex(point, point); point[i0] += 0.5; point[i1] += 0.5; index[0] = point[0]; index[1] = point[1]; index[2] = point[2]; if (pfImageGeometry3D->IsIndexInside(index)) m_PlanarFigureImage->SetPixel(index, 1); } ++imageIterator; } // Clean up VTK objects polyline->Delete(); extrudeFilter->Delete(); polyDataToImageStencil->Delete(); vtkImporter->Delete(); imageStencilFilter->Delete(); //vtkExporter->Delete(); // TODO: crashes when outcommented; memory leak?? delete[] ptIds; } void QmitkFiberProcessingView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkFiberProcessingView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } /* OnSelectionChanged is registered to SelectionService, therefore no need to implement SelectionService Listener explicitly */ void QmitkFiberProcessingView::UpdateGui() { // are fiber bundles selected? if ( m_SelectedFB.empty() ) { m_Controls->m_JoinBundles->setEnabled(false); m_Controls->m_SubstractBundles->setEnabled(false); m_Controls->m_ProcessFiberBundleButton->setEnabled(false); m_Controls->doExtractFibersButton->setEnabled(false); m_Controls->m_Extract3dButton->setEnabled(false); m_Controls->m_ResampleFibersButton->setEnabled(false); m_Controls->m_PlanarFigureButtonsFrame->setEnabled(false); m_Controls->m_FaColorFibersButton->setEnabled(false); + m_Controls->m_PruneFibersButton->setEnabled(false); + m_Controls->m_MirrorFibersButton->setEnabled(false); } else { m_Controls->m_PlanarFigureButtonsFrame->setEnabled(true); m_Controls->m_ProcessFiberBundleButton->setEnabled(true); m_Controls->m_ResampleFibersButton->setEnabled(true); + m_Controls->m_PruneFibersButton->setEnabled(true); + m_Controls->m_MirrorFibersButton->setEnabled(true); if (m_Surfaces.size()>0) m_Controls->m_Extract3dButton->setEnabled(true); // one bundle and one planar figure needed to extract fibers if (!m_SelectedPF.empty()) m_Controls->doExtractFibersButton->setEnabled(true); // more than two bundles needed to join/subtract if (m_SelectedFB.size() > 1) { m_Controls->m_JoinBundles->setEnabled(true); m_Controls->m_SubstractBundles->setEnabled(true); } else { m_Controls->m_JoinBundles->setEnabled(false); m_Controls->m_SubstractBundles->setEnabled(false); } if (m_SelectedImage.IsNotNull()) m_Controls->m_FaColorFibersButton->setEnabled(true); } // are planar figures selected? if ( m_SelectedPF.empty() ) { m_Controls->doExtractFibersButton->setEnabled(false); m_Controls->PFCompoANDButton->setEnabled(false); m_Controls->PFCompoORButton->setEnabled(false); m_Controls->PFCompoNOTButton->setEnabled(false); m_Controls->m_GenerateRoiImage->setEnabled(false); } else { if ( !m_SelectedFB.empty() ) m_Controls->m_GenerateRoiImage->setEnabled(true); else m_Controls->m_GenerateRoiImage->setEnabled(false); if (m_SelectedPF.size() > 1) { m_Controls->PFCompoANDButton->setEnabled(true); m_Controls->PFCompoORButton->setEnabled(true); m_Controls->PFCompoNOTButton->setEnabled(false); } else { m_Controls->PFCompoANDButton->setEnabled(false); m_Controls->PFCompoORButton->setEnabled(false); m_Controls->PFCompoNOTButton->setEnabled(true); } } } void QmitkFiberProcessingView::OnSelectionChanged( std::vector<mitk::DataNode*> nodes ) { if ( !this->IsVisible() ) return; //reset existing Vectors containing FiberBundles and PlanarFigures from a previous selection m_SelectedFB.clear(); m_SelectedPF.clear(); m_Surfaces.clear(); m_SelectedImage = NULL; for( std::vector<mitk::DataNode*>::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if ( dynamic_cast<mitk::FiberBundleX*>(node->GetData()) ) m_SelectedFB.push_back(node); else if (dynamic_cast<mitk::PlanarFigure*>(node->GetData())) m_SelectedPF.push_back(node); else if (dynamic_cast<mitk::Image*>(node->GetData())) m_SelectedImage = dynamic_cast<mitk::Image*>(node->GetData()); else if (dynamic_cast<mitk::Surface*>(node->GetData())) m_Surfaces.push_back(dynamic_cast<mitk::Surface*>(node->GetData())); } UpdateGui(); GenerateStats(); } void QmitkFiberProcessingView::OnDrawPolygon() { // bool checked = m_Controls->m_PolygonButton->isChecked(); // if(!this->AssertDrawingIsPossible(checked)) // return; mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New(); figure->ClosedOn(); this->AddFigureToDataStorage(figure, QString("Polygon%1").arg(++m_PolygonCounter)); MITK_INFO << "PlanarPolygon created ..."; mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDefaultDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; mitk::PlanarFigure* figureP = 0; for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast<mitk::DataNode*>(it->Value().GetPointer()); figureP = dynamic_cast<mitk::PlanarFigure*>(node->GetData()); if(figureP) { figureInteractor = dynamic_cast<mitk::PlanarFigureInteractor*>(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); } } } void QmitkFiberProcessingView::OnDrawCircle() { //bool checked = m_Controls->m_CircleButton->isChecked(); //if(!this->AssertDrawingIsPossible(checked)) // return; mitk::PlanarCircle::Pointer figure = mitk::PlanarCircle::New(); this->AddFigureToDataStorage(figure, QString("Circle%1").arg(++m_EllipseCounter)); this->GetDataStorage()->Modified(); MITK_INFO << "PlanarCircle created ..."; //call mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDefaultDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; mitk::PlanarFigure* figureP = 0; for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast<mitk::DataNode*>(it->Value().GetPointer()); figureP = dynamic_cast<mitk::PlanarFigure*>(node->GetData()); if(figureP) { figureInteractor = dynamic_cast<mitk::PlanarFigureInteractor*>(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); } } } void QmitkFiberProcessingView::Activated() { MITK_INFO << "FB OPerations ACTIVATED()"; /* mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = this->GetDefaultDataStorage()->GetAll(); mitk::DataNode* node = 0; mitk::PlanarFigureInteractor::Pointer figureInteractor = 0; mitk::PlanarFigure* figure = 0; for(mitk::DataStorage::SetOfObjects::ConstIterator it=_NodeSet->Begin(); it!=_NodeSet->End() ; it++) { node = const_cast<mitk::DataNode*>(it->Value().GetPointer()); figure = dynamic_cast<mitk::PlanarFigure*>(node->GetData()); if(figure) { figureInteractor = dynamic_cast<mitk::PlanarFigureInteractor*>(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); } } */ } void QmitkFiberProcessingView::AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey, mitk::BaseProperty *property ) { // initialize figure's geometry with empty geometry mitk::PlaneGeometry::Pointer emptygeometry = mitk::PlaneGeometry::New(); figure->SetGeometry2D( emptygeometry ); //set desired data to DataNode where Planarfigure is stored mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName(name.toStdString()); newNode->SetData(figure); newNode->AddProperty( "planarfigure.default.line.color", mitk::ColorProperty::New(1.0,0.0,0.0)); newNode->AddProperty( "planarfigure.line.width", mitk::FloatProperty::New(2.0)); newNode->AddProperty( "planarfigure.drawshadow", mitk::BoolProperty::New(true)); newNode->AddProperty( "selected", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.ishovering", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.drawoutline", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.drawquantities", mitk::BoolProperty::New(false) ); newNode->AddProperty( "planarfigure.drawshadow", mitk::BoolProperty::New(true) ); newNode->AddProperty( "planarfigure.line.width", mitk::FloatProperty::New(3.0) ); newNode->AddProperty( "planarfigure.shadow.widthmodifier", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.outline.width", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.helperline.width", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.line.color", mitk::ColorProperty::New(1.0,1.0,1.0) ); newNode->AddProperty( "planarfigure.default.line.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.default.outline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.default.helperline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.markerline.color", mitk::ColorProperty::New(0.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.default.markerline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.default.marker.color", mitk::ColorProperty::New(1.0,1.0,1.0) ); newNode->AddProperty( "planarfigure.default.marker.opacity",mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.line.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.line.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.outline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.helperline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.markerline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.markerline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.hover.marker.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.hover.marker.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.line.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.line.opacity",mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.outline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.outline.opacity", mitk::FloatProperty::New(2.0)); newNode->AddProperty( "planarfigure.selected.helperline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.helperline.opacity",mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.markerline.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.markerline.opacity", mitk::FloatProperty::New(2.0) ); newNode->AddProperty( "planarfigure.selected.marker.color", mitk::ColorProperty::New(1.0,0.0,0.0) ); newNode->AddProperty( "planarfigure.selected.marker.opacity",mitk::FloatProperty::New(2.0)); // figure drawn on the topmost layer / image newNode->SetColor(1.0,1.0,1.0); newNode->SetOpacity(0.8); GetDataStorage()->Add(newNode ); std::vector<mitk::DataNode*> selectedNodes = GetDataManagerSelection(); for(unsigned int i = 0; i < selectedNodes.size(); i++) { selectedNodes[i]->SetSelected(false); } newNode->SetSelected(true); } void QmitkFiberProcessingView::DoFiberExtraction() { if ( m_SelectedFB.empty() ){ QMessageBox::information( NULL, "Warning", "No fibe bundle selected!"); MITK_WARN("QmitkFiberProcessingView") << "no fibe bundle selected"; return; } for (int i=0; i<m_SelectedFB.size(); i++) { mitk::FiberBundleX::Pointer fib = dynamic_cast<mitk::FiberBundleX*>(m_SelectedFB.at(i)->GetData()); mitk::PlanarFigure::Pointer roi = dynamic_cast<mitk::PlanarFigure*> (m_SelectedPF.at(0)->GetData()); mitk::FiberBundleX::Pointer extFB = fib->ExtractFiberSubset(roi); if (extFB->GetNumFibers()<=0) continue; mitk::DataNode::Pointer node; node = mitk::DataNode::New(); node->SetData(extFB); QString name(m_SelectedFB.at(i)->GetName().c_str()); name += "_"; name += m_SelectedPF.at(0)->GetName().c_str(); node->SetName(name.toStdString()); GetDataStorage()->Add(node); m_SelectedFB.at(i)->SetVisibility(false); } } void QmitkFiberProcessingView::GenerateAndComposite() { mitk::PlanarFigureComposite::Pointer PFCAnd = mitk::PlanarFigureComposite::New(); mitk::PlaneGeometry* currentGeometry2D = dynamic_cast<mitk::PlaneGeometry*>( const_cast<mitk::Geometry2D*>(GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D())); PFCAnd->SetGeometry2D(currentGeometry2D); PFCAnd->setOperationType(mitk::PFCOMPOSITION_AND_OPERATION); for( std::vector<mitk::DataNode::Pointer>::iterator it = m_SelectedPF.begin(); it != m_SelectedPF.end(); ++it ) { mitk::DataNode::Pointer nodePF = *it; mitk::PlanarFigure::Pointer tmpPF = dynamic_cast<mitk::PlanarFigure*>( nodePF->GetData() ); PFCAnd->addPlanarFigure( tmpPF ); PFCAnd->addDataNode( nodePF ); PFCAnd->setDisplayName("AND_COMPO"); } AddCompositeToDatastorage(PFCAnd, NULL); } void QmitkFiberProcessingView::GenerateOrComposite() { mitk::PlanarFigureComposite::Pointer PFCOr = mitk::PlanarFigureComposite::New(); mitk::PlaneGeometry* currentGeometry2D = dynamic_cast<mitk::PlaneGeometry*>( const_cast<mitk::Geometry2D*>(GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D())); PFCOr->SetGeometry2D(currentGeometry2D); PFCOr->setOperationType(mitk::PFCOMPOSITION_OR_OPERATION); for( std::vector<mitk::DataNode::Pointer>::iterator it = m_SelectedPF.begin(); it != m_SelectedPF.end(); ++it ) { mitk::DataNode::Pointer nodePF = *it; mitk::PlanarFigure::Pointer tmpPF = dynamic_cast<mitk::PlanarFigure*>( nodePF->GetData() ); PFCOr->addPlanarFigure( tmpPF ); PFCOr->addDataNode( nodePF ); PFCOr->setDisplayName("OR_COMPO"); } AddCompositeToDatastorage(PFCOr, NULL); } void QmitkFiberProcessingView::GenerateNotComposite() { mitk::PlanarFigureComposite::Pointer PFCNot = mitk::PlanarFigureComposite::New(); mitk::PlaneGeometry* currentGeometry2D = dynamic_cast<mitk::PlaneGeometry*>( const_cast<mitk::Geometry2D*>(GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetCurrentWorldGeometry2D())); PFCNot->SetGeometry2D(currentGeometry2D); PFCNot->setOperationType(mitk::PFCOMPOSITION_NOT_OPERATION); for( std::vector<mitk::DataNode::Pointer>::iterator it = m_SelectedPF.begin(); it != m_SelectedPF.end(); ++it ) { mitk::DataNode::Pointer nodePF = *it; mitk::PlanarFigure::Pointer tmpPF = dynamic_cast<mitk::PlanarFigure*>( nodePF->GetData() ); PFCNot->addPlanarFigure( tmpPF ); PFCNot->addDataNode( nodePF ); PFCNot->setDisplayName("NOT_COMPO"); } AddCompositeToDatastorage(PFCNot, NULL); } /* CLEANUP NEEDED */ void QmitkFiberProcessingView::AddCompositeToDatastorage(mitk::PlanarFigureComposite::Pointer pfcomp, mitk::DataNode::Pointer parentDataNode ) { mitk::DataNode::Pointer newPFCNode; newPFCNode = mitk::DataNode::New(); newPFCNode->SetName( pfcomp->getDisplayName() ); newPFCNode->SetData(pfcomp); newPFCNode->SetVisibility(true); switch (pfcomp->getOperationType()) { case 0: { if (!parentDataNode.IsNull()) { GetDataStorage()->Add(newPFCNode, parentDataNode); } else { GetDataStorage()->Add(newPFCNode); } //iterate through its childs for(int i=0; i<pfcomp->getNumberOfChildren(); ++i) { mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast<mitk::PlanarFigureComposite*>(tmpPFchild.GetPointer()); if ( !pfcompcast.IsNull() ) { // child is of type planar Figure composite // make new node of the child, cuz later the child has to be removed of its old position in datamanager // feed new dataNode with information of the savedDataNode, which is gonna be removed soon mitk::DataNode::Pointer newChildPFCNode; newChildPFCNode = mitk::DataNode::New(); newChildPFCNode->SetData(tmpPFchild); newChildPFCNode->SetName( savedPFchildNode->GetName() ); pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user //update inside vector the dataNodePointer pfcomp->replaceDataNodeAt(i, newChildPFCNode); AddCompositeToDatastorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager // without having its parent anymore //GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } } else { // child is not of type PlanarFigureComposite, so its one of the planarFigures // create new dataNode containing the data of the old dataNode, but position in dataManager will be // modified cuz we re setting a (new) parent. mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); newPFchildNode->SetName(savedPFchildNode->GetName() ); newPFchildNode->SetData(tmpPFchild); newPFchildNode->SetVisibility(true); // replace the dataNode in PFComp DataNodeVector pfcomp->replaceDataNodeAt(i, newPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; } else { MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } MITK_INFO << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); //add new child to datamanager with its new position as child of newPFCNode parent GetDataStorage()->Add(newPFchildNode, newPFCNode); } } GetDataStorage()->Modified(); break; } case 1: { if (!parentDataNode.IsNull()) { MITK_INFO << "adding " << newPFCNode->GetName() << " to " << parentDataNode->GetName() ; GetDataStorage()->Add(newPFCNode, parentDataNode); } else { MITK_INFO << "adding " << newPFCNode->GetName(); GetDataStorage()->Add(newPFCNode); } for(int i=0; i<pfcomp->getNumberOfChildren(); ++i) { mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast<mitk::PlanarFigureComposite*>(tmpPFchild.GetPointer()); if ( !pfcompcast.IsNull() ) { // child is of type planar Figure composite // make new node of the child, cuz later the child has to be removed of its old position in datamanager // feed new dataNode with information of the savedDataNode, which is gonna be removed soon mitk::DataNode::Pointer newChildPFCNode; newChildPFCNode = mitk::DataNode::New(); newChildPFCNode->SetData(tmpPFchild); newChildPFCNode->SetName( savedPFchildNode->GetName() ); pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user //update inside vector the dataNodePointer pfcomp->replaceDataNodeAt(i, newChildPFCNode); AddCompositeToDatastorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager // without having its parent anymore //GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } } else { // child is not of type PlanarFigureComposite, so its one of the planarFigures // create new dataNode containing the data of the old dataNode, but position in dataManager will be // modified cuz we re setting a (new) parent. mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); newPFchildNode->SetName(savedPFchildNode->GetName() ); newPFchildNode->SetData(tmpPFchild); newPFchildNode->SetVisibility(true); // replace the dataNode in PFComp DataNodeVector pfcomp->replaceDataNodeAt(i, newPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } MITK_INFO << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); //add new child to datamanager with its new position as child of newPFCNode parent GetDataStorage()->Add(newPFchildNode, newPFCNode); } } GetDataStorage()->Modified(); break; } case 2: { if (!parentDataNode.IsNull()) { MITK_INFO << "adding " << newPFCNode->GetName() << " to " << parentDataNode->GetName() ; GetDataStorage()->Add(newPFCNode, parentDataNode); } else { MITK_INFO << "adding " << newPFCNode->GetName(); GetDataStorage()->Add(newPFCNode); } //iterate through its childs for(int i=0; i<pfcomp->getNumberOfChildren(); ++i) { mitk::PlanarFigure::Pointer tmpPFchild = pfcomp->getChildAt(i); mitk::DataNode::Pointer savedPFchildNode = pfcomp->getDataNodeAt(i); mitk::PlanarFigureComposite::Pointer pfcompcast= dynamic_cast<mitk::PlanarFigureComposite*>(tmpPFchild.GetPointer()); if ( !pfcompcast.IsNull() ) { // child is of type planar Figure composite // makeRemoveBundle new node of the child, cuz later the child has to be removed of its old position in datamanager // feed new dataNode with information of the savedDataNode, which is gonna be removed soon mitk::DataNode::Pointer newChildPFCNode; newChildPFCNode = mitk::DataNode::New(); newChildPFCNode->SetData(tmpPFchild); newChildPFCNode->SetName( savedPFchildNode->GetName() ); pfcompcast->setDisplayName( savedPFchildNode->GetName() ); //name might be changed in DataManager by user //update inside vector the dataNodePointer pfcomp->replaceDataNodeAt(i, newChildPFCNode); AddCompositeToDatastorage(pfcompcast, newPFCNode); //the current PFCNode becomes the childs parent // remove savedNode here, cuz otherwise its children will change their position in the dataNodeManager // without having its parent anymore //GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } } else { // child is not of type PlanarFigureComposite, so its one of the planarFigures // create new dataNode containing the data of the old dataNode, but position in dataManager will be // modified cuz we re setting a (new) parent. mitk::DataNode::Pointer newPFchildNode = mitk::DataNode::New(); newPFchildNode->SetName(savedPFchildNode->GetName() ); newPFchildNode->SetData(tmpPFchild); newPFchildNode->SetVisibility(true); // replace the dataNode in PFComp DataNodeVector pfcomp->replaceDataNodeAt(i, newPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " exists in DS...trying to remove it"; }else{ MITK_INFO << "[ERROR] does NOT exist, but can I read its Name? " << savedPFchildNode->GetName(); } // remove old child position in dataStorage GetDataStorage()->Remove(savedPFchildNode); if ( GetDataStorage()->Exists(savedPFchildNode)) { MITK_INFO << savedPFchildNode->GetName() << " still exists"; } MITK_INFO << "adding " << newPFchildNode->GetName() << " to " << newPFCNode->GetName(); //add new child to datamanager with its new position as child of newPFCNode parent GetDataStorage()->Add(newPFchildNode, newPFCNode); } } GetDataStorage()->Modified(); break; } default: MITK_INFO << "we have an UNDEFINED composition... ERROR" ; break; } } void QmitkFiberProcessingView::JoinBundles() { if ( m_SelectedFB.size()<2 ){ QMessageBox::information( NULL, "Warning", "Select at least two fiber bundles!"); MITK_WARN("QmitkFiberProcessingView") << "Select at least two fiber bundles!"; return; } std::vector<mitk::DataNode::Pointer>::const_iterator it = m_SelectedFB.begin(); mitk::FiberBundleX::Pointer newBundle = dynamic_cast<mitk::FiberBundleX*>((*it)->GetData()); QString name(""); name += QString((*it)->GetName().c_str()); ++it; for (it; it!=m_SelectedFB.end(); ++it) { newBundle = newBundle->AddBundle(dynamic_cast<mitk::FiberBundleX*>((*it)->GetData())); name += "+"+QString((*it)->GetName().c_str()); } mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); } void QmitkFiberProcessingView::SubstractBundles() { if ( m_SelectedFB.size()<2 ){ QMessageBox::information( NULL, "Warning", "Select at least two fiber bundles!"); MITK_WARN("QmitkFiberProcessingView") << "Select at least two fiber bundles!"; return; } std::vector<mitk::DataNode::Pointer>::const_iterator it = m_SelectedFB.begin(); mitk::FiberBundleX::Pointer newBundle = dynamic_cast<mitk::FiberBundleX*>((*it)->GetData()); QString name(""); name += QString((*it)->GetName().c_str()); ++it; for (it; it!=m_SelectedFB.end(); ++it) { newBundle = newBundle->SubtractBundle(dynamic_cast<mitk::FiberBundleX*>((*it)->GetData())); if (newBundle.IsNull()) break; name += "-"+QString((*it)->GetName().c_str()); } if (newBundle.IsNull()) { QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers. Did you select the fiber bundles in the correct order? X-Y is not equal to Y-X!"); return; } mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); } +void QmitkFiberProcessingView::PruneBundle() +{ + int minLength = this->m_Controls->m_PruneFibersSpinBox->value(); + bool doneSomething = false; + for (int i=0; i<m_SelectedFB.size(); i++) + { + mitk::FiberBundleX::Pointer fib = dynamic_cast<mitk::FiberBundleX*>(m_SelectedFB.at(i)->GetData()); + if (!fib->RemoveShortFibers(minLength)) + QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); + else + doneSomething = true; + } + + if (doneSomething) + { + GenerateStats(); + RenderingManager::GetInstance()->RequestUpdateAll(); + } +} + void QmitkFiberProcessingView::GenerateStats() { if ( m_SelectedFB.empty() ) return; QString stats(""); for( int i=0; i<m_SelectedFB.size(); i++ ) { mitk::DataNode::Pointer node = m_SelectedFB[i]; if (node.IsNotNull() && dynamic_cast<mitk::FiberBundleX*>(node->GetData())) { if (i>0) stats += "\n-----------------------------\n"; stats += QString(node->GetName().c_str()) + "\n"; mitk::FiberBundleX::Pointer fib = dynamic_cast<mitk::FiberBundleX*>(node->GetData()); vtkSmartPointer<vtkPolyData> fiberPolyData = fib->GetFiberPolyData(); vtkSmartPointer<vtkCellArray> vLines = fiberPolyData->GetLines(); vLines->InitTraversal(); int numberOfLines = vLines->GetNumberOfCells(); stats += "Number of fibers: "+ QString::number(numberOfLines) + "\n"; float length = 0; std::vector<float> lengths; for (int i=0; i<numberOfLines; i++) { vtkIdType numPoints(0); vtkIdType* points(NULL); vLines->GetNextCell ( numPoints, points ); float l=0; for (unsigned int j=0; j<numPoints-1; j++) { itk::Point<double> p1; itk::Point<double> p2; fiberPolyData->GetPoint(points[j], p1.GetDataPointer()); fiberPolyData->GetPoint(points[j+1], p2.GetDataPointer()); float dist = p1.EuclideanDistanceTo(p2); length += dist; l += dist; } itk::Point<double> p2; fiberPolyData->GetPoint(points[numPoints-1], p2.GetDataPointer()); lengths.push_back(l); } std::sort(lengths.begin(), lengths.end()); if (numberOfLines>0) length /= numberOfLines; float dev=0; int count = 0; vLines->InitTraversal(); for (int i=0; i<numberOfLines; i++) { vtkIdType numPoints(0); vtkIdType* points(NULL); vLines->GetNextCell ( numPoints, points ); float l=0; for (unsigned int j=0; j<numPoints-1; j++) { itk::Point<double> p1; itk::Point<double> p2; fiberPolyData->GetPoint(points[j], p1.GetDataPointer()); fiberPolyData->GetPoint(points[j+1], p2.GetDataPointer()); float dist = p1.EuclideanDistanceTo(p2); l += dist; } dev += (length-l)*(length-l); count++; } if (numberOfLines>1) dev /= (numberOfLines-1); else dev = 0; stats += "Min. length: "+ QString::number(lengths.front(),'f',1) + " mm\n"; stats += "Max. length: "+ QString::number(lengths.back(),'f',1) + " mm\n"; stats += "Mean length: "+ QString::number(length,'f',1) + " mm\n"; stats += "Median length: "+ QString::number(lengths.at(lengths.size()/2),'f',1) + " mm\n"; stats += "Standard deviation: "+ QString::number(sqrt(dev),'f',1) + " mm\n"; } } this->m_Controls->m_StatsTextEdit->setText(stats); } void QmitkFiberProcessingView::ProcessSelectedBundles() { if ( m_SelectedFB.empty() ){ QMessageBox::information( NULL, "Warning", "No fibe bundle selected!"); MITK_WARN("QmitkFiberProcessingView") << "no fibe bundle selected"; return; } int generationMethod = m_Controls->m_GenerationBox->currentIndex(); for( int i=0; i<m_SelectedFB.size(); i++ ) { mitk::DataNode::Pointer node = m_SelectedFB[i]; if (node.IsNotNull() && dynamic_cast<mitk::FiberBundleX*>(node->GetData())) { mitk::FiberBundleX::Pointer fib = dynamic_cast<mitk::FiberBundleX*>(node->GetData()); QString name(node->GetName().c_str()); DataNode::Pointer newNode = NULL; switch(generationMethod){ case 0: newNode = GenerateTractDensityImage(fib, false); name += "_TDI"; break; case 1: newNode = GenerateTractDensityImage(fib, true); name += "_envelope"; break; case 2: newNode = GenerateColorHeatmap(fib); break; case 3: newNode = GenerateFiberEndingsImage(fib); name += "_fiber_endings"; break; case 4: newNode = GenerateFiberEndingsPointSet(fib); name += "_fiber_endings"; break; } if (newNode.IsNotNull()) { newNode->SetName(name.toStdString()); GetDataStorage()->Add(newNode); } } } } // generate pointset displaying the fiber endings mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateFiberEndingsPointSet(mitk::FiberBundleX::Pointer fib) { mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); vtkSmartPointer<vtkPolyData> fiberPolyData = fib->GetFiberPolyData(); vtkSmartPointer<vtkCellArray> vLines = fiberPolyData->GetLines(); vLines->InitTraversal(); int count = 0; int numFibers = fib->GetNumFibers(); for( int i=0; i<numFibers; i++ ) { vtkIdType numPoints(0); vtkIdType* points(NULL); vLines->GetNextCell ( numPoints, points ); if (numPoints>0) { double* point = fiberPolyData->GetPoint(points[0]); itk::Point<float,3> itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } if (numPoints>2) { double* point = fiberPolyData->GetPoint(points[numPoints-1]); itk::Point<float,3> itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } } mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( pointSet ); return node; } // generate image displaying the fiber endings mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateFiberEndingsImage(mitk::FiberBundleX::Pointer fib) { typedef unsigned char OutPixType; typedef itk::Image<OutPixType,3> OutImageType; typedef itk::TractsToFiberEndingsImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetInvertImage(m_Controls->m_InvertCheckbox->isChecked()); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image OutImageType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } // generate rgba heatmap from fiber bundle mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateColorHeatmap(mitk::FiberBundleX::Pointer fib) { typedef itk::RGBAPixel<unsigned char> OutPixType; typedef itk::Image<OutPixType, 3> OutImageType; typedef itk::TractsToRgbaImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { itk::Image<unsigned char, 3>::Pointer itkImage = itk::Image<unsigned char, 3>::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image<OutPixType,3> OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } // generate tract density image from fiber bundle mitk::DataNode::Pointer QmitkFiberProcessingView::GenerateTractDensityImage(mitk::FiberBundleX::Pointer fib, bool binary) { typedef float OutPixType; typedef itk::Image<OutPixType, 3> OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetInvertImage(m_Controls->m_InvertCheckbox->isChecked()); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image<OutPixType,3> OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } void QmitkFiberProcessingView::ResampleSelectedBundles() { int factor = this->m_Controls->m_ResampleFibersSpinBox->value(); for (int i=0; i<m_SelectedFB.size(); i++) { mitk::FiberBundleX::Pointer fib = dynamic_cast<mitk::FiberBundleX*>(m_SelectedFB.at(i)->GetData()); fib->DoFiberSmoothing(factor); } + GenerateStats(); + RenderingManager::GetInstance()->RequestUpdateAll(); +} + +void QmitkFiberProcessingView::MirrorFibers() +{ + unsigned int axis = this->m_Controls->m_AxisSelectionBox->currentIndex(); + for (int i=0; i<m_SelectedFB.size(); i++) + { + mitk::FiberBundleX::Pointer fib = dynamic_cast<mitk::FiberBundleX*>(m_SelectedFB.at(i)->GetData()); + fib->MirrorFibers(axis); + } + GenerateStats(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::DoFaColorCoding() { if (m_SelectedImage.IsNull()) return; -// mitk::PixelType pType = mitk::MakeScalarPixelType<float>(); -// if (m_SelectedImage->GetPixelType()!=pType) -// { -// //mitk::Image bla; bla.GetPixelType().GetNameOfClass() -// MITK_INFO << m_SelectedImage->GetPixelType().GetNameOfClass(); -// QMessageBox::warning(NULL, "Wrong Image Type", "FA/GFA image should be of type float"); -//// return; -// } for( int i=0; i<m_SelectedFB.size(); i++ ) { mitk::FiberBundleX::Pointer fib = dynamic_cast<mitk::FiberBundleX*>(m_SelectedFB.at(i)->GetData()); fib->SetFAMap(m_SelectedImage); fib->SetColorCoding(mitk::FiberBundleX::COLORCODING_FA_BASED); fib->DoColorCodingFaBased(); } if(m_MultiWidget) m_MultiWidget->RequestUpdate(); } - diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h index c1f606e896..db1daf65c2 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h @@ -1,197 +1,199 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) -Copyright (c) German Cancer Research Center, +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 +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 QmitkFiberProcessingView_h #define QmitkFiberProcessingView_h #include <QmitkFunctionality.h> #include "ui_QmitkFiberProcessingViewControls.h" #include <mitkDataStorage.h> #include <mitkDataStorageSelection.h> #include <mitkPlanarFigure.h> #include <mitkPlanarFigureComposite.h> #include <mitkFiberBundleX.h> #include <mitkDataNode.h> #include <mitkSurface.h> #include <itkImage.h> #include <itkCastImageFilter.h> #include <itkVTKImageImport.h> #include <itkVTKImageExport.h> #include <itkRegionOfInterestImageFilter.h> #include <vtkLinearExtrusionFilter.h> #include <vtkPolyDataToImageStencil.h> #include <vtkSelectEnclosedPoints.h> #include <vtkImageImport.h> #include <vtkImageExport.h> #include <vtkImageStencil.h> #include <vtkSmartPointer.h> #include <vtkSelection.h> #include <vtkSelectionNode.h> #include <vtkExtractSelectedThresholds.h> #include <vtkFloatArray.h> #include <mitkUnstructuredGrid.h> #include <vtkXMLUnstructuredGridWriter.h> #include <itkTimeProbe.h> +#include <itkStreamlineTrackingFilter.h> /*! \brief QmitkFiberProcessingView \warning View to process fiber bundles. Supplies methods to extract fibers from the bundle, join and subtract bundles, generate images from the selected bundle and much more. \sa QmitkFunctionality \ingroup Functionalities */ class QmitkFiberProcessingView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: typedef itk::Image< unsigned char, 3 > itkUCharImageType; typedef itk::Image< float, 3 > itkFloatImageType; static const std::string VIEW_ID; QmitkFiberProcessingView(); virtual ~QmitkFiberProcessingView(); virtual void CreateQtPartControl(QWidget *parent); virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); virtual void StdMultiWidgetNotAvailable(); virtual void Activated(); protected slots: void OnDrawCircle(); void OnDrawPolygon(); void DoFiberExtraction(); void GenerateAndComposite(); void GenerateOrComposite(); void GenerateNotComposite(); - + void PruneBundle(); + void MirrorFibers(); void JoinBundles(); void SubstractBundles(); void GenerateRoiImage(); void ProcessSelectedBundles(); void ResampleSelectedBundles(); void DoFaColorCoding(); void Extract3d(); virtual void AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey = NULL, mitk::BaseProperty *property = NULL ); protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( std::vector<mitk::DataNode*> nodes ); Ui::QmitkFiberProcessingViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; /** Connection from VTK to ITK */ template <typename VTK_Exporter, typename ITK_Importer> void ConnectPipelines(VTK_Exporter* exporter, ITK_Importer importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template <typename ITK_Exporter, typename VTK_Importer> void ConnectPipelines(ITK_Exporter exporter, VTK_Importer* importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template < typename TPixel, unsigned int VImageDimension > void InternalCalculateMaskFromPlanarFigure( itk::Image< TPixel, VImageDimension > *image, unsigned int axis, std::string nodeName ); template < typename TPixel, unsigned int VImageDimension > void InternalReorientImagePlane( const itk::Image< TPixel, VImageDimension > *image, mitk::Geometry3D* planegeo3D, int additionalIndex ); void GenerateStats(); void UpdateGui(); berry::ISelectionListener::Pointer m_SelListener; berry::IStructuredSelection::ConstPointer m_CurrentSelection; private: int m_EllipseCounter; int m_PolygonCounter; //contains the selected FiberBundles std::vector<mitk::DataNode::Pointer> m_SelectedFB; //contains the selected PlanarFigures std::vector<mitk::DataNode::Pointer> m_SelectedPF; mitk::Image::Pointer m_SelectedImage; mitk::Image::Pointer m_InternalImage; mitk::PlanarFigure::Pointer m_PlanarFigure; float m_UpsamplingFactor; itkUCharImageType::Pointer m_InternalImageMask3D; itkUCharImageType::Pointer m_PlanarFigureImage; std::vector<mitk::Surface::Pointer> m_Surfaces; void AddCompositeToDatastorage(mitk::PlanarFigureComposite::Pointer, mitk::DataNode::Pointer); void debugPFComposition(mitk::PlanarFigureComposite::Pointer , int ); void CompositeExtraction(mitk::DataNode::Pointer node, mitk::Image* image); mitk::DataNode::Pointer GenerateTractDensityImage(mitk::FiberBundleX::Pointer fib, bool binary); mitk::DataNode::Pointer GenerateColorHeatmap(mitk::FiberBundleX::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsImage(mitk::FiberBundleX::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsPointSet(mitk::FiberBundleX::Pointer fib); }; #endif // _QMITKFIBERTRACKINGVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui index e907ff8063..34374ce3c9 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui @@ -1,683 +1,790 @@ <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>QmitkFiberProcessingViewControls</class> <widget class="QWidget" name="QmitkFiberProcessingViewControls"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>665</width> - <height>587</height> + <height>671</height> </rect> </property> <property name="windowTitle"> <string>Form</string> </property> <layout class="QVBoxLayout" name="verticalLayout"> <property name="spacing"> <number>0</number> </property> <property name="leftMargin"> <number>9</number> </property> <property name="topMargin"> <number>3</number> </property> <property name="rightMargin"> <number>9</number> </property> <property name="bottomMargin"> <number>3</number> </property> <item> <widget class="QGroupBox" name="groupBox"> <property name="title"> <string>Fiber Bundle Modification</string> </property> <layout class="QGridLayout" name="gridLayout_4"> <item row="0" column="0"> <widget class="QFrame" name="m_PlanarFigureButtonsFrame"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> <width>200</width> <height>0</height> </size> </property> <property name="maximumSize"> <size> <width>16777215</width> <height>60</height> </size> </property> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> <layout class="QGridLayout" name="gridLayout"> <property name="margin"> <number>0</number> </property> <item row="0" column="0"> <widget class="QPushButton" name="m_CircleButton"> <property name="maximumSize"> <size> <width>30</width> <height>30</height> </size> </property> <property name="toolTip"> <string>Draw circular ROI. Select reference fiber bundle to execute.</string> </property> <property name="text"> <string/> </property> <property name="icon"> <iconset resource="../../resources/QmitkDiffusionImaging.qrc"> <normaloff>:/QmitkDiffusionImaging/circle.png</normaloff>:/QmitkDiffusionImaging/circle.png</iconset> </property> <property name="iconSize"> <size> <width>32</width> <height>32</height> </size> </property> <property name="checkable"> <bool>false</bool> </property> <property name="flat"> <bool>true</bool> </property> </widget> </item> <item row="0" column="1"> <widget class="QPushButton" name="m_RectangleButton"> <property name="maximumSize"> <size> <width>30</width> <height>30</height> </size> </property> <property name="toolTip"> <string>Draw rectangular ROI. Select reference fiber bundle to execute.</string> </property> <property name="text"> <string/> </property> <property name="icon"> <iconset resource="../../resources/QmitkDiffusionImaging.qrc"> <normaloff>:/QmitkDiffusionImaging/rectangle.png</normaloff>:/QmitkDiffusionImaging/rectangle.png</iconset> </property> <property name="iconSize"> <size> <width>32</width> <height>32</height> </size> </property> <property name="checkable"> <bool>true</bool> </property> <property name="flat"> <bool>true</bool> </property> </widget> </item> <item row="0" column="2"> <widget class="QPushButton" name="m_PolygonButton"> <property name="maximumSize"> <size> <width>30</width> <height>30</height> </size> </property> <property name="toolTip"> <string>Draw polygonal ROI. Select reference fiber bundle to execute.</string> </property> <property name="text"> <string/> </property> <property name="icon"> <iconset resource="../../resources/QmitkDiffusionImaging.qrc"> <normaloff>:/QmitkDiffusionImaging/polygon.png</normaloff>:/QmitkDiffusionImaging/polygon.png</iconset> </property> <property name="iconSize"> <size> <width>32</width> <height>32</height> </size> </property> <property name="checkable"> <bool>true</bool> </property> <property name="flat"> <bool>true</bool> </property> </widget> </item> <item row="0" column="3"> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> </layout> </widget> </item> <item row="2" column="0"> <widget class="QFrame" name="frame_2"> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> <layout class="QGridLayout" name="gridLayout_3"> <property name="margin"> <number>0</number> </property> <item row="0" column="0"> <widget class="QCommandLinkButton" name="doExtractFibersButton"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>200</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Extract fibers passing through selected ROI or composite ROI. Select ROI and fiber bundle to execute.</string> </property> <property name="text"> <string>Extract</string> </property> </widget> </item> <item row="1" column="0"> <widget class="QCommandLinkButton" name="m_SubstractBundles"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>200</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Returns all fibers contained in bundle X that are not contained in bundle Y (not commutative!). Select at least two fiber bundles to execute.</string> </property> <property name="text"> <string>Substract</string> </property> </widget> </item> <item row="1" column="1"> <widget class="QCommandLinkButton" name="m_JoinBundles"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>200</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Merge selected fiber bundles. Select at least two fiber bundles to execute.</string> </property> <property name="text"> <string>Join</string> </property> </widget> </item> <item row="0" column="2"> <spacer name="horizontalSpacer_2"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> <item row="0" column="1"> <widget class="QCommandLinkButton" name="m_Extract3dButton"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>200</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Extract fibers passing through selected surface mesh. Select surface mesh and fiber bundle to execute.</string> </property> <property name="text"> <string>Extract 3D</string> </property> </widget> </item> <item row="2" column="0"> <widget class="QCommandLinkButton" name="m_GenerateRoiImage"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>16777215</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Generate a binary image containing all selected ROIs. Select at least one ROI (planar figure) and a reference fiber bundle or image.</string> </property> <property name="text"> <string>ROI Image</string> </property> </widget> </item> </layout> </widget> </item> <item row="1" column="0"> <widget class="QFrame" name="m_PlanarFigureButtonsFrame_2"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> <width>200</width> <height>0</height> </size> </property> <property name="maximumSize"> <size> <width>16777215</width> <height>60</height> </size> </property> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> <layout class="QGridLayout" name="gridLayout_5"> <property name="margin"> <number>0</number> </property> <item row="0" column="3"> <spacer name="horizontalSpacer_3"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> <item row="0" column="0"> <widget class="QCommandLinkButton" name="PFCompoANDButton"> <property name="enabled"> <bool>false</bool> </property> <property name="maximumSize"> <size> <width>60</width> <height>16777215</height> </size> </property> <property name="toolTip"> <string>Create AND composition with selected ROIs.</string> </property> <property name="text"> <string>AND</string> </property> </widget> </item> <item row="0" column="1"> <widget class="QCommandLinkButton" name="PFCompoORButton"> <property name="enabled"> <bool>false</bool> </property> <property name="maximumSize"> <size> <width>60</width> <height>16777215</height> </size> </property> <property name="toolTip"> <string>Create OR composition with selected ROIs.</string> </property> <property name="text"> <string>OR</string> </property> </widget> </item> <item row="0" column="2"> <widget class="QCommandLinkButton" name="PFCompoNOTButton"> <property name="enabled"> <bool>false</bool> </property> <property name="maximumSize"> <size> <width>60</width> <height>16777215</height> </size> </property> <property name="toolTip"> <string>Create NOT composition from selected ROI.</string> </property> <property name="text"> <string>NOT</string> </property> </widget> </item> </layout> </widget> </item> </layout> </widget> </item> <item> <widget class="QGroupBox" name="groupBox_2"> <property name="title"> <string>Fiber Bundle Processing</string> </property> <layout class="QFormLayout" name="formLayout"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> <item row="0" column="0"> <widget class="QComboBox" name="m_GenerationBox"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <item> <property name="text"> <string>Tract Density Image (TDI)</string> </property> </item> <item> <property name="text"> <string>Binary Envelope</string> </property> </item> <item> <property name="text"> <string>Fiber Bundle Image</string> </property> </item> <item> <property name="text"> <string>Fiber Endings Image</string> </property> </item> <item> <property name="text"> <string>Fiber Endings Pointset</string> </property> </item> </widget> </item> <item row="0" column="1"> <widget class="QSpinBox" name="m_UpsamplingSpinBox"> <property name="toolTip"> <string>Upsampling factor</string> </property> <property name="minimum"> <number>1</number> </property> <property name="maximum"> <number>10</number> </property> <property name="value"> <number>2</number> </property> </widget> </item> <item row="1" column="0"> <widget class="QCommandLinkButton" name="m_ProcessFiberBundleButton"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>200</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Perform selected operation on all selected fiber bundles.</string> </property> <property name="text"> <string>Generate</string> </property> </widget> </item> <item row="1" column="1"> <widget class="QCheckBox" name="m_InvertCheckbox"> <property name="toolTip"> <string>If selected operation generates an image, the inverse image is returned.</string> </property> <property name="text"> <string>Invert</string> </property> </widget> </item> <item row="2" column="0"> <widget class="QCommandLinkButton" name="m_ResampleFibersButton"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>200</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Resample fibers using a Kochanek spline interpolation.</string> </property> <property name="text"> <string>Smooth Fibers</string> </property> </widget> </item> <item row="2" column="1"> <widget class="QSpinBox" name="m_ResampleFibersSpinBox"> <property name="toolTip"> <string>Points per cm</string> </property> <property name="minimum"> <number>1</number> </property> <property name="maximum"> <number>50</number> </property> <property name="value"> <number>10</number> </property> </widget> </item> <item row="3" column="0"> + <widget class="QCommandLinkButton" name="m_PruneFibersButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>200</width> + <height>16777215</height> + </size> + </property> + <property name="font"> + <font> + <pointsize>11</pointsize> + </font> + </property> + <property name="toolTip"> + <string>Remove fibers shorten than the specified length (in mm).</string> + </property> + <property name="text"> + <string>Prune Bundle</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QSpinBox" name="m_PruneFibersSpinBox"> + <property name="toolTip"> + <string>Minimum fiber length in mm</string> + </property> + <property name="minimum"> + <number>0</number> + </property> + <property name="maximum"> + <number>1000</number> + </property> + <property name="value"> + <number>20</number> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QCommandLinkButton" name="m_MirrorFibersButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>200</width> + <height>16777215</height> + </size> + </property> + <property name="font"> + <font> + <pointsize>11</pointsize> + </font> + </property> + <property name="toolTip"> + <string>Mirror fibers around specified axis.</string> + </property> + <property name="text"> + <string>Mirror Fibers</string> + </property> + </widget> + </item> + <item row="5" column="0"> <widget class="QCommandLinkButton" name="m_FaColorFibersButton"> <property name="enabled"> <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>200</width> <height>16777215</height> </size> </property> <property name="font"> <font> <pointsize>11</pointsize> </font> </property> <property name="toolTip"> <string>Apply float image values (0-1) as color coding to the selected fiber bundle.</string> </property> <property name="text"> <string>Color By Scalar Map</string> </property> </widget> </item> + <item row="4" column="1"> + <widget class="QComboBox" name="m_AxisSelectionBox"> + <property name="currentIndex"> + <number>0</number> + </property> + <property name="maxVisibleItems"> + <number>3</number> + </property> + <property name="maxCount"> + <number>3</number> + </property> + <item> + <property name="text"> + <string>x - Axis</string> + </property> + </item> + <item> + <property name="text"> + <string>y - Axis</string> + </property> + </item> + <item> + <property name="text"> + <string>z - Axis</string> + </property> + </item> + </widget> + </item> </layout> </widget> </item> <item> <widget class="QGroupBox" name="groupBox_3"> <property name="title"> <string>Fiber Bundle Statistics</string> </property> <layout class="QGridLayout" name="gridLayout_2"> <item row="0" column="0"> <widget class="QTextEdit" name="m_StatsTextEdit"> <property name="font"> <font> <family>Courier 10 Pitch</family> </font> </property> <property name="acceptDrops"> <bool>false</bool> </property> <property name="readOnly"> <bool>true</bool> </property> </widget> </item> </layout> </widget> </item> <item> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>40</height> </size> </property> </spacer> </item> </layout> </widget> <resources> <include location="../../resources/QmitkDiffusionImaging.qrc"/> </resources> <connections/> </ui> diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkGibbsTrackingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkGibbsTrackingViewControls.ui index b99d3213ef..de4d981ce9 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkGibbsTrackingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkGibbsTrackingViewControls.ui @@ -1,1045 +1,1045 @@ <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>QmitkGibbsTrackingViewControls</class> <widget class="QWidget" name="QmitkGibbsTrackingViewControls"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>463</width> <height>1011</height> </rect> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> <width>0</width> <height>0</height> </size> </property> <property name="windowTitle"> <string>QmitkTemplate</string> </property> <layout class="QVBoxLayout" name="verticalLayout_2"> <property name="spacing"> <number>0</number> </property> <property name="leftMargin"> <number>9</number> </property> <property name="topMargin"> <number>3</number> </property> <property name="rightMargin"> <number>9</number> </property> <property name="bottomMargin"> <number>3</number> </property> <item> <widget class="QGroupBox" name="m_DataFrame"> <property name="title"> <string>Data</string> </property> <layout class="QGridLayout" name="gridLayout_4"> <item row="0" column="0"> <widget class="QLabel" name="label"> <property name="text"> <string>Q-Ball Image:</string> </property> </widget> </item> <item row="0" column="1"> <widget class="QLabel" name="m_QballImageLabel"> <property name="toolTip"> <string>Mandatory input</string> </property> <property name="text"> <string>-</string> </property> </widget> </item> <item row="1" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string>Mask Image:</string> </property> </widget> </item> <item row="1" column="1"> <widget class="QLabel" name="m_MaskImageLabel"> <property name="toolTip"> <string>Optional input to limit the algorithms search space.</string> </property> <property name="text"> <string>-</string> </property> </widget> </item> </layout> </widget> </item> <item> <widget class="QGroupBox" name="m_ParametersFrame"> <property name="title"> <string>Parameters</string> </property> <layout class="QGridLayout" name="gridLayout_5"> <property name="bottomMargin"> <number>0</number> </property> <item row="0" column="0"> <widget class="QLabel" name="m_IterationsLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Iterations: 10^7</string> </property> </widget> </item> <item row="0" column="2"> <widget class="QSlider" name="m_IterationsSlider"> <property name="toolTip"> <string>Specify number of iterations for the tracking algorithm.</string> </property> <property name="maximum"> <number>10</number> </property> <property name="value"> <number>6</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="tickPosition"> <enum>QSlider::TicksBelow</enum> </property> </widget> </item> <item row="2" column="0"> <widget class="QCheckBox" name="m_VisualizationCheckbox"> <property name="enabled"> <bool>true</bool> </property> <property name="toolTip"> <string>Activate continuous visualization of intermediate results.</string> </property> <property name="text"> <string>Visualize Tractography</string> </property> <property name="checked"> <bool>true</bool> </property> </widget> </item> <item row="2" column="2"> <widget class="QToolButton" name="m_VisualizeOnceButton"> <property name="toolTip"> <string>Visualize intermediate result.</string> </property> <property name="text"> <string/> </property> <property name="icon"> <iconset resource="../../resources/QmitkDiffusionImaging.qrc"> <normaloff>:/QmitkDiffusionImaging/Refresh_48.png</normaloff>:/QmitkDiffusionImaging/Refresh_48.png</iconset> </property> <property name="checkable"> <bool>true</bool> </property> </widget> </item> <item row="3" column="0"> <widget class="QCheckBox" name="m_AdvancedSettingsCheckbox"> <property name="text"> <string>Advanced Settings</string> </property> </widget> </item> <item row="1" column="0"> <widget class="QLabel" name="m_CurvatureThresholdLabel_3"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Output File:</string> </property> </widget> </item> <item row="1" column="2"> <widget class="QFrame" name="frame_2"> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Plain</enum> </property> <property name="lineWidth"> <number>0</number> </property> <layout class="QGridLayout" name="gridLayout"> <property name="margin"> <number>0</number> </property> <property name="spacing"> <number>0</number> </property> <item row="0" column="1"> <widget class="QToolButton" name="m_OutputFileButton"> <property name="toolTip"> <string>Select output file name and folder.</string> </property> <property name="text"> <string>...</string> </property> </widget> </item> <item row="0" column="0"> <widget class="QLineEdit" name="m_OutputFileLabel"> <property name="text"> <string>N/A</string> </property> <property name="readOnly"> <bool>true</bool> </property> </widget> </item> </layout> </widget> </item> </layout> </widget> </item> <item> <widget class="QFrame" name="m_AdvancedFrame"> <property name="enabled"> <bool>true</bool> </property> <property name="frameShape"> <enum>QFrame::StyledPanel</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> <layout class="QGridLayout" name="gridLayout_2"> <property name="leftMargin"> <number>9</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>9</number> </property> <property name="bottomMargin"> <number>0</number> </property> <property name="spacing"> <number>4</number> </property> <item row="1" column="1"> <widget class="QLabel" name="m_ParticleLengthLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>auto</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> <item row="2" column="1"> <widget class="QLabel" name="m_ParticleWidthLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>auto</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> <item row="2" column="2"> <widget class="QSlider" name="m_ParticleWidthSlider"> <property name="toolTip"> <string>auto = 0.5 * min. spacing; sigma</string> </property> <property name="maximum"> <number>100</number> </property> <property name="singleStep"> <number>1</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="tickPosition"> <enum>QSlider::NoTicks</enum> </property> </widget> </item> <item row="3" column="1"> <widget class="QLabel" name="m_ParticleWeightLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>auto</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> <item row="3" column="2"> <widget class="QSlider" name="m_ParticleWeightSlider"> <property name="toolTip"> <string>automatic estimation from gfa map and q-ball data.</string> </property> <property name="minimum"> <number>0</number> </property> <property name="maximum"> <number>1000</number> </property> <property name="singleStep"> <number>1</number> </property> <property name="value"> <number>0</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="invertedControls"> <bool>true</bool> </property> <property name="tickPosition"> <enum>QSlider::NoTicks</enum> </property> </widget> </item> <item row="4" column="1"> <widget class="QLabel" name="m_StartTempLabel"> <property name="text"> <string>0.1</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> <item row="4" column="2"> <widget class="QSlider" name="m_StartTempSlider"> <property name="minimum"> <number>1</number> </property> <property name="maximum"> <number>100</number> </property> <property name="singleStep"> <number>1</number> </property> <property name="value"> <number>10</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="invertedAppearance"> <bool>false</bool> </property> <property name="invertedControls"> <bool>false</bool> </property> <property name="tickPosition"> <enum>QSlider::NoTicks</enum> </property> </widget> </item> <item row="5" column="1"> <widget class="QLabel" name="m_EndTempLabel"> <property name="text"> <string>0.001</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> <item row="5" column="2"> <widget class="QSlider" name="m_EndTempSlider"> <property name="minimum"> <number>1</number> </property> <property name="maximum"> <number>99</number> </property> <property name="singleStep"> <number>1</number> </property> <property name="value"> <number>10</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="tickPosition"> <enum>QSlider::NoTicks</enum> </property> </widget> </item> <item row="6" column="1"> <widget class="QLabel" name="m_InExBalanceLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>0</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> <item row="6" column="2"> <widget class="QSlider" name="m_InExBalanceSlider"> <property name="toolTip"> <string>IE Bias < 0 < EE Bias</string> </property> <property name="minimum"> <number>-50</number> </property> <property name="maximum"> <number>50</number> </property> <property name="singleStep"> <number>1</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="tickPosition"> <enum>QSlider::NoTicks</enum> </property> </widget> </item> <item row="7" column="1"> <widget class="QLabel" name="m_FiberLengthLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>40mm</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> <item row="7" column="2"> <widget class="QSlider" name="m_FiberLengthSlider"> <property name="toolTip"> <string>Only fibers longer than specified are accepted.</string> </property> <property name="maximum"> - <number>100</number> + <number>500</number> </property> <property name="singleStep"> <number>1</number> </property> <property name="value"> <number>40</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="tickPosition"> <enum>QSlider::NoTicks</enum> </property> </widget> </item> <item row="1" column="0"> <widget class="QLabel" name="m_ParticleLengthLabel_2"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Particle Length:</string> </property> </widget> </item> <item row="2" column="0"> <widget class="QLabel" name="m_ParticleWidthLabel_2"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Particle Width:</string> </property> </widget> </item> <item row="3" column="0"> <widget class="QLabel" name="m_ParticleWeightLabel_2"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Particle Weight:</string> </property> </widget> </item> <item row="4" column="0"> <widget class="QLabel" name="m_StartTempLabel_2"> <property name="text"> <string>Start Temperature:</string> </property> </widget> </item> <item row="5" column="0"> <widget class="QLabel" name="m_EndTempLabel_2"> <property name="text"> <string>End Temperature:</string> </property> </widget> </item> <item row="6" column="0"> <widget class="QLabel" name="m_InExBalanceLabel_2"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Balance In/Ex Energy:</string> </property> </widget> </item> <item row="7" column="0"> <widget class="QLabel" name="m_FiberLengthLabel_2"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Min. Fiber Length:</string> </property> </widget> </item> <item row="10" column="0"> <widget class="QCheckBox" name="m_MeanSubtractionCheckbox"> <property name="enabled"> <bool>true</bool> </property> <property name="toolTip"> <string>Use mean subtracted ODFs (recommended).</string> </property> <property name="text"> <string>Subtract ODF Mean</string> </property> <property name="checked"> <bool>true</bool> </property> </widget> </item> <item row="10" column="1"> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeType"> <enum>QSizePolicy::Fixed</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>60</width> <height>20</height> </size> </property> </spacer> </item> <item row="8" column="0"> <widget class="QLabel" name="m_CurvatureThresholdLabel_2"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Curvature Threshold:</string> </property> </widget> </item> <item row="8" column="1"> <widget class="QLabel" name="m_CurvatureThresholdLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>45°</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> <item row="8" column="2"> <widget class="QSlider" name="m_CurvatureThresholdSlider"> <property name="toolTip"> <string>Allow only fiber curvature values smaller than the selected threshold.</string> </property> <property name="maximum"> <number>180</number> </property> <property name="singleStep"> <number>1</number> </property> <property name="value"> <number>45</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="tickPosition"> <enum>QSlider::NoTicks</enum> </property> </widget> </item> <item row="1" column="2"> <widget class="QSlider" name="m_ParticleLengthSlider"> <property name="toolTip"> <string>auto = 1.5 * min. spacing; l</string> </property> <property name="maximum"> <number>100</number> </property> <property name="singleStep"> <number>1</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="tickPosition"> <enum>QSlider::NoTicks</enum> </property> </widget> </item> </layout> </widget> </item> <item> <widget class="QFrame" name="frame_3"> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Plain</enum> </property> <property name="lineWidth"> <number>0</number> </property> <layout class="QGridLayout" name="gridLayout_7"> <property name="margin"> <number>0</number> </property> <property name="spacing"> <number>0</number> </property> <item row="0" column="0"> <widget class="QCommandLinkButton" name="m_SaveTrackingParameters"> <property name="enabled"> <bool>true</bool> </property> <property name="toolTip"> <string>Save current parameters as xml (.gtp)</string> </property> <property name="layoutDirection"> <enum>Qt::LeftToRight</enum> </property> <property name="text"> <string>Save Parameters</string> </property> <property name="icon"> <iconset resource="../../../../Modules/QmitkExt/resources/QmitkResources.qrc"> <normaloff>:/qmitk/btnMoveDown.png</normaloff>:/qmitk/btnMoveDown.png</iconset> </property> </widget> </item> <item row="0" column="1"> <widget class="QCommandLinkButton" name="m_LoadTrackingParameters"> <property name="enabled"> <bool>true</bool> </property> <property name="toolTip"> <string>Load parameters from xml file (.gtp)</string> </property> <property name="layoutDirection"> <enum>Qt::LeftToRight</enum> </property> <property name="text"> <string>Load Parameters</string> </property> <property name="icon"> <iconset resource="../../../../Modules/QmitkExt/resources/QmitkResources.qrc"> <normaloff>:/qmitk/btnMoveUp.png</normaloff>:/qmitk/btnMoveUp.png</iconset> </property> </widget> </item> <item row="1" column="0"> <widget class="QCommandLinkButton" name="m_TrackingStart"> <property name="enabled"> <bool>false</bool> </property> <property name="toolTip"> <string>No Q-Ball image selected.</string> </property> <property name="layoutDirection"> <enum>Qt::LeftToRight</enum> </property> <property name="text"> <string>Start Tractography</string> </property> <property name="icon"> <iconset resource="../../../../Modules/QmitkExt/resources/QmitkResources.qrc"> <normaloff>:/qmitk/play.xpm</normaloff>:/qmitk/play.xpm</iconset> </property> </widget> </item> <item row="1" column="1"> <widget class="QCommandLinkButton" name="m_TrackingStop"> <property name="enabled"> <bool>false</bool> </property> <property name="toolTip"> <string/> </property> <property name="layoutDirection"> <enum>Qt::LeftToRight</enum> </property> <property name="text"> <string>Stop Tractography</string> </property> <property name="icon"> <iconset resource="../../../../Modules/QmitkExt/resources/QmitkResources.qrc"> <normaloff>:/qmitk/stop.xpm</normaloff>:/qmitk/stop.xpm</iconset> </property> </widget> </item> </layout> </widget> </item> <item> <widget class="QGroupBox" name="groupBox_4"> <property name="title"> <string>Monitor</string> </property> <layout class="QGridLayout" name="gridLayout_6"> <item row="0" column="0"> <widget class="QLabel" name="label_23"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Progress:</string> </property> </widget> </item> <item row="0" column="1"> <widget class="QLabel" name="m_CurrentStepLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>-</string> </property> </widget> </item> <item row="1" column="0"> <widget class="QLabel" name="label_21"> <property name="toolTip"> <string comment="Will only be updated if tracking is visualized" extracomment="Will only be updated if tracking is visualized">Will only be updated if tracking is visualized</string> </property> <property name="statusTip"> <string>Will only be updated if tracking is visualized</string> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Accepted Fibers:</string> </property> </widget> </item> <item row="2" column="0"> <widget class="QLabel" name="label_24"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Connections:</string> </property> </widget> </item> <item row="3" column="0"> <widget class="QLabel" name="label_25"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Particles:</string> </property> </widget> </item> <item row="4" column="0"> <widget class="QLabel" name="label_27"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Proposal Acceptance Rate:</string> </property> </widget> </item> <item row="5" column="0"> <widget class="QLabel" name="label_26"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>Tracking Time:</string> </property> </widget> </item> <item row="1" column="1"> <widget class="QLabel" name="m_AcceptedFibersLabel"> <property name="toolTip"> <string>Will only be updated if tracking is visualized</string> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>-</string> </property> </widget> </item> <item row="2" column="1"> <widget class="QLabel" name="m_NumConnectionsLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>-</string> </property> </widget> </item> <item row="3" column="1"> <widget class="QLabel" name="m_NumParticlesLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>-</string> </property> </widget> </item> <item row="4" column="1"> <widget class="QLabel" name="m_ProposalAcceptance"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>-</string> </property> </widget> </item> <item row="5" column="1"> <widget class="QLabel" name="m_TrackingTimeLabel"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> <string>-</string> </property> </widget> </item> </layout> </widget> </item> <item> <spacer name="spacer1"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> <property name="sizeType"> <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>0</width> <height>0</height> </size> </property> </spacer> </item> </layout> </widget> <layoutdefault spacing="6" margin="11"/> <resources> <include location="../../../../Modules/QmitkExt/resources/QmitkResources.qrc"/> <include location="../../resources/QmitkDiffusionImaging.qrc"/> </resources> <connections/> </ui> diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.cpp new file mode 100644 index 0000000000..fe502112c6 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.cpp @@ -0,0 +1,197 @@ +/*=================================================================== + +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. + +===================================================================*/ + + +// Blueberry +#include <berryISelectionService.h> +#include <berryIWorkbenchWindow.h> +#include <berryIStructuredSelection.h> + +// Qmitk +#include "QmitkStreamlineTrackingView.h" +#include "QmitkStdMultiWidget.h" + +// Qt +#include <QMessageBox> + +// MITK +#include <mitkImageToItk.h> +#include <mitkFiberBundleX.h> + +// VTK +#include <vtkPolyData.h> +#include <vtkPoints.h> +#include <vtkCellArray.h> +#include <vtkSmartPointer.h> +#include <vtkPolyLine.h> +#include <vtkCellData.h> + + +const std::string QmitkStreamlineTrackingView::VIEW_ID = "org.mitk.views.streamlinetracking"; +const std::string id_DataManager = "org.mitk.views.datamanager"; +using namespace berry; + +QmitkStreamlineTrackingView::QmitkStreamlineTrackingView() + : QmitkFunctionality() + , m_Controls( 0 ) + , m_MultiWidget( NULL ) + , m_TensorImage( NULL ) + , m_SeedRoi( NULL ) +{ +} + +// Destructor +QmitkStreamlineTrackingView::~QmitkStreamlineTrackingView() +{ + +} + +void QmitkStreamlineTrackingView::CreateQtPartControl( QWidget *parent ) +{ + if ( !m_Controls ) + { + // create GUI widgets from the Qt Designer's .ui file + m_Controls = new Ui::QmitkStreamlineTrackingViewControls; + m_Controls->setupUi( parent ); + + connect( m_Controls->commandLinkButton, SIGNAL(clicked()), this, SLOT(DoFiberTracking()) ); + connect( m_Controls->m_SeedsPerVoxelSlider, SIGNAL(valueChanged(int)), this, SLOT(OnSeedsPerVoxelChanged(int)) ); + connect( m_Controls->m_MinTractLengthSlider, SIGNAL(valueChanged(int)), this, SLOT(OnMinTractLengthChanged(int)) ); + connect( m_Controls->m_FaThresholdSlider, SIGNAL(valueChanged(int)), this, SLOT(OnFaThresholdChanged(int)) ); + } +} + +void QmitkStreamlineTrackingView::OnSeedsPerVoxelChanged(int value) +{ + m_Controls->m_SeedsPerVoxelLabel->setText(QString("Seeds per Voxel: ")+QString::number(value)); +} + +void QmitkStreamlineTrackingView::OnMinTractLengthChanged(int value) +{ + m_Controls->m_MinTractLengthLabel->setText(QString("Min. Tract Length: ")+QString::number(value)+QString("mm")); +} + +void QmitkStreamlineTrackingView::OnFaThresholdChanged(int value) +{ + m_Controls->m_FaThresholdLabel->setText(QString("FA Threshold: ")+QString::number((float)value/100)); +} + +void QmitkStreamlineTrackingView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) +{ + m_MultiWidget = &stdMultiWidget; +} + + +void QmitkStreamlineTrackingView::StdMultiWidgetNotAvailable() +{ + m_MultiWidget = NULL; +} + +void QmitkStreamlineTrackingView::OnSelectionChanged( std::vector<mitk::DataNode*> nodes ) +{ + m_TensorImageNode = NULL; + m_TensorImage = NULL; + m_SeedRoi = NULL; + m_Controls->m_TensorImageLabel->setText("-"); + m_Controls->m_RoiImageLabel->setText("-"); + + if(nodes.empty()) + return; + + for( std::vector<mitk::DataNode*>::iterator it = nodes.begin(); it != nodes.end(); ++it ) + { + mitk::DataNode::Pointer node = *it; + + if( node.IsNotNull() && dynamic_cast<mitk::Image*>(node->GetData()) ) + { + if( dynamic_cast<mitk::TensorImage*>(node->GetData()) ) + { + m_TensorImageNode = node; + m_TensorImage = dynamic_cast<mitk::TensorImage*>(node->GetData()); + m_Controls->m_TensorImageLabel->setText(node->GetName().c_str()); + } + else + { + bool isBinary = false; + node->GetPropertyValue<bool>("binary", isBinary); + if (isBinary) + { + m_SeedRoi = dynamic_cast<mitk::Image*>(node->GetData()); + m_Controls->m_RoiImageLabel->setText(node->GetName().c_str()); + } + } + } + } + + if(m_TensorImage.IsNotNull()) + m_Controls->commandLinkButton->setEnabled(true); + else + m_Controls->commandLinkButton->setEnabled(false); +} + + + +void QmitkStreamlineTrackingView::DoFiberTracking() +{ + if (m_TensorImage.IsNull()) + return; + + typedef itk::Image< itk::DiffusionTensor3D<float>, 3> TensorImageType; + typedef mitk::ImageToItk<TensorImageType> CastType; + typedef mitk::ImageToItk<ItkUCharImageType> CastType2; + + CastType::Pointer caster = CastType::New(); + caster->SetInput(m_TensorImage); + caster->Update(); + TensorImageType::Pointer image = caster->GetOutput(); + + typedef itk::StreamlineTrackingFilter< float > FilterType; + FilterType::Pointer filter = FilterType::New(); + filter->SetInput(image); + filter->SetSeedsPerVoxel(m_Controls->m_SeedsPerVoxelSlider->value()); + filter->SetFaThreshold((float)m_Controls->m_FaThresholdSlider->value()/100); + + if (m_SeedRoi.IsNotNull()) + { + CastType2::Pointer caster2 = CastType2::New(); + caster2->SetInput(m_SeedRoi); + caster2->Update(); + ItkUCharImageType::Pointer mask = caster2->GetOutput(); + filter->SetMaskImage(mask); + } + + filter->Update(); + + vtkSmartPointer<vtkPolyData> fiberBundle = filter->GetFiberPolyData(); + if ( fiberBundle->GetNumberOfLines()==0 ) + return; + mitk::FiberBundleX::Pointer fib = mitk::FiberBundleX::New(fiberBundle); + + fib->RemoveShortFibers(m_Controls->m_MinTractLengthSlider->value()); + + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetData(fib); + + QString name(m_TensorImageNode->GetName().c_str()); + name += "_FiberBundle"; + node->SetName(name.toStdString()); + + node->SetVisibility(true); + + GetDataStorage()->Add(node); +} + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.h new file mode 100644 index 0000000000..3c436283e3 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.h @@ -0,0 +1,87 @@ +/*=================================================================== + +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 QmitkStreamlineTrackingView_h +#define QmitkStreamlineTrackingView_h + +#include <QmitkFunctionality.h> + +#include "ui_QmitkStreamlineTrackingViewControls.h" + +#include <mitkTensorImage.h> +#include <mitkDataStorage.h> +#include <mitkImage.h> +#include <itkImage.h> +#include <itkStreamlineTrackingFilter.h> + + +/*! +\brief QmitkStreamlineTrackingView + +\warning Implements standard streamline tracking as proposed by Mori et al. 1999 "Three-Dimensional Tracking of Axonal Projections in the Brain by Magnetic Resonance Imaging" + +\sa QmitkFunctionality +\ingroup Functionalities +*/ +class QmitkStreamlineTrackingView : public QmitkFunctionality +{ + // this is needed for all Qt objects that should have a Qt meta-object + // (everything that derives from QObject and wants to have signal/slots) + Q_OBJECT + +public: + + static const std::string VIEW_ID; + + typedef itk::Image< unsigned char, 3 > ItkUCharImageType; + + QmitkStreamlineTrackingView(); + virtual ~QmitkStreamlineTrackingView(); + + virtual void CreateQtPartControl(QWidget *parent); + + virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); + virtual void StdMultiWidgetNotAvailable(); + + protected slots: + + void DoFiberTracking(); + +protected: + + /// \brief called by QmitkFunctionality when DataManager's selection has changed + virtual void OnSelectionChanged( std::vector<mitk::DataNode*> nodes ); + Ui::QmitkStreamlineTrackingViewControls* m_Controls; + QmitkStdMultiWidget* m_MultiWidget; + +protected slots: + + void OnSeedsPerVoxelChanged(int value); + void OnMinTractLengthChanged(int value); + void OnFaThresholdChanged(int value); + +private: + + mitk::Image::Pointer m_SeedRoi; + mitk::TensorImage::Pointer m_TensorImage; + mitk::DataNode::Pointer m_TensorImageNode; + +}; + + + +#endif // _QMITKFIBERTRACKINGVIEW_H_INCLUDED + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingViewControls.ui new file mode 100644 index 0000000000..5a90ff232e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingViewControls.ui @@ -0,0 +1,212 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>QmitkStreamlineTrackingViewControls</class> + <widget class="QWidget" name="QmitkStreamlineTrackingViewControls"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>480</width> + <height>553</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="windowTitle"> + <string>QmitkTemplate</string> + </property> + <layout class="QGridLayout" name="gridLayout_3"> + <property name="topMargin"> + <number>3</number> + </property> + <property name="bottomMargin"> + <number>3</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Data</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Tensor Image:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="m_TensorImageLabel"> + <property name="text"> + <string>-</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>Seed ROI Image:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="m_RoiImageLabel"> + <property name="text"> + <string>-</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="3" column="0"> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>Parameters</string> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="3" column="0"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>200</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="m_SeedsPerVoxelLabel"> + <property name="toolTip"> + <string>Number of tracts started in each voxel of the seed ROI.</string> + </property> + <property name="text"> + <string>Seeds per Voxel: 1</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QSlider" name="m_MinTractLengthSlider"> + <property name="toolTip"> + <string>Minimum tract length in mm.</string> + </property> + <property name="minimum"> + <number>0</number> + </property> + <property name="maximum"> + <number>500</number> + </property> + <property name="value"> + <number>40</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QSlider" name="m_SeedsPerVoxelSlider"> + <property name="toolTip"> + <string>Number of tracts started in each voxel of the seed ROI.</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>10</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="m_MinTractLengthLabel"> + <property name="toolTip"> + <string>Minimum tract length in mm.</string> + </property> + <property name="text"> + <string>Min. Tract Length: 40mm</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="m_FaThresholdLabel"> + <property name="toolTip"> + <string>Minimum tract length in mm.</string> + </property> + <property name="text"> + <string>FA Threshold: 0.2</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QSlider" name="m_FaThresholdSlider"> + <property name="toolTip"> + <string>Fractional Anisotropy Threshold</string> + </property> + <property name="minimum"> + <number>0</number> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="value"> + <number>20</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="4" column="0"> + <widget class="QCommandLinkButton" name="commandLinkButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Start Tracking</string> + </property> + </widget> + </item> + <item row="5" column="0"> + <spacer name="spacer1"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>220</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11"/> + <tabstops> + <tabstop>commandLinkButton</tabstop> + </tabstops> + <resources/> + <connections/> +</ui> diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp index 50f76f44a1..de283acb87 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp @@ -1,71 +1,73 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) -Copyright (c) German Cancer Research Center, +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 +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 "mitkPluginActivator.h" #include <QtPlugin> #include "src/internal/QmitkDiffusionImagingPublicPerspective.h" #include "src/internal/QmitkQBallReconstructionView.h" #include "src/internal/QmitkPreprocessingView.h" #include "src/internal/QmitkDiffusionDicomImportView.h" #include "src/internal/QmitkDiffusionQuantificationView.h" #include "src/internal/QmitkTensorReconstructionView.h" #include "src/internal/QmitkControlVisualizationPropertiesView.h" #include "src/internal/QmitkODFDetailsView.h" #include "src/internal/QmitkGibbsTrackingView.h" #include "src/internal/QmitkStochasticFiberTrackingView.h" #include "src/internal/QmitkFiberProcessingView.h" #include "src/internal/QmitkFiberBundleDeveloperView.h" #include "src/internal/QmitkPartialVolumeAnalysisView.h" #include "src/internal/QmitkIVIMView.h" #include "src/internal/QmitkTractbasedSpatialStatisticsView.h" #include "src/internal/QmitkTbssSkeletonizationView.h" +#include "src/internal/QmitkStreamlineTrackingView.h" #include "src/internal/Connectomics/QmitkBrainNetworkAnalysisView.h" namespace mitk { void PluginActivator::start(ctkPluginContext* context) { BERRY_REGISTER_EXTENSION_CLASS(QmitkDiffusionImagingPublicPerspective, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkQBallReconstructionView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkPreprocessingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkDiffusionDicomImport, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkDiffusionQuantificationView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkTensorReconstructionView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkControlVisualizationPropertiesView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkODFDetailsView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkGibbsTrackingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkStochasticFiberTrackingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkFiberProcessingView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkFiberBundleDeveloperView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkPartialVolumeAnalysisView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkIVIMView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkTractbasedSpatialStatisticsView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkTbssSkeletonizationView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkBrainNetworkAnalysisView, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkStreamlineTrackingView, context) } void PluginActivator::stop(ctkPluginContext* context) { Q_UNUSED(context) } } Q_EXPORT_PLUGIN2(org_mitk_gui_qt_diffusionimaging, mitk::PluginActivator) diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/Perspectives/QmitkDIAppFiberTractographyPerspective.cpp b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/Perspectives/QmitkDIAppFiberTractographyPerspective.cpp index e03ad86c59..c476b26af0 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/Perspectives/QmitkDIAppFiberTractographyPerspective.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/Perspectives/QmitkDIAppFiberTractographyPerspective.cpp @@ -1,56 +1,60 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) -Copyright (c) German Cancer Research Center, +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 +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 "QmitkDIAppFiberTractographyPerspective.h" #include "berryIViewLayout.h" void QmitkDIAppFiberTractographyPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) { ///////////////////////////////////////////////////// // all di-app perspectives should have the following: ///////////////////////////////////////////////////// std::string editorArea = layout->GetEditorArea(); layout->AddStandaloneView("org.mitk.views.datamanager", false, berry::IPageLayout::LEFT, 0.3f, editorArea); layout->AddStandaloneView("org.mitk.views.controlvisualizationpropertiesview", false, berry::IPageLayout::BOTTOM, .2f, "org.mitk.views.datamanager"); berry::IFolderLayout::Pointer left = layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", berry::IPageLayout::BOTTOM, 0.15f, "org.mitk.views.controlvisualizationpropertiesview"); layout->AddStandaloneView("org.mitk.views.imagenavigator", false, berry::IPageLayout::BOTTOM, .4f, "org.mbi.diffusionimaginginternal.leftcontrols"); ///////////////////////////////////////////// // here goes the perspective specific stuff ///////////////////////////////////////////// left->AddView("org.mitk.views.gibbstracking"); berry::IViewLayout::Pointer lo = layout->GetViewLayout("org.mitk.views.gibbstracking"); lo->SetCloseable(false); left->AddView("org.mitk.views.stochasticfibertracking"); lo = layout->GetViewLayout("org.mitk.views.stochasticfibertracking"); lo->SetCloseable(false); + left->AddView("org.mitk.views.streamlinetracking"); + lo = layout->GetViewLayout("org.mitk.views.streamlinetracking"); + lo->SetCloseable(false); + left->AddView("org.mitk.views.fiberprocessing"); lo = layout->GetViewLayout("org.mitk.views.fiberprocessing"); lo->SetCloseable(false); }