First integration of Automatic Registration is running (on Approve button). There is in this commit soem confusion and changes in the DRR writing for testing with Alex

This commit is contained in:
Proton local user
2022-12-21 16:15:58 +01:00
parent 62aee70510
commit 3af6066e4f
5 changed files with 749 additions and 43 deletions

View File

@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 2.8.12)
SET(LIB_NAME itkDTRrecon) SET(LIB_NAME itkDTRrecon)
add_subdirectory(autoreg)
find_package(ITK REQUIRED) find_package(ITK REQUIRED)
include(${ITK_USE_FILE}) include(${ITK_USE_FILE})
INCLUDE_DIRECTORIES(${ITK_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${ITK_INCLUDE_DIRS})
@ -34,6 +36,7 @@ SET(LINK_LIBS
${VTK_LIBRARIES} ${VTK_LIBRARIES}
${ITK_LIBRARIES} ${ITK_LIBRARIES}
gdcmMSFF gdcmMSFF
autoreg
) )
TARGET_LINK_LIBRARIES( TARGET_LINK_LIBRARIES(

View File

@ -531,6 +531,8 @@ TransformMetaInformation (){
m_CurrentTransform.Fill(0.); m_CurrentTransform.Fill(0.);
m_DegreeOfFreedom = tDegreeOfFreedomEnum::UNKNOWN;
} }
void void

View File

@ -11,15 +11,70 @@
namespace itk namespace itk
{ {
typedef enum eProjectionOrientationType typedef enum eProjectionOrientationType{
{NA = 0, LAT=2, PA=1} NA = 0,
tProjOrientationType; LAT=2,
PA=1
} tProjOrientationType;
/** Enum type for Orientation */ /** Enum type for Orientation */
typedef enum eImageOrientationType typedef enum eImageOrientationType{
{NotDefined = 0, HFS = 1, FFS = 2} NotDefined = 0,
tPatOrientation; HFS = 1,
FFS = 2
} tPatOrientation;
typedef enum eDegreeOfFreedomType {
UNKNOWN = 0,
THREE_DOF,
SIX_DOF,
X_ONLY,
Y_ONLY,
Z_ONLY,
ROTATION_ONLY,
OTHER
} tDegreeOfFreedomEnum;
inline int GetNumberOfDOF(eDegreeOfFreedomType dof)
{
switch (dof) {
case SIX_DOF:
return 6;
break;
case THREE_DOF:
case ROTATION_ONLY:
return 3;
break;
case X_ONLY:
case Y_ONLY:
case Z_ONLY:
return 1;
break;
default:
return 0;
}
}
class DegreeOfFreedom : public itk::Object {
public:
typedef DegreeOfFreedom Self;
typedef itk::Object Superclass;
typedef itk::SmartPointer<Self> Pointer;
itkNewMacro(Self);
protected:
bool
m_TranslationX,
m_TranslationY,
m_TranslationZ,
m_RotationX,
m_RotationY,
m_RotationZ;
tDegreeOfFreedomEnum m_dof;
};
class TopogramImageMetaInformation : class TopogramImageMetaInformation :
public itk::Object{ public itk::Object{
@ -490,6 +545,8 @@ public:
itkSetMacro(CurrentTransform,TransformMatrixType); itkSetMacro(CurrentTransform,TransformMatrixType);
itkGetMacro(CurrentTransform,TransformMatrixType); itkGetMacro(CurrentTransform,TransformMatrixType);
itkSetEnumMacro(DegreeOfFreedom, tDegreeOfFreedomEnum);
itkGetEnumMacro(DegreeOfFreedom, tDegreeOfFreedomEnum);
protected: protected:
@ -503,6 +560,8 @@ protected:
m_ReferenceTransform, m_ReferenceTransform,
m_CurrentTransform; m_CurrentTransform;
tDegreeOfFreedomEnum
m_DegreeOfFreedom;
/** Default Constructor **/ /** Default Constructor **/
TransformMetaInformation (); TransformMetaInformation ();

View File

@ -14,6 +14,7 @@ gfattori 08.11.2021
#include "itkImageProcessor.h" #include "itkImageProcessor.h"
#include "itkCreateObjectFunction.h" #include "itkCreateObjectFunction.h"
#include "itkDRTHelpers.h"
#include "itkVersion.h" #include "itkVersion.h"
#include <gdcmReader.h> #include <gdcmReader.h>
#include <itkMatrix.h> #include <itkMatrix.h>
@ -24,6 +25,8 @@ gfattori 08.11.2021
#include "itkOrientImageFilter.h" #include "itkOrientImageFilter.h"
#include <gdcmIPPSorter.h> #include <gdcmIPPSorter.h>
#include "itkTimeProbesCollectorBase.h"
#include <string> #include <string>
@ -31,34 +34,6 @@ gfattori 08.11.2021
namespace itk namespace itk
{ {
/* this is in the end a IEC to HFS...
* but we keep this for ourselves...
*/
static double Standard_DRT2LPS [9] = {
1,0,0,
0,0,-1,
0,1,0 };
static double PAElementsIEC[9] = {
1, 0, 0,
0, -1, 0,
0, 0, -1 };
static double LATElementsIEC[9] = {
0, 0, -1,
0, -1, 0,
-1, 0, 0};
static double HFS2IEC[9] = {
1, 0, 0,
0, 0, 1,
0, -1, 0};
static double FFS2IEC[9] = {
-1, 0, 0,
0, 0, -1,
0, -1, 0};
//FUNCTION DECLARATION NECESSARY FOR COPY/PASTE FROM vtkGDCMImageReader //FUNCTION DECLARATION NECESSARY FOR COPY/PASTE FROM vtkGDCMImageReader
// const char *gGetStringValueFromTag(const gdcm::Tag& t, const gdcm::DataSet& ds); // const char *gGetStringValueFromTag(const gdcm::Tag& t, const gdcm::DataSet& ds);
@ -97,6 +72,8 @@ itkImageProcessor::itkImageProcessor()
// TZero[0]=TZero[1]=TZero[2]=0.; // TZero[0]=TZero[1]=TZero[2]=0.;
// RZero[0]=RZero[1]=RZero[2]=0.; // RZero[0]=RZero[1]=RZero[2]=0.;
toVTK2D1 = ITKtoVTKFilterType::New(); toVTK2D1 = ITKtoVTKFilterType::New();
toVTK2D2 = ITKtoVTKFilterType::New(); toVTK2D2 = ITKtoVTKFilterType::New();
toVTKLocalizer1 = ITKtoVTKFilterType::New(); toVTKLocalizer1 = ITKtoVTKFilterType::New();
@ -217,7 +194,37 @@ itkImageProcessor::itkImageProcessor()
// }; // };
// setup the Automatic Registration
metric = MetricType::New();
mimetric = MIMetricType::New();
optimizer = OptimizerType::New();
amoebaoptimizer = AmoebaOptimizerType::New();
optimizerObserver = CommandIterationUpdate::New();
exhaustiveOptimizer = ExhaustiveOptimizerType::New();
exhaustiveOptimizerObserver = ExhaustiveCommandIterationUpdate::New();
registration = RegistrationType::New();
if (m_UseMutualInformation) {
registration->SetMetric(mimetric);
} else {
registration->SetMetric(metric);
}
registration->SetOptimizer(optimizer);
registration->SetTransform1(transform1);
registration->SetTransform2(transform2);
registration->SetInterpolator1(interpolator1);
registration->SetInterpolator2(interpolator2);
m_UseExhaustiveOptmizer = false; //if the exhaustive optimizer shal be used, ovverrides ameoba
m_UseAmeobaOptimizer = false; //if the ameoba optimzer shall be used, otherwise Powell. Overriden by Exhaustive option.
m_UseFullROI = true; // if the full image ROI shall be used
m_UseMutualInformation = false; //oterwise NCC is used
m_UseDumptoFile = false; //If each (!) optimzer result shall be dumpped into a file.
} }
itkImageProcessor::~itkImageProcessor() itkImageProcessor::~itkImageProcessor()
@ -257,6 +264,17 @@ double itkImageProcessor::GetSCD2(){
m_DRTImage1MetaInfo ->GetSCD(); m_DRTImage1MetaInfo ->GetSCD();
} }
void itkImageProcessor::SetDegreeOfFreedom(tDegreeOfFreedomEnum dof)
{
m_TransformMetaInfo->SetDegreeOfFreedom(dof);
}
tDegreeOfFreedomEnum
itkImageProcessor::GetDegreeOfFreedom()
{
return m_TransformMetaInfo->GetDegreeOfFreedom();
}
void itkImageProcessor::SetCustom_ImportTransform(double dTx, void itkImageProcessor::SetCustom_ImportTransform(double dTx,
double dTy, double dTy,
double dTz, double dTz,
@ -384,8 +402,6 @@ void itkImageProcessor::SetCustom_2Dsize(int nX1, int nY1,int nX2,int nY2)
void itkImageProcessor::SetCustom_UpdateMetaInfo(){ void itkImageProcessor::SetCustom_UpdateMetaInfo(){
this->UpdateProjectionGeometryMeta(); this->UpdateProjectionGeometryMeta();
} }
@ -1254,6 +1270,35 @@ itkImageProcessor::MapTransformToNewOrigin(
return m_OutputTransform; return m_OutputTransform;
} }
// This External User Transform thing need to be checked out
void itkImageProcessor::CalculateExternalUserTransform(TransformType::Pointer transform, DRTImageMetaInformation::Pointer imageMetaInfo)
{
//crude hack to get from internal transform in LPS to external transform in IEC.
//result is stored in m_TransformMetaInfo
//TODO: support for projectionTransformCenter and userTransformCenter which are not the same
//currentlz we support only pFakeIsoLPS situations.
InternalImageType::DirectionType LPStoIEC_Directions;
LPStoIEC_Directions = m_CTMetaInfo->GetLPS2IECDirections();
auto parameters = transform->GetParameters();
ImageType3D::PointType translationUser;
translationUser[0] = parameters[3];
translationUser[1] = parameters[4];
translationUser[2] = parameters[5];
ImageType3D::PointType rotationUser;
rotationUser[0] = parameters[0];
rotationUser[1] = parameters[1];
rotationUser[2] = parameters[2];
m_TransformMetaInfo->SetUserTranslations(LPStoIEC_Directions * translationUser);
m_TransformMetaInfo->SetUserRotations(LPStoIEC_Directions * rotationUser);
}
itkImageProcessor::TransformType::Pointer itkImageProcessor::TransformType::Pointer
itkImageProcessor::CalculateInternalTransform( itkImageProcessor::CalculateInternalTransform(
ImageType3D::PointType m_TranslationOffset, //IEC ImageType3D::PointType m_TranslationOffset, //IEC
@ -1323,6 +1368,362 @@ itkImageProcessor::CalculateInternalTransform(
m_OutputTransform; m_OutputTransform;
} }
void itkImageProcessor::InitializeRegistration(int maximumIteration, double stepLength, double maxTranslation, eDegreeOfFreedomType dof)
{
std::cout << "*" << __COMPACT_PRETTY_FUNCTION__ << std::endl;
if (!m_PASourceDupli) {
itkExceptionMacro(<< "PA topogram not present");
}
if (!m_LATSourceDupli) {
itkExceptionMacro(<< "LAT topogram not present");
}
if (!m_VolumeSourceDupli) {
itkExceptionMacro(<< "CT data not present");
}
metric->ComputeGradientOff();
metric->SetSubtractMean(true);
metric->SetMaxTranslation(maxTranslation);
m_TransformMetaInfo->SetDegreeOfFreedom(dof);
mimetric->ComputeGradientOff();
if (verbose) {
metric->DebugOn();
}
registration->SetFixedImage1(m_PASourceDupli->GetOutput());
registration->SetFixedImage2(m_LATSourceDupli->GetOutput());
registration->SetMovingImage(m_VolumeSourceDupli->GetOutput());
//TODO: Here we could set the ROI for image registartion
auto region1 = m_PASourceDupli->GetOutput()->GetBufferedRegion();
auto region2 = m_LATSourceDupli->GetOutput()->GetBufferedRegion();
// bool setROI = false;
// if (setROI) {
// auto index1 = region1.GetIndex();
// auto size1 = region1.GetSize();
// auto point1 = m_PASourceDupli->GetOutput()->GetOrigin();
// index1[0] = size1[0] / 2 - 50;
// index1[1] = size1[1] / 2 - 50;
// size1[0] = 100;
// size1[1] = 100;
// size1[2] = 1;
// region1.SetIndex(index1);
// region1.SetSize(size1);
// }
registration->SetFixedImageRegion1(region1);
registration->SetFixedImageRegion2(region2);
registration->SetTransformMetaInfo(m_TransformMetaInfo);
registration->SetFilter1(filter1);
registration->SetFilter2(filter2);
//CalculateInternalTransform(transform1, m_DRTImage1MetaInfo);
/********* BEGIN CALCULATION OF INTERNAL TRANSFORM FOR PROJ1 *********/
ImageType3D::PointType ZeroPoint;
ZeroPoint.Fill(0.);
InternalImageType::DirectionType IECtoLPS_Directions;
IECtoLPS_Directions =
m_CTMetaInfo->GetLPS2IECDirections().GetTranspose();
TransformType::Pointer CurrTransform;
if(m_RTMetaInfo == NULL)
{
//AAAAAA TODOOOOO CERCA
ImageType3D::PointType pFakeIsoLPS =
m_DRTImage1MetaInfo->GetProjectionOriginLPS();
//ImageType3D::PointType pFakeIsoLPS =
// m_CTMetaInfo->GetProjectionOriginLPS(
// m_DRTGeometryMetaInfo->GetProjectionCenter1());
CurrTransform =
CalculateInternalTransform(
ZeroPoint,
ZeroPoint,
m_TransformMetaInfo->GetTranslations(),
m_TransformMetaInfo->GetRotations(),
m_DRTImage1MetaInfo->GetProjectionOriginLPS(),
pFakeIsoLPS,
ZeroPoint,
IECtoLPS_Directions
);
} else {
CurrTransform =
CalculateInternalTransform(
ZeroPoint ,
m_DRTGeometryMetaInfo->GetIECS2IECScannerR(),
m_TransformMetaInfo->GetTranslations(),
m_TransformMetaInfo->GetRotations(),
m_DRTImage1MetaInfo->GetProjectionOriginLPS(),
m_RTMetaInfo->GetIsocenterLPS() - m_CTMetaInfo->GetImportOffset(),
m_CTMetaInfo->GetImportOffset(),
IECtoLPS_Directions
);
}
transform1->SetComputeZYX(true);
transform1->SetIdentity();
transform1->SetTranslation(
CurrTransform->GetTranslation());
transform1->SetRotation(
CurrTransform->GetAngleX(),
CurrTransform->GetAngleY(),
CurrTransform->GetAngleZ()
);
transform1->SetCenter(
m_DRTImage1MetaInfo->GetProjectionOriginLPSZero() );
/********* END OF CALCULATE INTERNAL TRANSFORM FOR PROJ1 *********/
//CalculateInternalTransform(transform2, m_DRTImage2MetaInfo);
/********* BEGIN CALCULATION OF INTERNAL TRANSFORM FOR PROJ2 *********/
if(m_RTMetaInfo == NULL)
{
ImageType3D::PointType pFakeIsoLPS =
m_DRTImage2MetaInfo->GetProjectionOriginLPS();
//ImageType3D::PointType pFakeIsoLPS =
// m_CTMetaInfo->GetProjectionOriginLPS(
// m_DRTGeometryMetaInfo->GetProjectionCenter2());
CurrTransform =
CalculateInternalTransform(
ZeroPoint,
ZeroPoint,
m_TransformMetaInfo->GetTranslations(),
m_TransformMetaInfo->GetRotations(),
m_DRTImage2MetaInfo->GetProjectionOriginLPS(),
pFakeIsoLPS,
ZeroPoint,
IECtoLPS_Directions
);
} else {
CurrTransform =
CalculateInternalTransform(
ZeroPoint ,
m_DRTGeometryMetaInfo->GetIECS2IECScannerR(),
m_TransformMetaInfo->GetTranslations(),
m_TransformMetaInfo->GetRotations(),
m_DRTImage2MetaInfo->GetProjectionOriginLPS(),
m_RTMetaInfo->GetIsocenterLPS() - m_CTMetaInfo->GetImportOffset(),
m_CTMetaInfo->GetImportOffset(),
IECtoLPS_Directions
);
}
transform2->SetComputeZYX(true);
transform2->SetIdentity();
transform2->SetTranslation(
CurrTransform->GetTranslation());
transform2->SetRotation(
CurrTransform->GetAngleX(),
CurrTransform->GetAngleY(),
CurrTransform->GetAngleZ()
);
transform2->SetCenter(
m_DRTImage2MetaInfo->GetProjectionOriginLPSZero() );
/********* END OF CALCULATE INTERNAL TRANSFORM FOR PROJ1 *********/
if (verbose) {
registration->DebugOn();
registration->Print(std::cout);
}
if (!m_UseExhaustiveOptmizer) {
if (!m_UseAmeobaOptimizer) {
// The metric will return 0 or a "large" negative number in case of high correspondence of the images
// Thus, we need to minimze
optimizer->SetMaximize(false); // for NCC and MI
optimizer->SetMaximumIteration(maximumIteration);
optimizer->SetMaximumLineIteration(4); // for Powell's method
optimizer->SetStepLength(stepLength);
optimizer->SetStepTolerance(0.01);
optimizer->SetValueTolerance(0.000002);
if (verbose) {
optimizer->DebugOn();
optimizer->Print(std::cout);
}
optimizer->RemoveAllObservers();
optimizer->AddObserver(itk::IterationEvent(), optimizerObserver);
registration->SetOptimizer(optimizer);
} else {
amoebaoptimizer->SetMinimize(true);
amoebaoptimizer->SetMaximumNumberOfIterations(100);
amoebaoptimizer->SetParametersConvergenceTolerance(0.1);
amoebaoptimizer->SetFunctionConvergenceTolerance(0.000002);
amoebaoptimizer->SetAutomaticInitialSimplex(false);
//Initial size of the simplex (otherwise it is a very small number and optimizer stops immeditaly)
// 2 mm / 2 degrees seems to be a good value which performs well.
OptimizerType::ParametersType simplexDelta(3);
int numberOfDOF = GetNumberOfDOF(dof);
if (numberOfDOF == 0) {
itkExceptionMacro(<< "Unkown or unsupported degree of freedom");
}
for (int i = 0; i < numberOfDOF; i++) {
simplexDelta[i] = 2.0;
}
amoebaoptimizer->SetInitialSimplexDelta(simplexDelta);
amoebaoptimizer->RemoveAllObservers();
amoebaoptimizer->AddObserver(itk::IterationEvent(), optimizerObserver);
registration->SetOptimizer(amoebaoptimizer);
}
} else {
//only support for 3DOF
const int numberOfSteps = 25; //In each direction. Total number of steps is ((2*numberOfSteps+1))^3. For 25 -> 132651.
const double stepLength = 0.1;
auto parameters = transform1->GetParameters();
transform1->SetParameters(parameters);
ExhaustiveOptimizerType::StepsType steps(3);
steps[0] = numberOfSteps;
steps[1] = numberOfSteps;
steps[2] = numberOfSteps;
exhaustiveOptimizer->SetNumberOfSteps(steps);
exhaustiveOptimizer->SetStepLength(stepLength);
exhaustiveOptimizer->RemoveAllObservers();
exhaustiveOptimizer->AddObserver(itk::IterationEvent(), exhaustiveOptimizerObserver);
exhaustiveOptimizer->SetStepLength(stepLength);
registration->SetOptimizer(exhaustiveOptimizer);
}
std::cout << "#" << __COMPACT_PRETTY_FUNCTION__ << std::endl;
}
int itkImageProcessor::StartRegistration(std::string extraInfo)
{
std::cout << "*" << __COMPACT_PRETTY_FUNCTION__ << std::endl;
// TODO: Check if the registartion pipeline has been initialized
using ParametersType = RegistrationType::ParametersType;
auto startParameters = transform1->GetParameters();
time_t t = time(0); // get time now
struct tm* now = localtime(&t);
bool useDumpToFile = false;
char buffer[255];
strftime(buffer, 255, "test-%F-%H%M%S.txt", now);
std::fstream fs;
if (useDumpToFile || m_UseExhaustiveOptmizer) {
fs.open(buffer, std::fstream::out);
fs << extraInfo;
fs << "Value\tX\tY\tZ " << std::endl;
if (m_UseExhaustiveOptmizer) {
exhaustiveOptimizerObserver->set_stream(fs);
}
}
// Start the registration
// ~~~~~~~~~~~~~~~~~~~~~~
// Create a timer to record calculation time.
itk::TimeProbesCollectorBase timer;
if (verbose) {
std::cout << "Starting the registration now..." << std::endl;
}
try {
timer.Start("Registration");
// Start the registration.
registration->StartRegistration();
timer.Stop("Registration");
} catch (itk::ExceptionObject& err) {
std::cout << "ExceptionObject caught !" << std::endl;
std::cout << err << std::endl;
return -1;
}
auto oldprecision = fs.precision();
if (m_UseExhaustiveOptmizer) {
fs.precision(std::numeric_limits<double>::digits10 + 2);
fs << " MinimumMetricValue: " << exhaustiveOptimizer->GetMinimumMetricValue() << std::endl;
fs << " MaximumMetricValue: " << exhaustiveOptimizer->GetMaximumMetricValue() << std::endl;
fs.precision(oldprecision);
fs << " MinimumMetricValuePosition: " << exhaustiveOptimizer->GetMinimumMetricValuePosition() << std::endl;
fs << " MaximumMetricValuePosition: " << exhaustiveOptimizer->GetMaximumMetricValuePosition() << std::endl;
fs << " StopConditionDescription: " << exhaustiveOptimizer->GetStopConditionDescription() << std::endl;
fs << " MaximumMetricValuePosition: " << exhaustiveOptimizer->GetMaximumMetricValuePosition() << std::endl;
} else if (useDumpToFile) {
fs.precision(std::numeric_limits<double>::digits10 + 2);
fs << " FinalMetricValue: " << optimizer->GetValue() << std::endl; //same as GetCurrentCost
fs.precision(oldprecision);
fs << " FinalPosition: " << optimizer->GetCurrentPosition() << std::endl;
fs << " Iterations: " << optimizer->GetCurrentIteration() << std::endl;
fs << " StopConditionDescription: " << optimizer->GetStopConditionDescription() << std::endl;
}
fs.close();
m_OptmizerValue = optimizer->GetValue();
auto finalParameters = transform1->GetParameters();
optimizer->GetCurrentPosition();
finalParameters = finalParameters - startParameters;
TransformType::Pointer offsetTransform = TransformType::New();
offsetTransform->SetParameters(finalParameters);
CalculateExternalUserTransform(offsetTransform, m_DRTImage1MetaInfo);
const double translationAlongX = finalParameters[3];
const double translationAlongY = finalParameters[4];
const double translationAlongZ = finalParameters[5];
const double rotationAlongX = finalParameters[0];
const double rotationAlongY = finalParameters[1];
const double rotationAlongZ = finalParameters[2];
const int numberOfIterations = optimizer->GetCurrentIteration();
std::cout << "Result = " << std::endl;
std::cout << " Rotation Along X = " << rotationAlongX / dtr << " deg" << std::endl;
std::cout << " Rotation Along Y = " << rotationAlongY / dtr << " deg" << std::endl;
std::cout << " Rotation Along Z = " << rotationAlongZ / dtr << " deg" << std::endl;
std::cout << " Translation X = " << translationAlongX << " mm" << std::endl;
std::cout << " Translation Y = " << translationAlongY << " mm" << std::endl;
std::cout << " Translation Z = " << translationAlongZ << " mm" << std::endl;
std::cout << " Number Of Iterations = " << numberOfIterations << std::endl;
std::cout << " Metric value = " << m_OptmizerValue << std::endl;
std::cout << "#" << __COMPACT_PRETTY_FUNCTION__ << std::endl;
return 0;
}
void itkImageProcessor::InitializeProjector() void itkImageProcessor::InitializeProjector()
{ {
@ -2643,6 +3044,85 @@ double* itkImageProcessor::GetTransformParameters(){
return dTransfParam; return dTransfParam;
} }
// Doubts about this user thing
void itkImageProcessor::GetFinalTranslations(double& dX, double& dY, double& dZ)
{
ImageType3D::PointType translations = m_TransformMetaInfo->GetTranslations();
ImageType3D::PointType userTranslations = m_TransformMetaInfo->GetUserTranslations();
dX = translations[0] + userTranslations[0];
dY = translations[1] + userTranslations[1];
dZ = translations[2] + userTranslations[2];
}
void itkImageProcessor::GetFinalRotations(double& dRX, double& dRY, double& dRZ)
{
ImageType3D::PointType rotations = m_TransformMetaInfo->GetRotations();
ImageType3D::PointType userRotations = m_TransformMetaInfo->GetUserRotations();
dRX = rotations[0] + userRotations[0];
dRY = rotations[1] + userRotations[1];
dRZ = rotations[2] + userRotations[2];
}
double itkImageProcessor::GetOptimizerValue()
{
return m_OptmizerValue;
}
double itkImageProcessor::GetCurrentMetricValue()
{
//Note: this fails if the metric has not been propperly initilzed.
if (!m_UseMutualInformation) {
if (metric == NULL) {
return nan("");
}
return metric->GetValue();
} else {
if (mimetric == NULL) {
return nan("");
}
return mimetric->GetValue();
}
}
void itkImageProcessor::SetROI(double, double, double, double)
{
//TODO: Not implemanted yet. ROI are hard coded and can be enabled using SetFullROI.
}
void itkImageProcessor::SetOptimizer(std::string optimizer)
{
if (optimizer.compare("Powell") == 0) {
m_UseAmeobaOptimizer = false;
m_UseExhaustiveOptmizer = false;
} else if (optimizer.compare("Amoeba") == 0) {
m_UseExhaustiveOptmizer = false;
m_UseAmeobaOptimizer = true;
} else if (optimizer.compare("Exhaustive") == 0) {
m_UseExhaustiveOptmizer = true;
m_UseAmeobaOptimizer = false;
} else {
itkExceptionMacro(<< "Unkown optimzer string : " << optimizer);
}
}
void itkImageProcessor::SetMetric(std::string metric)
{
if (metric.compare("NCC") == 0) {
m_UseMutualInformation = false;
} else if (metric.compare("MI") == 0) {
m_UseMutualInformation = true;
} else {
itkExceptionMacro(<< "Unkown metric string : " << optimizer);
}
}
void itkImageProcessor::SetFullROI(bool fullROI)
{
m_UseFullROI = fullROI;
// TODO: Remove this function when ROI functinalitz has been implemented.
}
} // end namespace itk } // end namespace itk

View File

@ -30,6 +30,13 @@ gfattori 08.11.2021
#include "itkObjectFactory.h" #include "itkObjectFactory.h"
#include "itkSmartPointer.h" #include "itkSmartPointer.h"
#include "itkExhaustiveOptimizer.h"
#include "itkMutualInformationTwoImageToOneImageMetric.h"
#include "itkNormalizedCorrelationTwoImageToOneImageMetric.h"
#include "itkPowellOptimizer.h"
#include "itkTwoProjectionImageRegistrationMethod.h"
#include "itkAmoebaOptimizer.h"
#include "itkImageToVTKImageFilter.h" #include "itkImageToVTKImageFilter.h"
#include "itkImageFileReader.h" #include "itkImageFileReader.h"
@ -46,13 +53,104 @@ gfattori 08.11.2021
namespace itk namespace itk
{ {
/* reference string required for comparison with tag values */
static const char *ImageOrientationStrings[] = { class CommandIterationUpdate : public itk::Command {
"NotDefined", // TODO: Move to own files.
"HFS",
"FFS" public:
using Self = CommandIterationUpdate;
using Superclass = itk::Command;
using Pointer = itk::SmartPointer<Self>;
itkNewMacro(Self);
protected:
CommandIterationUpdate() = default;
public:
using OptimizerType = itk::PowellOptimizer;
using OptimizerPointer = const OptimizerType*;
using AmoebaOptimizerType = itk::AmoebaOptimizer;
;
using AmoebaOptimizerPointer = const OptimizerType*;
void
Execute(itk::Object* caller, const itk::EventObject& event) override
{
Execute((const itk::Object*)caller, event);
}
void
Execute(const itk::Object* object, const itk::EventObject& event) override
{
auto optimizer = dynamic_cast<OptimizerPointer>(object);
if (typeid(event) == typeid(itk::IterationEvent)) {
//Feedback from the optimizer executed at the end of every itteration
// currently just print the result into the cout. We might add
// functionality to register and emit signals to update the UI.
std::cout << "Iteration: " << optimizer->GetCurrentIteration() << std::endl;
auto oldprecision = std::cout.precision();
std::cout.precision(std::numeric_limits<double>::digits10 + 2);
std::cout << "Similarity: " << optimizer->GetValue() << std::endl;
std::cout.precision(oldprecision);
std::cout << "Position: " << optimizer->GetCurrentPosition() << std::endl;
}
return;
}
}; };
class ExhaustiveCommandIterationUpdate : public itk::Command {
// TODO: Move to own files.
public:
using Self = ExhaustiveCommandIterationUpdate;
using Superclass = itk::Command;
using Pointer = itk::SmartPointer<Self>;
itkNewMacro(Self);
std::ostream* os;
protected:
ExhaustiveCommandIterationUpdate() = default;
public:
using OptimizerType = itk::ExhaustiveOptimizer;
;
using OptimizerPointer = const OptimizerType*;
void set_stream(std::ostream& stream)
{
os = &stream;
}
void
Execute(itk::Object* caller, const itk::EventObject& event) override
{
Execute((const itk::Object*)caller, event);
}
void
Execute(const itk::Object* object, const itk::EventObject& event) override
{
auto optimizer = dynamic_cast<OptimizerPointer>(object);
if (typeid(event) == typeid(itk::IterationEvent)) {
//crude LPS to IEC transform for HFS.
auto position = optimizer->GetCurrentPosition();
auto oldprecision = os->precision();
os->precision(std::numeric_limits<double>::digits10 + 2);
*os << optimizer->GetCurrentValue();
os->precision(oldprecision);
*os << "\t" << position[0] << "\t" << position[2] << "\t" << -position[1] << std::endl;
}
return;
}
};
class ITK_EXPORT itkImageProcessor : public itk::Object class ITK_EXPORT itkImageProcessor : public itk::Object
{ {
@ -97,6 +195,10 @@ public:
double GetSCD1(); double GetSCD1();
double GetSCD2(); double GetSCD2();
/** Sets the degree of freedom for omptimzation*/
void SetDegreeOfFreedom(tDegreeOfFreedomEnum);
tDegreeOfFreedomEnum GetDegreeOfFreedom();
void SetCustom_ProjectionCenterOffsetFixedAxes_IEC(double,double,double,double,double,double); void SetCustom_ProjectionCenterOffsetFixedAxes_IEC(double,double,double,double,double,double);
void SetCustom_ProjectionCenterFixedAxes_IEC(double,double,double); void SetCustom_ProjectionCenterFixedAxes_IEC(double,double,double);
@ -117,6 +219,19 @@ public:
void SetInitialTranslations(double, double, double); void SetInitialTranslations(double, double, double);
void SetInitialRotations(double, double, double); void SetInitialRotations(double, double, double);
/** Get transform parameters for 3D Volume */
void GetFinalTranslations(double&, double&, double&);
void GetFinalRotations(double&, double&, double&);
/** Set user transform parameters for 3D Volume in LPS*/
void SetUserTranslationsLPS(double, double, double);
void SetUserRotationsLPS(double, double, double);
/** Initialize the registration pipeline*/
void InitializeRegistration(int, double, double, eDegreeOfFreedomType);
/** Start the registration process*/
int StartRegistration(std::string extraInfo);
/** Get transform parameters for 3D Volume */ /** Get transform parameters for 3D Volume */
double* GetTransformParameters(); double* GetTransformParameters();
@ -129,8 +244,6 @@ public:
/** Get Projection origin in LPS coordinates*/ /** Get Projection origin in LPS coordinates*/
const std::vector <double> GetRTImportOffset(); const std::vector <double> GetRTImportOffset();
/** Get the Localizer intensity window and /** Get the Localizer intensity window and
* center for rendering */ * center for rendering */
double GetLocalizerDisplayWindowLevel(int ); double GetLocalizerDisplayWindowLevel(int );
@ -153,6 +266,17 @@ public:
void WriteProjectionImages(); void WriteProjectionImages();
void Write2DImages(); void Write2DImages();
/** Get the current cost function value from the optimizer*/
double GetOptimizerValue();
/** Get the cost function value for the current transform*/
double GetCurrentMetricValue();
void SetROI(double, double, double, double);
void SetOptimizer(std::string);
void SetMetric(std::string);
void SetFullROI(bool);
protected: protected:
@ -189,6 +313,16 @@ private:
using InterpolatorType = itk::gSiddonJacobsRayCastInterpolateImageFunction<InternalImageType, double>; using InterpolatorType = itk::gSiddonJacobsRayCastInterpolateImageFunction<InternalImageType, double>;
using ResampleFilterType = itk::ResampleImageFilter<InternalImageType, InternalImageType>; using ResampleFilterType = itk::ResampleImageFilter<InternalImageType, InternalImageType>;
/** Optimizer which tries to find the minimn (Powell Optimizer)*/
using OptimizerType = itk::PowellOptimizer;
using AmoebaOptimizerType = itk::AmoebaOptimizer;
/** Optimizer which samples the whol space */
using ExhaustiveOptimizerType = itk::ExhaustiveOptimizer;
/** Metric to calculate similarites between images*/
using MetricType = itk::NormalizedCorrelationTwoImageToOneImageMetric<InternalImageType, InternalImageType>;
using MIMetricType = itk::MutualInformationTwoImageToOneImageMetric<InternalImageType, InternalImageType>;
/** The thing which actuall does the image registration*/
using RegistrationType = itk::TwoProjectionImageRegistrationMethod<InternalImageType, InternalImageType>;
/** Image reader types */ /** Image reader types */
using ImageReaderType2D = itk::ImageFileReader<ImageType2D>; using ImageReaderType2D = itk::ImageFileReader<ImageType2D>;
@ -206,6 +340,8 @@ private:
/** ITK to VTK filter */ /** ITK to VTK filter */
using ITKtoVTKFilterType = itk::ImageToVTKImageFilter<OutputImageType>; using ITKtoVTKFilterType = itk::ImageToVTKImageFilter<OutputImageType>;
void
CalculateExternalUserTransform(TransformType::Pointer transform, DRTImageMetaInformation::Pointer imageMetaInfo);
TransformType::Pointer TransformType::Pointer
CalculateInternalTransform( CalculateInternalTransform(
@ -239,6 +375,23 @@ private:
imageDRT1In, imageDRT1In,
imageDRT2In; imageDRT2In;
RegistrationType::Pointer
registration;
MetricType::Pointer
metric;
MIMetricType::Pointer
mimetric;
OptimizerType::Pointer
optimizer;
AmoebaOptimizerType::Pointer
amoebaoptimizer;
CommandIterationUpdate::Pointer
optimizerObserver;
ExhaustiveOptimizerType::Pointer
exhaustiveOptimizer;
ExhaustiveCommandIterationUpdate::Pointer
exhaustiveOptimizerObserver;
DuplicatorType::Pointer DuplicatorType::Pointer
m_LATSourceDupli, m_LATSourceDupli,
m_PASourceDupli, m_PASourceDupli,
@ -335,6 +488,15 @@ private:
TransformMetaInformation::Pointer TransformMetaInformation::Pointer
m_TransformMetaInfo; m_TransformMetaInfo;
double m_OptmizerValue;
bool m_UseExhaustiveOptmizer;
bool m_UseAmeobaOptimizer;
bool m_UseFullROI;
bool m_UseMutualInformation;
bool m_UseDumptoFile;
}; };