7 #include "PlusConfigure.h" 11 #include "vtkObjectFactory.h" 15 #include "vtkTransform.h" 16 #include "vtkIGSIOTransformRepository.h" 17 #include "vtkXMLUtilities.h" 19 #include "vtksys/SystemTools.hxx" 21 #include "itkPowellOptimizer.h" 22 #include "itkScaleVersor3DTransform.h" 23 #include "itkSimilarity3DTransform.h" 28 class DistanceToWiresCostFunction :
public itk::SingleValuedCostFunction
32 typedef DistanceToWiresCostFunction Self;
33 typedef itk::SingleValuedCostFunction Superclass;
34 typedef itk::SmartPointer<Self> Pointer;
35 typedef itk::SmartPointer<const Self> ConstPointer;
37 itkTypeMacro( DistanceToWiresCostFunction, SingleValuedCostFunction );
39 typedef Superclass::ParametersType ParametersType;
40 typedef Superclass::DerivativeType DerivativeType;
41 typedef itk::VersorRigid3DTransform< double > RigidTransformType;
43 DistanceToWiresCostFunction()
44 : m_CalibrationOptimizer(NULL)
50 m_CalibrationOptimizer=calibrationOptimizer;
53 static PlusStatus GetTransformMatrix(vnl_matrix_fixed<double,4,4>& imageToProbeTransform_vnl,
const ParametersType & imageToProbeTransformParameters)
55 imageToProbeTransform_vnl.set_identity();
57 if (imageToProbeTransformParameters.GetSize()!=7 && imageToProbeTransformParameters.GetSize()!=8)
59 LOG_ERROR(
"GetTransformMatrix expects 7 or 8 parameters");
63 auto rigidTransform=RigidTransformType::New();
64 rigidTransform->SetParameters(imageToProbeTransformParameters);
65 imageToProbeTransform_vnl.update(rigidTransform->GetMatrix().GetVnlMatrix());
66 imageToProbeTransform_vnl.put(0,3,rigidTransform->GetOffset()[0]);
67 imageToProbeTransform_vnl.put(1,3,rigidTransform->GetOffset()[1]);
68 imageToProbeTransform_vnl.put(2,3,rigidTransform->GetOffset()[2]);
70 bool isotropicPixelSpacing=(imageToProbeTransformParameters.GetSize()==7);
71 if (isotropicPixelSpacing)
74 imageToProbeTransform_vnl.scale_column(0,imageToProbeTransformParameters(6));
75 imageToProbeTransform_vnl.scale_column(1,imageToProbeTransformParameters(6));
76 imageToProbeTransform_vnl.scale_column(2,imageToProbeTransformParameters(6));
81 imageToProbeTransform_vnl.scale_column(0,imageToProbeTransformParameters(6));
82 imageToProbeTransform_vnl.scale_column(1,imageToProbeTransformParameters(7));
83 imageToProbeTransform_vnl.scale_column(2,(imageToProbeTransformParameters(6)+imageToProbeTransformParameters(7))/2);
88 static PlusStatus GetTransformParameters(ParametersType& imageToProbeTransformParameters,
const vnl_matrix_fixed<double,4,4>& imageToProbeTransform_vnl)
90 if (imageToProbeTransformParameters.GetSize()!=7 && imageToProbeTransformParameters.GetSize()!=8)
92 LOG_ERROR(
"GetTransformMatrix expects 7 or 8 parameters");
97 vnl_matrix_fixed<double,3,3> rotationMatrix= imageToProbeTransform_vnl.extract(3,3);
98 vnl_svd<double> svd(rotationMatrix);
99 itk::Matrix<double,3,3> orthogonalizedRotationMatrix;
100 orthogonalizedRotationMatrix = svd.U() * svd.V().transpose();
101 double scale[3] = { svd.W(0), svd.W(1), svd.W(2) };
104 auto imageToProbeTransformRigid = RigidTransformType::New();
105 imageToProbeTransformRigid->SetMatrix(orthogonalizedRotationMatrix );
106 RigidTransformType::ParametersType rigidParameters=imageToProbeTransformRigid->GetParameters();
107 imageToProbeTransformParameters[0]=rigidParameters[0];
108 imageToProbeTransformParameters[1]=rigidParameters[1];
109 imageToProbeTransformParameters[2]=rigidParameters[2];
112 imageToProbeTransformParameters[3]=imageToProbeTransform_vnl.get(0,3);
113 imageToProbeTransformParameters[4]=imageToProbeTransform_vnl.get(1,3);
114 imageToProbeTransformParameters[5]=imageToProbeTransform_vnl.get(2,3);
117 bool isotropicPixelSpacing=(imageToProbeTransformParameters.GetSize()==7);
118 if (isotropicPixelSpacing)
120 imageToProbeTransformParameters[6]=(scale[0]+scale[1])/2.0;
124 imageToProbeTransformParameters[6]=scale[0];
125 imageToProbeTransformParameters[7]=scale[1];
130 double GetValue(
const ParametersType & imageToProbeTransformParameters )
const 132 vnl_matrix_fixed<double,4,4> imageToProbeTransform_vnl;
133 GetTransformMatrix(imageToProbeTransform_vnl, imageToProbeTransformParameters);
134 double errorMean=0.0;
135 double errorStDev=0.0;
137 m_CalibrationOptimizer->ComputeError(imageToProbeTransform_vnl, errorMean, errorStDev, errorRms);
141 void GetDerivative(
const ParametersType & parameters, DerivativeType & derivative )
const 143 LOG_ERROR(
"GetDerivative is not implemented");
146 unsigned int GetNumberOfParameters(
void)
const 148 if (m_CalibrationOptimizer->GetIsotropicPixelSpacing())
167 : IsotropicPixelSpacing(true)
168 , ProbeCalibrationAlgo(NULL)
195 LOG_ERROR(
"Invalid cost function");
202 LOG_INFO(
"Translation = [" << imageToProbeTransformationMatrix.get(0,3) <<
" " << imageToProbeTransformationMatrix.get(1,3) <<
" " << imageToProbeTransformationMatrix.get(2,3) <<
" ]");
204 vnl_matrix_fixed<double,3,3> rotationMatrix=imageToProbeTransformationMatrix.extract(3,3);
205 vnl_svd<double> svd(rotationMatrix);
206 vnl_matrix<double> orthogonalizedRotationMatrix;
207 orthogonalizedRotationMatrix = svd.U() * svd.V().transpose();
208 double scale[3] = { svd.W(0), svd.W(1), svd.W(2) };
209 LOG_INFO(
"Scale = [" << scale[0] <<
" " << scale[1] <<
" " << scale[2] <<
" ]");
211 vnl_vector<double> xAxis=imageToProbeTransformationMatrix.get_column(0);
213 vnl_vector<double> yAxis=imageToProbeTransformationMatrix.get_column(1);
215 double xyAxesAngleDeg=vtkMath::DegreesFromRadians(acos(dot_product(xAxis,yAxis)));
216 LOG_INFO(
"XY axes angle = " << xyAxesAngleDeg <<
" deg");
218 double errorMean=0.0;
219 double errorStDev=0.0;
221 ComputeError(imageToProbeTransformationMatrix, errorMean, errorStDev, errorRms);
222 LOG_INFO(
"Error (mm): mean=" << errorMean<<
", stdev="<<errorStDev<<
", rms="<<errorRms);
230 DistanceToWiresCostFunction::Pointer costFunction =
new DistanceToWiresCostFunction(
this);
232 DistanceToWiresCostFunction::ParametersType imageToProbeSeedTransformParameters(costFunction->GetNumberOfParameters());
235 double errorMean=0.0;
236 double errorStDev=0.0;
239 LOG_INFO(
"Initial cost function value with unconstrained matrix = " << errorRms );
241 vtkSmartPointer<vtkMatrix4x4> vtkMatrix=vtkSmartPointer<vtkMatrix4x4>::New();
243 igsioMath::LogVtkMatrix(vtkMatrix);
246 double initialError=costFunction->GetValue(imageToProbeSeedTransformParameters);
247 LOG_INFO(
"Initial cost function value with constrained matrix= " << initialError );
249 vnl_matrix_fixed<double,4,4> imageToProbeTransform_vnl;
250 DistanceToWiresCostFunction::GetTransformMatrix(imageToProbeTransform_vnl, imageToProbeSeedTransformParameters);
251 vtkSmartPointer<vtkMatrix4x4> vtkMatrix=vtkSmartPointer<vtkMatrix4x4>::New();
253 igsioMath::LogVtkMatrix(vtkMatrix);
256 auto optimizer = OptimizerType::New();
259 optimizer->SetCostFunction( costFunction.GetPointer() );
261 catch( itk::ExceptionObject & e )
263 LOG_ERROR(
"Exception thrown ! An error ocurred during Optimization: "<<e);
267 optimizer->SetStepLength( 10 );
268 optimizer->SetStepTolerance( 1e-8 );
269 optimizer->SetValueTolerance( 1e-8 );
270 optimizer->SetMaximumIteration( 300 );
273 const double rotationParametersScale=1.0;
274 const double translationParametersScale=0.5;
275 const double scalesParametersScale=10.0;
278 OptimizerType::ScalesType scales( costFunction->GetNumberOfParameters() );
279 switch (costFunction->GetNumberOfParameters())
282 scales[0] = rotationParametersScale;
283 scales[1] = rotationParametersScale;
284 scales[2] = rotationParametersScale;
285 scales[3] = translationParametersScale;
286 scales[4] = translationParametersScale;
287 scales[5] = translationParametersScale;
288 scales[6] = scalesParametersScale;
291 scales[0] = rotationParametersScale;
292 scales[1] = rotationParametersScale;
293 scales[2] = rotationParametersScale;
294 scales[3] = translationParametersScale;
295 scales[4] = translationParametersScale;
296 scales[5] = translationParametersScale;
297 scales[6] = scalesParametersScale;
298 scales[7] = scalesParametersScale;
301 LOG_ERROR(
"Number of transformation parameters is incorrect");
304 optimizer->SetScales(scales);
306 optimizer->SetInitialPosition(imageToProbeSeedTransformParameters);
310 optimizer->StartOptimization();
312 catch( itk::ExceptionObject & e )
314 LOG_ERROR(
"Exception thrown ! An error ocurred during Optimization: Location = " << e.GetLocation() <<
"Description = " << e.GetDescription());
318 std::string stopCondition=optimizer->GetStopConditionDescription();
319 LOG_INFO(
"Optimization stopping condition: "<<stopCondition<<
". Number of iterations: " << optimizer->GetCurrentIteration());
325 vtkSmartPointer<vtkMatrix4x4> vtkMatrix=vtkSmartPointer<vtkMatrix4x4>::New();
327 igsioMath::LogVtkMatrix(vtkMatrix);
333 LOG_INFO(
"Without optimization:");
336 LOG_INFO(
"With optimization:");
339 vtkSmartPointer<vtkMatrix4x4> imageToProbeSeedTransformMatrixVtk = vtkSmartPointer<vtkMatrix4x4>::New();
340 vtkSmartPointer<vtkMatrix4x4> imageToProbeTransformMatrixVtk = vtkSmartPointer<vtkMatrix4x4>::New();
343 double angleDifference = igsioMath::GetOrientationDifference(imageToProbeSeedTransformMatrixVtk, imageToProbeTransformMatrixVtk);
344 LOG_INFO(
"Orientation difference between unoptimized and optimized matrices = " << angleDifference <<
" deg");
381 LOG_ERROR(
"Unknown cost function to perform calibration: "<<type);
389 LOG_TRACE(
"vtkPlusProbeCalibrationOptimizerAlgo::ReadConfiguration");
390 if ( aConfig == NULL )
392 LOG_ERROR(
"Unable to read configuration");
397 const char* optimizationMethod=aConfig->GetAttribute(
"OptimizationMethod");
398 if (optimizationMethod==NULL)
Refines the image to probe transform using non-linear optimization.
void ComputeError2d(const vnl_matrix_fixed< double, 4, 4 > &imageToProbeMatrix, double &errorMean, double &errorStDev, double &errorRms)
static const char * GetOptimizationMethodAsString(OptimizationMethodType type)
void SetImageToProbeSeedTransform(const vnl_matrix_fixed< double, 4, 4 > &imageToProbeTransformMatrix)
void SetProbeCalibrationAlgo(vtkPlusProbeCalibrationAlgo *probeCalibrationAlgo)
vtkPlusProbeCalibrationOptimizerAlgo()
virtual ~vtkPlusProbeCalibrationOptimizerAlgo()
PlusStatus ShowTransformation(const vnl_matrix_fixed< double, 4, 4 > &transformationMatrix)
vnl_matrix_fixed< double, 4, 4 > GetOptimizedImageToProbeTransformMatrix()
vtkStandardNewMacro(vtkPlusProbeCalibrationOptimizerAlgo)
void ComputeError(const vnl_matrix_fixed< double, 4, 4 > &imageToProbeTransformationMatrix, double &errorMean, double &errorStDev, double &errorRms)
itk::PowellOptimizer OptimizerType
bool IsotropicPixelSpacing
vnl_matrix_fixed< double, 4, 4 > ImageToProbeTransformMatrix
void ComputeError3d(const vnl_matrix_fixed< double, 4, 4 > &imageToProbeMatrix, double &errorMean, double &errorStDev, double &errorRms)
vnl_matrix_fixed< double, 4, 4 > ImageToProbeSeedTransformMatrix
PlusStatus ReadConfiguration(vtkXMLDataElement *aConfig)
vtkPlusProbeCalibrationAlgo * ProbeCalibrationAlgo
static void ConvertVnlMatrixToVtkMatrix(const vnl_matrix_fixed< double, 4, 4 > &inVnlMatrix, vtkMatrix4x4 *outVtkMatrix)
OptimizationMethodType OptimizationMethod
Probe calibration algorithm class.