5 #include <vnl/algo/vnl_determinant.h> 6 #include <vnl/algo/vnl_real_eigensystem.h> 7 #include <vnl/algo/vnl_matrix_inverse.h> 8 #include <vnl/vnl_inverse.h> 9 #include <itkPoolMultiThreader.h> 13 template <
class T> vnl_matrix <T>
GetSquareRoot(
const vnl_matrix <T> & m,
const double precision, vnl_matrix <T> & resultM)
18 unsigned int D = m.rows();
20 vnl_matrix <T> Mk1(D,D), Mk(D,D), Yk1(D,D), Yk(D,D), interm(D,D), invMk(D,D), Id(D,D);
30 energy=interm.frobenius_norm();
37 while( (niter <= niterMax) && (energy > precision) )
39 T gamma=(T)fabs(pow(vnl_determinant(Mk),-1.0/(2.0*n)));
40 vnl_matrix_inverse <T> inverter(Mk);
41 invMk= inverter.inverse();
42 Mk1=(Id+ (Mk*(gamma*gamma)+invMk*(1./(gamma*gamma)) )*0.5 )*0.5;
43 Yk1=Yk*(Id+invMk*(1./(gamma*gamma)) )*0.5*gamma;
50 energy=interm.frobenius_norm();
53 if (niter == niterMax)
55 std::cout <<
"\nWarning, max number of iteration reached in sqrt computation. Final energy is:" << energy <<
".\n";
65 template <
class T> vnl_matrix <T>
GetPadeLogarithm(
const vnl_matrix <T> & m,
const int numApprox)
67 unsigned int D = m.rows();
70 vnl_matrix <T> Id(D,D);
72 vnl_matrix <T> diff(D,D),interm2(D,D),interm3(D,D),sqr(D,D),cube(D,D);
75 T energy=diff.frobenius_norm();
79 std::cout <<
"Warning, matrix is not close enough to Id to call Pade approximation. Frobenius Distance=" << energy <<
". Returning original matrix.\n";
88 interm3=(Id-diff*0.5);
94 interm2=diff*(-1.0)+sqr*(0.5);
95 interm3=(Id-diff+sqr);
102 interm2=diff*(-1.0)+sqr+cube*(11.0/60.0);
103 interm3=(Id-diff*(1.5)+sqr*0.6+cube*(-0.05));
110 std::cout <<
"\n\ndefault is taken in log Pade\n\n";
111 interm2=diff*(-1.0)+sqr+cube*(11.0/60.0);
112 interm3=(Id-diff*(1.5)+sqr*0.6+cube*(-0.05));
116 log=interm2 * vnl_inverse(interm3);
145 template <
class T> vnl_matrix <T>
GetLogarithm(
const vnl_matrix <T> & m,
const double precision,
const int numApprox)
147 unsigned int D = m.rows();
151 vnl_matrix <double> log=m;
153 vnl_matrix <double> Id(D,D);
155 vnl_matrix <double> interm(D,D),Yi(D,D),Yi1(D,D),resultM(D,D);
156 vnl_matrix <double> matrix_sum=m;
158 int niterMax=60;
int niter=1;
162 energy=interm.frobenius_norm();
165 while ( (energy > 0.5) && (niter <= niterMax))
171 if ((!std::isfinite(resultM(0,0))) || (!std::isfinite(Yi(0,0))))
177 matrix_sum+= (Id-resultM)*factor;
181 energy=interm.frobenius_norm();
188 if (!std::isfinite(log(0,0)))
194 return log*factor+matrix_sum;
198 template <
class T> vnl_matrix <T>
GetExponential(
const vnl_matrix <T> & m,
const int numApprox)
200 unsigned int D = m.rows();
203 vnl_matrix <T> exp=m;
204 vnl_matrix <T> Id(D,D); Id.set_identity();
205 vnl_matrix <T> interm(D,D),interm2(D,D),interm3(D,D),sqr(D,D),cube(D,D);
207 T norm=m.frobenius_norm();
212 k=1 + (int) ceil(log(m.frobenius_norm())/log(2.0));
225 factor=pow(2.0,(
double) k);
232 interm2=Id+interm*0.5;
233 interm3=Id-interm*0.5;
239 interm2=Id+interm*0.5+sqr*(1.0/12.0);
240 interm3=Id-interm*0.5+sqr*(1.0/12.0);
247 interm2=Id+interm*0.5+sqr*(1.0/10.0)+cube*(1.0/120.0);
248 interm3=Id-interm*0.5+sqr*(1.0/10.0)-cube*(1.0/120.0);;
252 std::cout <<
"\n\ndefault is taken in exp Pade\n\n";
257 interm2=Id+interm*0.5+sqr*(1.0/10.0)+cube*(1.0/120.0);
258 interm3=Id-interm*0.5+sqr*(1.0/10.0)-cube*(1.0/120.0);;
262 interm=interm2 * vnl_inverse(interm3);
264 for(
int i=1;i<=k;i++)
274 const unsigned int dataDim = 3;
275 if (outputAngles.size() < dataDim)
276 outputAngles.resize(dataDim);
278 double rotationTrace = 0;
279 for (
unsigned int i = 0;i < dataDim;++i)
280 rotationTrace += rotationMatrix(i,i);
282 double cTheta = (rotationTrace - 1.0) / 2.0;
283 double theta = std::acos(cTheta);
284 double sTheta = std::sin(theta);
286 unsigned int pos = 0;
287 for (
int i = dataDim - 1;i >= 0;--i)
289 for (
int j = dataDim - 1;j > i;--j)
291 outputAngles[pos] = theta * (rotationMatrix(i,j) - rotationMatrix(j,i)) / (2.0 * sTheta);
293 outputAngles[pos] *= -1;
302 const unsigned int dataDim = 3;
303 outputRotation.set_size(dataDim,dataDim);
304 outputRotation.set_identity();
306 double thetaValue = 0;
307 for (
unsigned int i = 0;i < dataDim;++i)
308 thetaValue += angles[i] * angles[i];
313 double sqrtTheta = std::sqrt(thetaValue);
314 double firstAddConstant = std::sin(sqrtTheta) / sqrtTheta;
315 double secondAddConstant = (1.0 - std::cos(sqrtTheta)) / thetaValue;
317 for (
unsigned int i = 0;i < dataDim;++i)
319 for (
unsigned int j = 0;j < dataDim;++j)
323 outputRotation(i,i) -= secondAddConstant * angles[j] * angles[j];
324 outputRotation(i,j) += secondAddConstant * angles[i] * angles[j];
330 unsigned int pos = dataDim - 1;
331 for (
unsigned int i = 0;i < dataDim;++i)
333 for (
unsigned int j = i + 1;j < dataDim;++j)
335 if ((i + j) % 2 != 0)
337 outputRotation(i,j) -= angles[pos] * firstAddConstant;
338 outputRotation(j,i) += angles[pos] * firstAddConstant;
342 outputRotation(i,j) += angles[pos] * firstAddConstant;
343 outputRotation(j,i) -= angles[pos] * firstAddConstant;
352 template <
class TInputScalarType,
class TOutputScalarType,
unsigned int NDimensions,
unsigned int NDegreesOfFreedom>
360 m_Output.resize(m_InputTransforms.size());
362 itk::PoolMultiThreader::Pointer threaderLog = itk::PoolMultiThreader::New();
367 unsigned int actualNumberOfThreads = std::min(m_NumberOfThreads,(
unsigned int)m_InputTransforms.size());
370 threaderLog->SetSingleMethod(this->ThreadedLogging,tmpStr);
371 threaderLog->SingleMethodExecute();
378 template <
class TInputScalarType,
class TOutputScalarType,
unsigned int NDimensions,
unsigned int NDegreesOfFreedom>
379 ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION
383 itk::MultiThreaderBase::WorkUnitInfo *threadArgs = (itk::MultiThreaderBase::WorkUnitInfo *)arg;
385 unsigned int nbThread = threadArgs->WorkUnitID;
386 unsigned int nbProcs = threadArgs->NumberOfWorkUnits;
392 return ITK_THREAD_RETURN_DEFAULT_VALUE;
395 template <
class TInputScalarType,
class TOutputScalarType,
unsigned int NDimensions,
unsigned int NDegreesOfFreedom>
400 unsigned step = m_InputTransforms.size()/numThreads;
402 unsigned startTrsf = threadId*step;
403 unsigned endTrsf = (1+threadId)*step;
405 if (threadId+1==numThreads)
406 endTrsf = m_InputTransforms.size();
408 typename BaseInputMatrixTransformType::MatrixType affinePart;
409 itk::Vector <TInputScalarType,NDimensions> offsetPart;
410 vnl_matrix <TInputScalarType> tmpMatrix(NDimensions+1,NDimensions+1,0), logMatrix(NDimensions+1,NDimensions+1,0);
411 tmpMatrix(NDimensions,NDimensions) = 1;
413 for (
unsigned int i = startTrsf; i < endTrsf; ++i)
416 affinePart = tmpTrsf->GetMatrix();
417 offsetPart = tmpTrsf->GetOffset();
419 for (
unsigned int j = 0;j < NDimensions;++j)
421 tmpMatrix(j,NDimensions) = offsetPart[j];
422 for (
unsigned int k = 0;k < NDimensions;++k)
423 tmpMatrix(j,k) = affinePart(j,k);
428 unsigned int pos = 0;
429 if (m_UseRigidTransforms)
431 for (
unsigned int j = 0;j < NDimensions;++j)
433 for (
unsigned int k = j+1;k < NDimensions;++k)
435 m_Output[i][pos] = logMatrix(j,k);
440 for (
unsigned int j = 0;j < NDimensions;++j)
442 m_Output[i][pos] = logMatrix(j,NDimensions);
449 for (
unsigned int j = 0;j < NDimensions;++j)
451 for (
unsigned int k = 0;k <= NDimensions;++k)
453 m_Output[i][pos] = logMatrix(j,k);
void SetNumberOfWorkUnits(unsigned int &numThreads)
void Get3DRotationLogarithm(const vnl_matrix< T > &rotationMatrix, std::vector< T > &outputAngles)
Computation of a 3D rotation matrix logarithm. Rodrigues' explicit formula.
vnl_matrix< T > GetExponential(const vnl_matrix< T > &m, const int numApprox=1)
Computation of the matrix exponential. Algo: classical scaling and squaring, as in Matlab...
void InternalLogger(unsigned int threadId, unsigned int numThreads)
vnl_matrix< T > GetLogarithm(const vnl_matrix< T > &m, const double precision=0.00000000001, const int numApprox=1)
Computation of the matrix logarithm. Algo: inverse scaling and squaring, variant proposed by Cheng et...
static ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION ThreadedLogging(void *arg)
void Get3DRotationExponential(const std::vector< T > &angles, vnl_matrix< T > &outputRotation)
Computation of a 3D rotation matrix exponential. Rodrigues' explicit formula.
itk::MatrixOffsetTransformBase< TInputScalarType, NDimensions, NDimensions > BaseInputMatrixTransformType
vnl_matrix< T > GetPadeLogarithm(const vnl_matrix< double > &m, const int numApprox)
Final part of the computation of the log. Estimates the log with a Pade approximation for a matrix m ...
vnl_matrix< T > GetSquareRoot(const vnl_matrix< T > &m, const double precision, vnl_matrix< T > &resultM)
Gets the square root of matrix m.