diff --git a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkRandomPhantomFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkRandomPhantomFilter.cpp index bbaadbd74c..08038f90bc 100644 --- a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkRandomPhantomFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkRandomPhantomFilter.cpp @@ -1,439 +1,450 @@ /*=================================================================== 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 __itkRandomPhantomFilter_cpp //#define __itkRandomPhantomFilter_cpp #include "itkRandomPhantomFilter.h" #include #include #include namespace itk{ RandomPhantomFilter::RandomPhantomFilter() : m_NumTracts(1) , m_MinStreamlineDensity(25) , m_MaxStreamlineDensity(200) , m_StartRadiusMin(5) , m_StartRadiusMax(30) , m_CurvynessMin(10) , m_CurvynessMax(45) , m_StepSizeMin(15) , m_StepSizeMax(30) , m_MinTwist(10) , m_MaxTwist(30) { m_VolumeSize[0] = 500; m_VolumeSize[1] = 500; m_VolumeSize[2] = 500; } RandomPhantomFilter::~RandomPhantomFilter() { } void RandomPhantomFilter::TransformPlanarFigure(mitk::PlanarEllipse* pe, mitk::Vector3D translation, mitk::Vector3D rotation, double twistangle, double radius1, double radius2) { mitk::BaseGeometry* geom = pe->GetGeometry(); // translate geom->Translate(translation); // calculate rotation matrix double x = rotation[0]*itk::Math::pi/180; double y = rotation[1]*itk::Math::pi/180; double z = rotation[2]*itk::Math::pi/180; itk::Matrix< double, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; itk::Matrix< double, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; itk::Matrix< double, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< double, 3, 3 > rot = rotZ*rotY*rotX; // rotate fiducial geom->GetIndexToWorldTransform()->SetMatrix(rot*geom->GetIndexToWorldTransform()->GetMatrix()); // adjust control points auto p0 = pe->GetControlPoint(0); auto p1 = pe->GetControlPoint(1); auto p2 = pe->GetControlPoint(2); auto p3 = pe->GetControlPoint(3); auto v1 = p1 - p0; auto v2 = p2 - p0; auto dot = std::cos(itk::Math::pi*twistangle/180.0); vnl_matrix_fixed tRot; tRot[0][0] = dot; tRot[1][1] = tRot[0][0]; tRot[1][0] = sin(acos(tRot[0][0])); tRot[0][1] = -tRot[1][0]; if (twistangle<0) tRot = tRot.transpose(); vnl_vector_fixed vt; vt[0]=1; vt[1]=0; vnl_vector_fixed v3 = tRot*vt; v1.Normalize(); v2.Normalize(); p1 = p0 + radius1; p2 = p0 + radius2; p3 = p0 + mitk::Vector2D(v3); pe->SetControlPoint(1, p1); pe->SetControlPoint(2, p2); pe->SetControlPoint(3, p3); pe->Modified(); } mitk::PlanarEllipse::Pointer RandomPhantomFilter::CreatePlanarFigure() { mitk::PlaneGeometry::Pointer pl = mitk::PlaneGeometry::New(); pl->SetIdentity(); // mitk::Point3D o; o.Fill(10.0); // pl->SetOrigin(o); mitk::PlanarEllipse::Pointer figure = mitk::PlanarEllipse::New(); figure->ResetNumberOfControlPoints(0); figure->SetPlaneGeometry(pl); mitk::Point2D p0; p0.Fill(0.0); mitk::Point2D p1; p1.Fill(0.0); p1[0] = 1; mitk::Point2D p2; p2.Fill(0.0); p2[1] = 1; figure->PlaceFigure(p0); figure->AddControlPoint(p0); figure->AddControlPoint(p1); figure->AddControlPoint(p2); figure->AddControlPoint(p2); figure->SetProperty("initiallyplaced", mitk::BoolProperty::New(true)); return figure; } void RandomPhantomFilter::SetNumTracts(unsigned int NumTracts) { m_NumTracts = NumTracts; } void RandomPhantomFilter::GetPfOnBoundingPlane(mitk::Vector3D& pos, mitk::Vector3D& rot) { Statistics::MersenneTwisterRandomVariateGenerator::Pointer randGen = Statistics::MersenneTwisterRandomVariateGenerator::New(); randGen->SetSeed(); int plane = randGen->GetIntegerVariate(5) + 1; MITK_INFO << "Plane: " << plane; switch(plane) { case 1: { pos[0] = randGen->GetUniformVariate(0, m_VolumeSize[0]); pos[1] = randGen->GetUniformVariate(0, m_VolumeSize[1]); pos[2] = 0; rot[0] = 0; rot[1] = 0; rot[2] = 0; break; } case 2: { pos[0] = 0; pos[1] = randGen->GetUniformVariate(0, m_VolumeSize[1]); pos[2] = randGen->GetUniformVariate(0, m_VolumeSize[2]); rot[0] = 0; rot[1] = 90; rot[2] = 0; break; } case 3: { pos[0] = randGen->GetUniformVariate(0, m_VolumeSize[0]); pos[1] = 0; pos[2] = randGen->GetUniformVariate(0, m_VolumeSize[2]); rot[0] = -90; rot[1] = 0; rot[2] = 0; break; } case 4: { pos[0] = randGen->GetUniformVariate(0, m_VolumeSize[0]); pos[1] = m_VolumeSize[1]; pos[2] = randGen->GetUniformVariate(0, m_VolumeSize[2]); rot[0] = 90; rot[1] = 0; rot[2] = 0; break; } case 5: { pos[0] = m_VolumeSize[0]; pos[1] = randGen->GetUniformVariate(0, m_VolumeSize[1]); pos[2] = randGen->GetUniformVariate(0, m_VolumeSize[2]); rot[0] = 0; rot[1] = -90; rot[2] = 0; break; } case 6: { pos[0] = randGen->GetUniformVariate(0, m_VolumeSize[0]); pos[1] = randGen->GetUniformVariate(0, m_VolumeSize[1]); pos[2] = m_VolumeSize[2]; rot[0] = 180; rot[1] = 0; rot[2] = 0; break; } } } bool RandomPhantomFilter::IsInVolume(mitk::Vector3D pos) { if (pos[0]>=0 && pos[0]<=m_VolumeSize[0] && pos[1]>=0 && pos[1]<=m_VolumeSize[1] && pos[2]>=0 && pos[2]<=m_VolumeSize[2]) return true; return false; } void RandomPhantomFilter::setMinTwist(unsigned int MinTwist) { m_MinTwist = MinTwist; } void RandomPhantomFilter::setMaxStreamlineDensity(unsigned int MaxStreamlineDensity) { m_MaxStreamlineDensity = MaxStreamlineDensity; } void RandomPhantomFilter::setMinStreamlineDensity(unsigned int MinStreamlinDensity) { m_MinStreamlineDensity = MinStreamlinDensity; } void RandomPhantomFilter::setMaxTwist(unsigned int MaxTwist) { m_MaxTwist = MaxTwist; } void RandomPhantomFilter::setVolumeSize(const mitk::Vector3D &VolumeSize) { m_VolumeSize = VolumeSize; } void RandomPhantomFilter::setStepSizeMax(unsigned int StepSizeMax) { m_StepSizeMax = StepSizeMax; } void RandomPhantomFilter::setStepSizeMin(unsigned int StepSizeMin) { m_StepSizeMin = StepSizeMin; } void RandomPhantomFilter::setCurvynessMax(unsigned int CurvynessMax) { m_CurvynessMax = CurvynessMax; } void RandomPhantomFilter::setCurvynessMin(unsigned int CurvynessMin) { m_CurvynessMin = CurvynessMin; } void RandomPhantomFilter::setStartRadiusMax(unsigned int StartRadiusMax) { m_StartRadiusMax = StartRadiusMax; } void RandomPhantomFilter::setStartRadiusMin(unsigned int StartRadiusMin) { m_StartRadiusMin = StartRadiusMin; } void RandomPhantomFilter::GenerateData() { Statistics::MersenneTwisterRandomVariateGenerator::Pointer randGen = Statistics::MersenneTwisterRandomVariateGenerator::New(); randGen->SetSeed(); for (unsigned int i=0; i bundle_waypoints; double curvyness = randGen->GetUniformVariate(m_CurvynessMin, m_CurvynessMax); int twistdir = static_cast(randGen->GetIntegerVariate(2)) - 1; double dtwist = randGen->GetUniformVariate(m_MinTwist, m_MaxTwist); mitk::Vector3D pos; pos.Fill(0.0); mitk::Vector3D rot; rot.Fill(0.0); double twist = 0; double radius1 = randGen->GetUniformVariate(m_StartRadiusMin, m_StartRadiusMax); double radius2 = randGen->GetUniformVariate(m_StartRadiusMin, m_StartRadiusMax); GetPfOnBoundingPlane(pos, rot); rot[0] += randGen->GetUniformVariate(-curvyness, curvyness); rot[1] += randGen->GetUniformVariate(-curvyness, curvyness); rot[2] += randGen->GetUniformVariate(-curvyness, curvyness); mitk::PlanarEllipse::Pointer start = CreatePlanarFigure(); TransformPlanarFigure(start, pos, rot, twist, radius1, radius2); bundle_waypoints.push_back(start); double c_area = M_PI*radius1*radius2; int sizestrategy = static_cast(randGen->GetIntegerVariate(2)) - 1; MITK_INFO << "Twist: " << dtwist; MITK_INFO << "Twist direction: " << twistdir; MITK_INFO << "Curvyness: " << curvyness; MITK_INFO << "Size strategy: " << sizestrategy; int c = 1; while(IsInVolume(pos)) { pos += bundle_waypoints.at(c-1)->GetPlaneGeometry()->GetNormal() * randGen->GetUniformVariate(m_StepSizeMin, m_StepSizeMax); rot[0] += randGen->GetUniformVariate(-curvyness, curvyness); rot[1] += randGen->GetUniformVariate(-curvyness, curvyness); rot[2] += randGen->GetUniformVariate(-curvyness, curvyness); twist += dtwist * twistdir; if (randGen->GetUniformVariate(0.0, 1.0) < 0.25) { int temp = static_cast(randGen->GetIntegerVariate(2)) - 1; if (temp!=twistdir) { twistdir = temp; MITK_INFO << "Twist direction change: " << twistdir; } } if (randGen->GetUniformVariate(0.0, 1.0) < 0.25) { int temp = static_cast(randGen->GetIntegerVariate(2)) - 1; if (temp!=sizestrategy) { sizestrategy = temp; MITK_INFO << "Size strategy change: " << sizestrategy; } } double dsize = 3.0; double minradius = 5.0; double maxradius = 2.0*m_StartRadiusMax; if (sizestrategy==0) { radius1 += randGen->GetUniformVariate(-dsize, dsize); radius2 += randGen->GetUniformVariate(-dsize, dsize); while (radius1 < 5) radius1 += randGen->GetUniformVariate(-dsize, dsize); while (radius2 < 5) radius2 += randGen->GetUniformVariate(-dsize, dsize); } else if (sizestrategy==1) { radius1 += randGen->GetUniformVariate(0, dsize); radius2 += randGen->GetUniformVariate(0, dsize); if (radius1 > maxradius) { radius1 = maxradius; sizestrategy = static_cast(randGen->GetIntegerVariate(1)) - 1; } if (radius2 > maxradius) { radius2 = maxradius; sizestrategy = static_cast(randGen->GetIntegerVariate(1)) - 1; } } else if (sizestrategy==-1) { radius1 += randGen->GetUniformVariate(-dsize, 0); radius2 += randGen->GetUniformVariate(-dsize, 0); if (radius1 < minradius) { radius1 = minradius; sizestrategy = static_cast(randGen->GetIntegerVariate(1)); } if (radius2 < minradius) { radius2 = minradius; sizestrategy = static_cast(randGen->GetIntegerVariate(1)); } } c_area += M_PI*radius1*radius2; mitk::PlanarEllipse::Pointer pf = CreatePlanarFigure(); TransformPlanarFigure(pf, pos, rot, twist, radius1, radius2); bundle_waypoints.push_back(pf); ++c; } c_area /= c; c_area /= 100; MITK_INFO << "Average crossectional area: " << c_area << "cm²"; fiber_params.m_Fiducials.push_back(bundle_waypoints); auto density = randGen->GetUniformVariate(m_MinStreamlineDensity, m_MaxStreamlineDensity); MITK_INFO << "Density: " << density; + MITK_INFO << "Num. fibers: " << fiber_params.m_Density; + fiber_params.m_Density = static_cast(std::ceil(c_area*density)); + if (randGen->GetIntegerVariate(1)==0) + { + fiber_params.m_Distribution = FiberGenerationParameters::DISTRIBUTE_UNIFORM; + MITK_INFO << "Distribution: uniform"; + } + else + { + fiber_params.m_Distribution = FiberGenerationParameters::DISTRIBUTE_GAUSSIAN; + MITK_INFO << "Distribution: Gaussian"; + } - MITK_INFO << "Num. fibers: " << fiber_params.m_Density; MITK_INFO << "Num. fiducials: " << c; MITK_INFO << "------------\n"; std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect itk::FibersFromPlanarFiguresFilter::Pointer filter = itk::FibersFromPlanarFiguresFilter::New(); filter->SetParameters(fiber_params); filter->Update(); m_FiberBundles.push_back(filter->GetFiberBundles().at(0)); std::cout.rdbuf (old); // <-- restore } } } //#endif // __itkRandomPhantomFilter_cpp diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/documentation/UserManual/QmitkFiberGenerationViewUserManual.dox b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/documentation/UserManual/QmitkFiberGenerationViewUserManual.dox index 894b666b06..77b3929efa 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/documentation/UserManual/QmitkFiberGenerationViewUserManual.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/documentation/UserManual/QmitkFiberGenerationViewUserManual.dox @@ -1,70 +1,72 @@ /** \page org_mitk_views_fibergenerationview Fiber Generator This view provides the user interface for defining artificial white matter fibers. Arbitrary fiber configurations like bent, crossing, kissing, twisting, and fanning bundles can be intuitively defined by positioning only a few 3D waypoints to trigger the automated generation of synthetic fibers. -From these fibers a diffusion-weighted signal can be simulated using the Fiberfox View. +From these fibers a diffusion-weighted signal can be simulated using the Fiberfox View. The view also enables the automatic generation of random fiber configurations (Fig. 3). Available sections: - \ref QmitkFiberGenerationViewUserManualFiberDefinition - \ref QmitkFiberGenerationViewUserManualKnownIssues - \ref QmitkFiberGenerationViewUserManualReferences -\section QmitkFiberGenerationViewUserManualFiberDefinition Fiber Definition +\section QmitkFiberGenerationViewUserManualFiberDefinition Manual Fiber Definition Fiber strands are defined simply by placing markers in a 3D image volume. The fibers are then interpolated between these fiducials. Example: \li Chose an image volume to place the markers used to define the fiber pathway. If you don't have such an image available switch to the "Signal Generation" tab, define the size and spacing of the desired image and click "Generate Image". If no fiber bundle is selected, this will generate a dummy image that can be used to place the fiducials. \li Start placing fiducials at the desired positions to define the fiber pathway. To do that, click on the button with the circle pictogram, then click at the desired position and plane in the image volume and drag your mouse while keeping the button pressed to generate a circular shape. Adjust the shape using the control points (Fig. 2). The position of control point D introduces a twist of the fibers between two successive fiducials. The actual fiber generation is triggered automatically as soon as you place the second control point. \li In some cases the fibers are entangled in a way that can't be resolved by introducing an additional fiber twist. Fiberfox tries to avoid these situations, which arise from different normal orientations of succeeding fiducials, automatically. In rare cases this is not successful. Use the double-arrow button to flip the fiber positions of the selected fiducial in one dimension. Either the problem is resolved now or you can resolve it manually by adjusting the twist-control point. \li To create non elliptical fiber profile shapes switch to the Fiber Extraction View. This view provides tools to extract subesets of fibers from fiber bundles and enables to cut out arbitrary polygonal fiber shapes from existing bundles. \imageMacro{Fiberfox-Fiducial.png, "Fig. 1: Control points defining the actual shape of the fiducial. A specifies the fiducials position in space\, B and C the two ellipse radii and D the twisting angle between two successive fiducials.",10} Fiber Options: \li Real Time Fibers: If checked, each parameter adjustment (fiducial position, number of fibers, ...) will be directly applied to the selected fiber bundle. If unchecked, the fibers will only be generated if the corresponding button "Generate Fibers" is clicked. \li Fiber Distribution: Specifies if the fiber distribution inside the bundle follows a uniform or normal distribution. \li \# Fibers: Specifies the number of fibers that will be generated for the selected bundle. \li Advanced Options: Show/hide advanced options \li Fiber Sampling: Adjusts the distenace of the fiber sampling points (in mm). A higher sampling rate is needed if high curvatures are modeled. \li Tension, Continuity, Bias: Parameters controlling the shape of the splines interpolation the fiducials. See Wikipedia for details. Fiducial Options: \li Use Constant Fiducial Radius: If checked, all fiducials are treated as circles with the same radius. The first fiducial of the bundle defines the radius of all other fiducials. \li Align with grid: Click to shift the selected fiducial center points to the next voxel center. Operations: \li Rotation: Define the rotation of the selected fiber bundle around each axis (in degree). \li Translation: Define the translation of the selected fiber bundle along each axis (in mm). \li Scaling: Define a scaling factor for the selected fiber bundle in each dimension. \li Transform Selection: Apply specified rotation, translation and scaling to the selected Bundle/Fiducial \li Copy Bundles: Add copies of the selected fiber bundles to the datamanager. \li Join Bundles: Add new bundle to the datamanager that contains all fibers from the selected bundles. \li Include Fiducials: If checked, the specified transformation is also applied to the fiducials belonging to the selected fiber bundle and the fiducials are also copied. \imageMacro{FiberfoxExamples.png, "Fig. 2: Examples of artificial crossing (a\,b)\, fanning (c\,d)\, highly curved (e\,f)\, kissing (g\,h) and twisting (i\,j) fibers as well as of the corresponding tensor images generated with Fiberfox.",4} +\imageMacro{random_phantom.png, "Fig. 3: Example of a random fiber phantom containing all kinds of configurations.",4} + \section QmitkFiberGenerationViewUserManualKnownIssues Known Issues \li If a scaling factor is applied to the selcted fiber bundle, the corresponding fiducials are not scaled accordingly. \li In some cases the automatic update of the selected fiber bundle is not triggered even if "Real Time Fibers" is checked, e.g. if a fiducial is deleted. If this happens on can always force an update by pressing the "Generate Fibers" button. If any other issues or feature requests arises during the use of Fiberfox, please don't hesitate to send us an e-mail or directly report the issue in our bugtracker: https://phabricator.mitk.org/maniphest/ \section QmitkFiberGenerationViewUserManualReferences References [1] Neher, P.F., Laun, F.B., Stieltjes, B., Maier-Hein, K.H., 2014. Fiberfox: facilitating the creation of realistic white matter software phantoms. Magn Reson Med 72, 1460–1470. doi:10.1002/mrm.25045 [2] Neher, P.F., Laun, F.Neher, P.F., Stieltjes, B., Laun, F.B., Meinzer, H.-P., Fritzsche, K.H., 2013. Fiberfox: A novel tool to generate software phantoms of complex fiber geometries, in: Proceedings of International Society of Magnetic Resonance in Medicine. [3] Neher, P.F., Stieltjes, B., Laun, F.B., Meinzer, H.-P., Fritzsche, K.H., 2013. Fiberfox: A novel tool to generate software phantoms of complex fiber geometries, in: Proceedings of International Society of Magnetic Resonance in Medicine. [4] Hering, J., Neher, P.F., Meinzer, H.-P., Maier-Hein, K.H., 2014. Construction of ground-truth data for head motion correction in diffusion MRI, in: Proceedings of International Society of Magnetic Resonance in Medicine. [5] Maier-Hein, Klaus, Neher, Peter, Houde, Jean-Christophe, Caruyer, Emmanuel, Daducci, Alessandro, Dyrby, Tim, … Descoteaux, Maxime. (2015). Tractography Challenge ISMRM 2015 Data [Data set]. Zenodo. http://doi.org/10.5281/zenodo.572345 [6] Maier-Hein, Klaus, Neher, Peter, Houde, Jean-Christophe, Caruyer, Emmanuel, Daducci, Alessandro, Dyrby, Tim, … Descoteaux, Maxime. (2017). Tractography Challenge ISMRM 2015 High-resolution Data [Data set]. Zenodo. http://doi.org/10.5281/zenodo.579933 */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/documentation/UserManual/random_phantom.png b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/documentation/UserManual/random_phantom.png new file mode 100644 index 0000000000..cc4f29a0cb Binary files /dev/null and b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/documentation/UserManual/random_phantom.png differ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberGenerationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberGenerationView.cpp index 9a7af8be07..dc37d11497 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberGenerationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberGenerationView.cpp @@ -1,1165 +1,1165 @@ /*=================================================================== 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 #include // Qmitk #include "QmitkFiberGenerationView.h" // MITK #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define RAPIDXML_NO_EXCEPTIONS #include #include #include #include #include "usModuleRegistry.h" #include #include #include #include #include #include #include #include #include #include #include "mitkNodePredicateDataType.h" #include #include #include #include #define _USE_MATH_DEFINES #include const std::string QmitkFiberGenerationView::VIEW_ID = "org.mitk.views.fibergenerationview"; QmitkFiberGenerationView::QmitkFiberGenerationView() : QmitkAbstractView() , m_Controls( 0 ) , m_SelectedImageNode( nullptr ) { } // Destructor QmitkFiberGenerationView::~QmitkFiberGenerationView() { } void QmitkFiberGenerationView::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::QmitkFiberGenerationViewControls; m_Controls->setupUi( parent ); m_ParameterFile = QDir::currentPath()+"/param.ffp"; connect(static_cast(m_Controls->m_RandomPhantomButton), SIGNAL(clicked()), static_cast(this), SLOT(RandomPhantom())); connect(static_cast(m_Controls->m_GenerateFibersButton), SIGNAL(clicked()), static_cast(this), SLOT(GenerateFibers())); connect(static_cast(m_Controls->m_CircleButton), SIGNAL(clicked()), static_cast(this), SLOT(OnDrawROI())); connect(static_cast(m_Controls->m_FlipButton), SIGNAL(clicked()), static_cast(this), SLOT(OnFlipButton())); connect(static_cast(m_Controls->m_JoinBundlesButton), SIGNAL(clicked()), static_cast(this), SLOT(JoinBundles())); connect(static_cast(m_Controls->m_VarianceBox), SIGNAL(valueChanged(double)), static_cast(this), SLOT(OnVarianceChanged(double))); connect(static_cast(m_Controls->m_DistributionBox), SIGNAL(currentIndexChanged(int)), static_cast(this), SLOT(OnDistributionChanged(int))); connect(static_cast(m_Controls->m_FiberDensityBox), SIGNAL(valueChanged(int)), static_cast(this), SLOT(OnFiberDensityChanged(int))); connect(static_cast(m_Controls->m_FiberSamplingBox), SIGNAL(valueChanged(double)), static_cast(this), SLOT(OnFiberSamplingChanged(double))); connect(static_cast(m_Controls->m_TensionBox), SIGNAL(valueChanged(double)), static_cast(this), SLOT(OnTensionChanged(double))); connect(static_cast(m_Controls->m_ContinuityBox), SIGNAL(valueChanged(double)), static_cast(this), SLOT(OnContinuityChanged(double))); connect(static_cast(m_Controls->m_BiasBox), SIGNAL(valueChanged(double)), static_cast(this), SLOT(OnBiasChanged(double))); connect(static_cast(m_Controls->m_ConstantRadiusBox), SIGNAL(stateChanged(int)), static_cast(this), SLOT(OnConstantRadius(int))); connect(static_cast(m_Controls->m_CopyBundlesButton), SIGNAL(clicked()), static_cast(this), SLOT(CopyBundles())); connect(static_cast(m_Controls->m_TransformBundlesButton), SIGNAL(clicked()), static_cast(this), SLOT(ApplyTransform())); connect(static_cast(m_Controls->m_AlignOnGrid), SIGNAL(clicked()), static_cast(this), SLOT(AlignOnGrid())); connect(static_cast(m_Controls->m_FidAxis1), SIGNAL(editingFinished()), static_cast(this), SLOT(UpdateFiducialPosition())); connect(static_cast(m_Controls->m_FidAxis2), SIGNAL(editingFinished()), static_cast(this), SLOT(UpdateFiducialPosition())); connect(static_cast(m_Controls->m_FidPosX), SIGNAL(editingFinished()), static_cast(this), SLOT(UpdateFiducialPosition())); connect(static_cast(m_Controls->m_FidPosY), SIGNAL(editingFinished()), static_cast(this), SLOT(UpdateFiducialPosition())); connect(static_cast(m_Controls->m_FidPosZ), SIGNAL(editingFinished()), static_cast(this), SLOT(UpdateFiducialPosition())); connect(static_cast(m_Controls->m_FidTwist), SIGNAL(editingFinished()), static_cast(this), SLOT(UpdateFiducialPosition())); connect(static_cast(m_Controls->m_AdvancedOptionsBox), SIGNAL( stateChanged(int)), static_cast(this), SLOT(ShowAdvancedOptions(int))); connect(static_cast(m_Controls->m_SaveParametersButton), SIGNAL(clicked()), static_cast(this), SLOT(SaveParameters())); connect(static_cast(m_Controls->m_LoadParametersButton), SIGNAL(clicked()), static_cast(this), SLOT(LoadParameters())); - + OnDistributionChanged(0); } UpdateGui(); } void QmitkFiberGenerationView::RandomPhantom() { itk::RandomPhantomFilter::Pointer filter = itk::RandomPhantomFilter::New(); filter->SetNumTracts(m_Controls->m_NumBundlesBox->value()); filter->setMinStreamlineDensity(m_Controls->m_MinDensityBox->value()); filter->setMaxStreamlineDensity(m_Controls->m_MaxDensityBox->value()); mitk::Vector3D vol; vol[0] = m_Controls->m_VolumeSizeX->value(); vol[1] = m_Controls->m_VolumeSizeY->value(); vol[2] = m_Controls->m_VolumeSizeZ->value(); filter->setVolumeSize(vol); filter->setStepSizeMin(m_Controls->m_StepSizeMinBox->value()); filter->setStepSizeMax(m_Controls->m_StepSizeMaxBox->value()); filter->setCurvynessMin(m_Controls->m_CurvyMinBox->value()); filter->setCurvynessMax(m_Controls->m_CurvyMaxBox->value()); filter->setStartRadiusMin(m_Controls->m_SizeMinBox->value()); filter->setStartRadiusMax(m_Controls->m_SizeMaxBox->value()); filter->setMinTwist(m_Controls->m_MinTwistBox->value()); filter->setMaxTwist(m_Controls->m_MaxTwistBox->value()); filter->Update(); auto fibs = filter->GetFiberBundles(); std::vector< mitk::DataNode::Pointer > fiber_nodes; int c = 1; for (auto fib : fibs) { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( fib ); node->SetName("Bundle_" + boost::lexical_cast(c)); GetDataStorage()->Add(node); fiber_nodes.push_back(node); ++c; } // mitk::RenderingManager::GetInstance()->RequestUpdateAll(); mitk::RenderingManager::GetInstance()->InitializeViews(GetDataStorage()->ComputeVisibleBoundingGeometry3D()); } void QmitkFiberGenerationView::UpdateParametersFromGui() { m_Parameters.ClearFiberParameters(); m_Parameters.m_Misc.m_CheckAdvancedFiberOptionsBox = m_Controls->m_AdvancedOptionsBox->isChecked(); switch(m_Controls->m_DistributionBox->currentIndex()) { case 0: m_Parameters.m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_UNIFORM; break; case 1: m_Parameters.m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_GAUSSIAN; break; default: m_Parameters.m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_UNIFORM; } m_Parameters.m_FiberGen.m_Variance = m_Controls->m_VarianceBox->value(); m_Parameters.m_FiberGen.m_Density = m_Controls->m_FiberDensityBox->value(); m_Parameters.m_FiberGen.m_Sampling = m_Controls->m_FiberSamplingBox->value(); m_Parameters.m_FiberGen.m_Tension = m_Controls->m_TensionBox->value(); m_Parameters.m_FiberGen.m_Continuity = m_Controls->m_ContinuityBox->value(); m_Parameters.m_FiberGen.m_Bias = m_Controls->m_BiasBox->value(); m_Parameters.m_FiberGen.m_Rotation[0] = m_Controls->m_XrotBox->value(); m_Parameters.m_FiberGen.m_Rotation[1] = m_Controls->m_YrotBox->value(); m_Parameters.m_FiberGen.m_Rotation[2] = m_Controls->m_ZrotBox->value(); m_Parameters.m_FiberGen.m_Translation[0] = m_Controls->m_XtransBox->value(); m_Parameters.m_FiberGen.m_Translation[1] = m_Controls->m_YtransBox->value(); m_Parameters.m_FiberGen.m_Translation[2] = m_Controls->m_ZtransBox->value(); m_Parameters.m_FiberGen.m_Scale[0] = m_Controls->m_XscaleBox->value(); m_Parameters.m_FiberGen.m_Scale[1] = m_Controls->m_YscaleBox->value(); m_Parameters.m_FiberGen.m_Scale[2] = m_Controls->m_ZscaleBox->value(); m_Parameters.m_Misc.m_CheckRealTimeFibersBox = m_Controls->m_RealTimeFibers->isChecked(); m_Parameters.m_Misc.m_CheckAdvancedFiberOptionsBox = m_Controls->m_AdvancedOptionsBox->isChecked(); m_Parameters.m_Misc.m_CheckIncludeFiducialsBox = m_Controls->m_IncludeFiducials->isChecked(); m_Parameters.m_Misc.m_CheckConstantRadiusBox = m_Controls->m_ConstantRadiusBox->isChecked(); } void QmitkFiberGenerationView::SaveParameters(QString filename) { UpdateParametersFromGui(); m_Parameters.SaveParameters(filename.toStdString()); m_ParameterFile = filename; } void QmitkFiberGenerationView::SaveParameters() { QString filename = QFileDialog::getSaveFileName( 0, tr("Save Parameters"), m_ParameterFile, tr("Fiberfox Parameters (*.ffp)") ); SaveParameters(filename); } void QmitkFiberGenerationView::LoadParameters() { QString filename = QFileDialog::getOpenFileName(0, tr("Load Parameters"), QString(itksys::SystemTools::GetFilenamePath(m_ParameterFile.toStdString()).c_str()), tr("Fiberfox Parameters (*.ffp)") ); if(filename.isEmpty() || filename.isNull()) return; m_ParameterFile = filename; m_Parameters.LoadParameters(filename.toStdString()); if (m_Parameters.m_MissingTags.size()>0) { QString missing("Parameter file might be corrupted. The following parameters could not be read: "); missing += QString(m_Parameters.m_MissingTags.c_str()); missing += "\nDefault values have been assigned to the missing parameters."; QMessageBox::information( nullptr, "Warning!", missing); } m_Controls->m_RealTimeFibers->setChecked(m_Parameters.m_Misc.m_CheckRealTimeFibersBox); m_Controls->m_AdvancedOptionsBox->setChecked(m_Parameters.m_Misc.m_CheckAdvancedFiberOptionsBox); m_Controls->m_IncludeFiducials->setChecked(m_Parameters.m_Misc.m_CheckIncludeFiducialsBox); m_Controls->m_ConstantRadiusBox->setChecked(m_Parameters.m_Misc.m_CheckConstantRadiusBox); m_Controls->m_DistributionBox->setCurrentIndex(m_Parameters.m_FiberGen.m_Distribution); m_Controls->m_VarianceBox->setValue(m_Parameters.m_FiberGen.m_Variance); m_Controls->m_FiberDensityBox->setValue(m_Parameters.m_FiberGen.m_Density); m_Controls->m_FiberSamplingBox->setValue(m_Parameters.m_FiberGen.m_Sampling); m_Controls->m_TensionBox->setValue(m_Parameters.m_FiberGen.m_Tension); m_Controls->m_ContinuityBox->setValue(m_Parameters.m_FiberGen.m_Continuity); m_Controls->m_BiasBox->setValue(m_Parameters.m_FiberGen.m_Bias); m_Controls->m_XrotBox->setValue(m_Parameters.m_FiberGen.m_Rotation[0]); m_Controls->m_YrotBox->setValue(m_Parameters.m_FiberGen.m_Rotation[1]); m_Controls->m_ZrotBox->setValue(m_Parameters.m_FiberGen.m_Rotation[2]); m_Controls->m_XtransBox->setValue(m_Parameters.m_FiberGen.m_Translation[0]); m_Controls->m_YtransBox->setValue(m_Parameters.m_FiberGen.m_Translation[1]); m_Controls->m_ZtransBox->setValue(m_Parameters.m_FiberGen.m_Translation[2]); m_Controls->m_XscaleBox->setValue(m_Parameters.m_FiberGen.m_Scale[0]); m_Controls->m_YscaleBox->setValue(m_Parameters.m_FiberGen.m_Scale[1]); m_Controls->m_ZscaleBox->setValue(m_Parameters.m_FiberGen.m_Scale[2]); } void QmitkFiberGenerationView::ShowAdvancedOptions(int state) { if (state) { m_Controls->m_AdvancedFiberOptionsFrame->setVisible(true); m_Controls->m_AdvancedOptionsBox->setChecked(true); } else { m_Controls->m_AdvancedFiberOptionsFrame->setVisible(false); m_Controls->m_AdvancedOptionsBox->setChecked(false); } } void QmitkFiberGenerationView::OnConstantRadius(int value) { if (value>0 && m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberGenerationView::OnDistributionChanged(int value) { if (value==1) m_Controls->m_VarianceBox->setVisible(true); else m_Controls->m_VarianceBox->setVisible(false); if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberGenerationView::OnVarianceChanged(double) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberGenerationView::OnFiberDensityChanged(int) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberGenerationView::OnFiberSamplingChanged(double) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberGenerationView::OnTensionChanged(double) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberGenerationView::OnContinuityChanged(double) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberGenerationView::OnBiasChanged(double) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberGenerationView::UpdateFiducialPosition() { if (m_SelectedFiducials.size()!=1) return; mitk::PlanarEllipse* pe = dynamic_cast(m_SelectedFiducials.at(0)->GetData()); mitk::BaseGeometry* geom = pe->GetGeometry(); // translate mitk::Point3D origin; origin[0] = m_Controls->m_FidPosX->value(); origin[1] = m_Controls->m_FidPosY->value(); origin[2] = m_Controls->m_FidPosZ->value(); // transform control point coordinate into geometry translation auto p0 = pe->GetControlPoint(0); auto p1 = pe->GetControlPoint(1); auto p2 = pe->GetControlPoint(2); auto p3 = pe->GetControlPoint(3); auto v1 = p1 - p0; auto v2 = p2 - p0; auto angle_deg = m_Controls->m_FidTwist->value(); auto dot = std::cos(itk::Math::pi*angle_deg/180.0); vnl_matrix_fixed tRot; tRot[0][0] = dot; tRot[1][1] = tRot[0][0]; tRot[1][0] = sin(acos(tRot[0][0])); tRot[0][1] = -tRot[1][0]; if (angle_deg<0) tRot = tRot.transpose(); vnl_vector_fixed vt; vt[0]=1; vt[1]=0; vnl_vector_fixed v3 = tRot*vt; if (v1.GetNorm()<0.0001 || v2.GetNorm()<0.0001) { QMessageBox::information( nullptr, "", "Please select exactly one fiducial."); return; } v1.Normalize(); v2.Normalize(); p1 = p0 + v1*m_Controls->m_FidAxis1->value(); p2 = p0 + v2*m_Controls->m_FidAxis2->value(); p3 = p0 + mitk::Vector2D(v3); pe->SetControlPoint(1, p1); pe->SetControlPoint(2, p2); pe->SetControlPoint(3, p3); geom->SetOrigin(origin); pe->Modified(); if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); UpdateGui(); } void QmitkFiberGenerationView::AlignOnGrid() { for (unsigned int i=0; i(m_SelectedFiducials.at(i)->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::DataStorage::SetOfObjects::ConstPointer parentFibs = GetDataStorage()->GetSources(m_SelectedFiducials.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = parentFibs->begin(); it != parentFibs->end(); ++it ) { mitk::DataNode::Pointer pFibNode = *it; if ( pFibNode.IsNotNull() && dynamic_cast(pFibNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer parentImgs = GetDataStorage()->GetSources(pFibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = parentImgs->begin(); it2 != parentImgs->end(); ++it2 ) { mitk::DataNode::Pointer pImgNode = *it2; if ( pImgNode.IsNotNull() && dynamic_cast(pImgNode->GetData()) ) { mitk::Image::Pointer img = dynamic_cast(pImgNode->GetData()); mitk::BaseGeometry::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); break; } } break; } } } for(unsigned int i=0; iGetSources(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it = sources->begin(); it != sources->end(); ++it ) { mitk::DataNode::Pointer imgNode = *it; if ( imgNode.IsNotNull() && dynamic_cast(imgNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = dynamic_cast(fiducialNode->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::Image::Pointer img = dynamic_cast(imgNode->GetData()); mitk::BaseGeometry::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); } } break; } } } for(unsigned int i=0; i(m_SelectedImages.at(i)->GetData()); mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(m_SelectedImages.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = derivations->begin(); it != derivations->end(); ++it ) { mitk::DataNode::Pointer fibNode = *it; if ( fibNode.IsNotNull() && dynamic_cast(fibNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer derivations2 = GetDataStorage()->GetDerivations(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations2->begin(); it2 != derivations2->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = dynamic_cast(fiducialNode->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::BaseGeometry::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); } } } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberGenerationView::OnFlipButton() { if (m_SelectedFiducial.IsNull()) return; std::map::iterator it = m_DataNodeToPlanarFigureData.find(m_SelectedFiducial.GetPointer()); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; data.m_Flipped += 1; data.m_Flipped %= 2; } if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberGenerationView::OnAddBundle() { if (m_SelectedImageNode.IsNull()) return; mitk::DataStorage::SetOfObjects::ConstPointer children = GetDataStorage()->GetDerivations(m_SelectedImageNode); mitk::FiberBundle::Pointer bundle = mitk::FiberBundle::New(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( bundle ); QString name = QString("Bundle_%1").arg(children->size()); node->SetName(name.toStdString()); m_SelectedBundles.push_back(node); UpdateGui(); GetDataStorage()->Add(node, m_SelectedImageNode); } void QmitkFiberGenerationView::OnDrawROI() { if (m_SelectedBundles.empty()) OnAddBundle(); if (m_SelectedBundles.empty()) return; mitk::DataStorage::SetOfObjects::ConstPointer children = GetDataStorage()->GetDerivations(m_SelectedBundles.at(0)); mitk::PlanarEllipse::Pointer figure = mitk::PlanarEllipse::New(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( figure ); node->SetBoolProperty("planarfigure.3drendering", true); node->SetBoolProperty("planarfigure.3drendering.fill", true); QList nodes = this->GetDataManagerSelection(); for( int i=0; iSetSelected(false); m_SelectedFiducial = node; QString name = QString("Fiducial_%1").arg(children->size()); node->SetName(name.toStdString()); node->SetSelected(true); this->DisableCrosshairNavigation(); mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(node->GetDataInteractor().GetPointer()); if(figureInteractor.IsNull()) { figureInteractor = mitk::PlanarFigureInteractor::New(); us::Module* planarFigureModule = us::ModuleRegistry::GetModule( "MitkPlanarFigure" ); figureInteractor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule ); figureInteractor->SetEventConfig( "PlanarFigureConfig.xml", planarFigureModule ); figureInteractor->SetDataNode( node ); } UpdateGui(); GetDataStorage()->Add(node, m_SelectedBundles.at(0)); } bool QmitkFiberGenerationView::CompareLayer(mitk::DataNode::Pointer i,mitk::DataNode::Pointer j) { int li = -1; i->GetPropertyValue("layer", li); int lj = -1; j->GetPropertyValue("layer", lj); return liGetSources(m_SelectedFiducial); for( mitk::DataStorage::SetOfObjects::const_iterator it = parents->begin(); it != parents->end(); ++it ) if(dynamic_cast((*it)->GetData())) m_SelectedBundles.push_back(*it); if (m_SelectedBundles.empty()) return; } UpdateParametersFromGui(); for (unsigned int i=0; iGetDerivations(m_SelectedBundles.at(i)); std::vector< mitk::DataNode::Pointer > childVector; for( mitk::DataStorage::SetOfObjects::const_iterator it = children->begin(); it != children->end(); ++it ) childVector.push_back(*it); std::sort(childVector.begin(), childVector.end(), CompareLayer); std::vector< mitk::PlanarEllipse::Pointer > fib; std::vector< unsigned int > flip; float radius = 1; int count = 0; for( std::vector< mitk::DataNode::Pointer >::const_iterator it = childVector.begin(); it != childVector.end(); ++it ) { mitk::DataNode::Pointer node = *it; if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { mitk::PlanarEllipse* ellipse = dynamic_cast(node->GetData()); if (m_Controls->m_ConstantRadiusBox->isChecked()) { ellipse->SetTreatAsCircle(true); mitk::Point2D c = ellipse->GetControlPoint(0); mitk::Point2D p = ellipse->GetControlPoint(1); mitk::Vector2D v = p-c; if (count==0) { radius = v.GetVnlVector().magnitude(); ellipse->SetControlPoint(1, p); ellipse->Modified(); } else { v.Normalize(); v *= radius; ellipse->SetControlPoint(1, c+v); ellipse->Modified(); } } fib.push_back(ellipse); std::map::iterator it = m_DataNodeToPlanarFigureData.find(node.GetPointer()); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; flip.push_back(data.m_Flipped); } else flip.push_back(0); } count++; } if (fib.size()>1) { m_Parameters.m_FiberGen.m_Fiducials.push_back(fib); m_Parameters.m_FiberGen.m_FlipList.push_back(flip); } else if (fib.size()>0) m_SelectedBundles.at(i)->SetData( mitk::FiberBundle::New() ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } itk::FibersFromPlanarFiguresFilter::Pointer filter = itk::FibersFromPlanarFiguresFilter::New(); filter->SetParameters(m_Parameters.m_FiberGen); filter->Update(); std::vector< mitk::FiberBundle::Pointer > fiberBundles = filter->GetFiberBundles(); for (unsigned int i=0; iSetData( fiberBundles.at(i) ); if (fiberBundles.at(i)->GetNumFibers()>50000) m_SelectedBundles.at(i)->SetVisibility(false); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberGenerationView::ApplyTransform() { std::vector< mitk::DataNode::Pointer > selectedBundles; for(unsigned int i=0; iGetDerivations(m_SelectedImages.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = derivations->begin(); it != derivations->end(); ++it ) { mitk::DataNode::Pointer fibNode = *it; if ( fibNode.IsNotNull() && dynamic_cast(fibNode->GetData()) ) selectedBundles.push_back(fibNode); } } if (selectedBundles.empty()) selectedBundles = m_SelectedBundles2; if (!selectedBundles.empty()) { for (std::vector::const_iterator it = selectedBundles.begin(); it!=selectedBundles.end(); ++it) { mitk::FiberBundle::Pointer fib = dynamic_cast((*it)->GetData()); fib->RotateAroundAxis(m_Controls->m_XrotBox->value(), m_Controls->m_YrotBox->value(), m_Controls->m_ZrotBox->value()); fib->TranslateFibers(m_Controls->m_XtransBox->value(), m_Controls->m_YtransBox->value(), m_Controls->m_ZtransBox->value()); fib->ScaleFibers(m_Controls->m_XscaleBox->value(), m_Controls->m_YscaleBox->value(), m_Controls->m_ZscaleBox->value()); // handle child fiducials if (m_Controls->m_IncludeFiducials->isChecked()) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse* pe = dynamic_cast(fiducialNode->GetData()); mitk::BaseGeometry* geom = pe->GetGeometry(); // translate mitk::Vector3D world; world[0] = m_Controls->m_XtransBox->value(); world[1] = m_Controls->m_YtransBox->value(); world[2] = m_Controls->m_ZtransBox->value(); geom->Translate(world); // calculate rotation matrix double x = m_Controls->m_XrotBox->value()*itk::Math::pi/180; double y = m_Controls->m_YrotBox->value()*itk::Math::pi/180; double z = m_Controls->m_ZrotBox->value()*itk::Math::pi/180; itk::Matrix< double, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; itk::Matrix< double, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; itk::Matrix< double, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< double, 3, 3 > rot = rotZ*rotY*rotX; // transform control point coordinate into geometry translation geom->SetOrigin(pe->GetWorldControlPoint(0)); mitk::Point2D cp; cp.Fill(0.0); pe->SetControlPoint(0, cp); // rotate fiducial geom->GetIndexToWorldTransform()->SetMatrix(rot*geom->GetIndexToWorldTransform()->GetMatrix()); // implicit translation mitk::Vector3D trans; trans[0] = geom->GetOrigin()[0]-fib->GetGeometry()->GetCenter()[0]; trans[1] = geom->GetOrigin()[1]-fib->GetGeometry()->GetCenter()[1]; trans[2] = geom->GetOrigin()[2]-fib->GetGeometry()->GetCenter()[2]; mitk::Vector3D newWc = rot*trans; newWc = newWc-trans; geom->Translate(newWc); pe->Modified(); } } } } } else { for (unsigned int i=0; i(m_SelectedFiducials.at(i)->GetData()); mitk::BaseGeometry* geom = pe->GetGeometry(); // translate mitk::Vector3D world; world[0] = m_Controls->m_XtransBox->value(); world[1] = m_Controls->m_YtransBox->value(); world[2] = m_Controls->m_ZtransBox->value(); geom->Translate(world); // calculate rotation matrix double x = m_Controls->m_XrotBox->value()*itk::Math::pi/180; double y = m_Controls->m_YrotBox->value()*itk::Math::pi/180; double z = m_Controls->m_ZrotBox->value()*itk::Math::pi/180; itk::Matrix< double, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; itk::Matrix< double, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; itk::Matrix< double, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< double, 3, 3 > rot = rotZ*rotY*rotX; // transform control point coordinate into geometry translation geom->SetOrigin(pe->GetWorldControlPoint(0)); mitk::Point2D cp; cp.Fill(0.0); pe->SetControlPoint(0, cp); // rotate fiducial geom->GetIndexToWorldTransform()->SetMatrix(rot*geom->GetIndexToWorldTransform()->GetMatrix()); pe->Modified(); } if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberGenerationView::CopyBundles() { if ( m_SelectedBundles.size()<1 ){ QMessageBox::information( nullptr, "Warning", "Select at least one fiber bundle!"); MITK_WARN("QmitkFiberGenerationView") << "Select at least one fiber bundle!"; return; } for (std::vector::const_iterator it = m_SelectedBundles.begin(); it!=m_SelectedBundles.end(); ++it) { // find parent image mitk::DataNode::Pointer parentNode; mitk::DataStorage::SetOfObjects::ConstPointer parentImgs = GetDataStorage()->GetSources(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = parentImgs->begin(); it2 != parentImgs->end(); ++it2 ) { mitk::DataNode::Pointer pImgNode = *it2; if ( pImgNode.IsNotNull() && dynamic_cast(pImgNode->GetData()) ) { parentNode = pImgNode; break; } } mitk::FiberBundle::Pointer fib = dynamic_cast((*it)->GetData()); mitk::FiberBundle::Pointer newBundle = fib->GetDeepCopy(); QString name((*it)->GetName().c_str()); name += "_copy"; mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); if (parentNode.IsNotNull()) GetDataStorage()->Add(fbNode, parentNode); else GetDataStorage()->Add(fbNode); // copy child fiducials if (m_Controls->m_IncludeFiducials->isChecked()) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = dynamic_cast(fiducialNode->GetData())->Clone(); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetData(pe); newNode->SetName(fiducialNode->GetName()); newNode->SetBoolProperty("planarfigure.3drendering", true); GetDataStorage()->Add(newNode, fbNode); } } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberGenerationView::JoinBundles() { if ( m_SelectedBundles.size()<2 ){ QMessageBox::information( nullptr, "Warning", "Select at least two fiber bundles!"); MITK_WARN("QmitkFiberGenerationView") << "Select at least two fiber bundles!"; return; } std::vector< mitk::FiberBundle::Pointer > to_add; std::vector::const_iterator it = m_SelectedBundles.begin(); (*it)->SetVisibility(false); mitk::FiberBundle::Pointer newBundle = dynamic_cast((*it)->GetData()); QString name(""); name += QString((*it)->GetName().c_str()); ++it; for (; it!=m_SelectedBundles.end(); ++it) { (*it)->SetVisibility(false); to_add.push_back(dynamic_cast((*it)->GetData())); } newBundle = newBundle->AddBundles(to_add); mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName("Joined"); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberGenerationView::UpdateGui() { m_Controls->m_FiberGenMessage->setVisible(true); m_Controls->m_TransformBundlesButton->setEnabled(false); m_Controls->m_CopyBundlesButton->setEnabled(false); m_Controls->m_GenerateFibersButton->setEnabled(false); m_Controls->m_FlipButton->setEnabled(false); m_Controls->m_CircleButton->setEnabled(false); m_Controls->m_JoinBundlesButton->setEnabled(false); m_Controls->m_AlignOnGrid->setEnabled(false); m_Controls->m_FiducialAttributeBox->setEnabled(false); // Fiber generation gui if (m_SelectedFiducial.IsNotNull()) { m_Controls->m_TransformBundlesButton->setEnabled(true); m_Controls->m_FlipButton->setEnabled(true); m_Controls->m_AlignOnGrid->setEnabled(true); } if (m_SelectedFiducials.size()==1) { m_Controls->m_FiducialAttributeBox->setEnabled(true); mitk::PlanarEllipse* pe = dynamic_cast(m_SelectedFiducials.at(0)->GetData()); auto origin = pe->GetGeometry()->GetOrigin(); m_Controls->m_FidPosX->setValue(origin[0]); m_Controls->m_FidPosY->setValue(origin[1]); m_Controls->m_FidPosZ->setValue(origin[2]); auto p0 = pe->GetControlPoint(0); auto p1 = pe->GetControlPoint(1); auto p2 = pe->GetControlPoint(2); auto p3 = pe->GetControlPoint(3); auto v1 = p1 - p0; auto v2 = p2 - p0; m_Controls->m_FidAxis1->setValue(v1.GetNorm()); m_Controls->m_FidAxis2->setValue(v2.GetNorm()); vnl_vector_fixed vt; vt[0]=1; vt[1]=0; auto v3 = p3-p0; v3.Normalize(); auto angle = dot_product(vt, v3.GetVnlVector()); angle = std::acos(angle)*180.0/itk::Math::pi; if (v3[1]<0) angle *= -1; m_Controls->m_FidTwist->setValue(angle); } else { m_Controls->m_FidPosX->setValue(0); m_Controls->m_FidPosY->setValue(0); m_Controls->m_FidPosZ->setValue(0); m_Controls->m_FidAxis1->setValue(1); m_Controls->m_FidAxis2->setValue(1); m_Controls->m_FidTwist->setValue(0); } if (m_SelectedImageNode.IsNotNull() || !m_SelectedBundles.empty()) { m_Controls->m_CircleButton->setEnabled(true); m_Controls->m_FiberGenMessage->setVisible(false); } if (m_SelectedImageNode.IsNotNull() && !m_SelectedBundles.empty()) m_Controls->m_AlignOnGrid->setEnabled(true); if (!m_SelectedBundles.empty()) { m_Controls->m_TransformBundlesButton->setEnabled(true); m_Controls->m_CopyBundlesButton->setEnabled(true); m_Controls->m_GenerateFibersButton->setEnabled(true); if (m_SelectedBundles.size()>1) m_Controls->m_JoinBundlesButton->setEnabled(true); } } void QmitkFiberGenerationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& nodes) { m_SelectedBundles2.clear(); m_SelectedImages.clear(); m_SelectedFiducials.clear(); m_SelectedFiducial = nullptr; m_SelectedBundles.clear(); m_SelectedImageNode = nullptr; // iterate all selected objects, adjust warning visibility for( int i=0; i(node->GetData()) ) { m_SelectedImages.push_back(node); m_SelectedImageNode = node; } else if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_SelectedBundles2.push_back(node); if (m_Controls->m_RealTimeFibers->isChecked()) { m_SelectedBundles.push_back(node); mitk::FiberBundle::Pointer newFib = dynamic_cast(node->GetData()); if (newFib->GetNumFibers()!=static_cast(m_Controls->m_FiberDensityBox->value())) GenerateFibers(); } else m_SelectedBundles.push_back(node); } else if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_SelectedFiducials.push_back(node); m_SelectedFiducial = node; m_SelectedBundles.clear(); mitk::DataStorage::SetOfObjects::ConstPointer parents = GetDataStorage()->GetSources(node); for( mitk::DataStorage::SetOfObjects::const_iterator it = parents->begin(); it != parents->end(); ++it ) { mitk::DataNode::Pointer pNode = *it; if ( pNode.IsNotNull() && dynamic_cast(pNode->GetData()) ) m_SelectedBundles.push_back(pNode); } } } UpdateGui(); } void QmitkFiberGenerationView::EnableCrosshairNavigation() { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberGenerationView::DisableCrosshairNavigation() { } void QmitkFiberGenerationView::NodeRemoved(const mitk::DataNode* node) { mitk::DataNode* nonConstNode = const_cast(node); std::map::iterator it = m_DataNodeToPlanarFigureData.find(nonConstNode); if (dynamic_cast(node->GetData())) { m_SelectedBundles.clear(); m_SelectedBundles2.clear(); } else if (dynamic_cast(node->GetData())) m_SelectedImages.clear(); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; // remove observers data.m_Figure->RemoveObserver( data.m_EndPlacementObserverTag ); data.m_Figure->RemoveObserver( data.m_SelectObserverTag ); data.m_Figure->RemoveObserver( data.m_StartInteractionObserverTag ); data.m_Figure->RemoveObserver( data.m_EndInteractionObserverTag ); m_DataNodeToPlanarFigureData.erase( it ); } } void QmitkFiberGenerationView::NodeAdded( const mitk::DataNode* node ) { // add observer for selection in renderwindow mitk::PlanarFigure* figure = dynamic_cast(node->GetData()); bool isPositionMarker (false); node->GetBoolProperty("isContourMarker", isPositionMarker); if( figure && !isPositionMarker ) { MITK_DEBUG << "figure added. will add interactor if needed."; mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(node->GetDataInteractor().GetPointer()); mitk::DataNode* nonConstNode = const_cast( node ); if(figureInteractor.IsNull()) { figureInteractor = mitk::PlanarFigureInteractor::New(); us::Module* planarFigureModule = us::ModuleRegistry::GetModule( "MitkPlanarFigure" ); figureInteractor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule ); figureInteractor->SetEventConfig( "PlanarFigureConfig.xml", planarFigureModule ); figureInteractor->SetDataNode( nonConstNode ); } MITK_DEBUG << "will now add observers for planarfigure"; QmitkPlanarFigureData data; data.m_Figure = figure; // // add observer for event when figure has been placed typedef itk::SimpleMemberCommand< QmitkFiberGenerationView > SimpleCommandType; // SimpleCommandType::Pointer initializationCommand = SimpleCommandType::New(); // initializationCommand->SetCallbackFunction( this, &QmitkFiberGenerationView::PlanarFigureInitialized ); // data.m_EndPlacementObserverTag = figure->AddObserver( mitk::EndPlacementPlanarFigureEvent(), initializationCommand ); // add observer for event when figure is picked (selected) typedef itk::MemberCommand< QmitkFiberGenerationView > MemberCommandType; MemberCommandType::Pointer selectCommand = MemberCommandType::New(); selectCommand->SetCallbackFunction( this, &QmitkFiberGenerationView::PlanarFigureSelected ); data.m_SelectObserverTag = figure->AddObserver( mitk::SelectPlanarFigureEvent(), selectCommand ); // add observer for event when interaction with figure starts SimpleCommandType::Pointer startInteractionCommand = SimpleCommandType::New(); startInteractionCommand->SetCallbackFunction( this, &QmitkFiberGenerationView::DisableCrosshairNavigation); data.m_StartInteractionObserverTag = figure->AddObserver( mitk::StartInteractionPlanarFigureEvent(), startInteractionCommand ); // add observer for event when interaction with figure starts SimpleCommandType::Pointer endInteractionCommand = SimpleCommandType::New(); endInteractionCommand->SetCallbackFunction( this, &QmitkFiberGenerationView::EnableCrosshairNavigation); data.m_EndInteractionObserverTag = figure->AddObserver( mitk::EndInteractionPlanarFigureEvent(), endInteractionCommand ); m_DataNodeToPlanarFigureData[nonConstNode] = data; } } void QmitkFiberGenerationView::PlanarFigureSelected( itk::Object* object, const itk::EventObject& ) { mitk::TNodePredicateDataType::Pointer isPf = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer allPfs = this->GetDataStorage()->GetSubset( isPf ); for ( mitk::DataStorage::SetOfObjects::const_iterator it = allPfs->begin(); it!=allPfs->end(); ++it) { mitk::DataNode* node = *it; if( node->GetData() == object ) { node->SetSelected(true); m_SelectedFiducial = node; } else node->SetSelected(false); } UpdateGui(); this->RequestRenderWindowUpdate(); } void QmitkFiberGenerationView::SetFocus() { m_Controls->m_CircleButton->setFocus(); }