From e637da91cee206a946ca51e07eb9e15ea94de162 Mon Sep 17 00:00:00 2001 From: StaronC Date: Fri, 15 Mar 2024 18:10:20 +0100 Subject: [PATCH] Created TriangleDeformationUtils.cpp file for methods than are common to all commands and transformed to functions. Added reading of correlation mask from MMVI for initialisation with MMVI, along with a class for triangulation nodes and serialising them. Helped auto-completion and hid rarely used command options. New command ComputeNodesPrecision is implemented. --- MMVII/include/MMVII_DeclareAllCmd.h | 5 +- MMVII/include/MMVII_PhgrDist.h | 4 - MMVII/include/MMVII_TplSymbTriangle.h | 2 +- MMVII/src/Appli/cSpecMMVII_Appli.cpp | 9 +- .../ApplyDelaunayOnRandomGeneratedPoints.cpp | 248 ++--- .../ComputeNodesPrecision.cpp | 190 ++++ .../MeshDisplacement/ComputeNodesPrecision.h | 86 ++ .../SerialiseTriangleDeformation.cpp | 115 +++ .../SerialiseTriangleDeformation.h | 56 ++ .../MeshDisplacement/TriangleDeformation.cpp | 873 ++++++------------ .../MeshDisplacement/TriangleDeformation.h | 225 ++--- .../TriangleDeformationRad.cpp | 405 -------- .../MeshDisplacement/TriangleDeformationRad.h | 92 -- .../TriangleDeformationRadiometry.cpp | 397 ++++---- .../TriangleDeformationRadiometry.h | 80 +- .../TriangleDeformationTrRad.cpp | 583 ------------ .../TriangleDeformationTrRad.h | 113 --- .../TriangleDeformationTranslation.cpp | 537 ++++++----- .../TriangleDeformationTranslation.h | 130 +-- .../TriangleDeformationUtils.cpp | 804 ++++++++++++++++ .../TriangleDeformationUtils.h | 206 +++++ .../src/SymbDerGen/Formulas_TrianglesDeform.h | 133 +-- MMVII/src/SymbDerGen/GenerateCodes.cpp | 12 - 23 files changed, 2574 insertions(+), 2731 deletions(-) create mode 100644 MMVII/src/MeshDisplacement/ComputeNodesPrecision.cpp create mode 100644 MMVII/src/MeshDisplacement/ComputeNodesPrecision.h create mode 100644 MMVII/src/MeshDisplacement/SerialiseTriangleDeformation.cpp create mode 100644 MMVII/src/MeshDisplacement/SerialiseTriangleDeformation.h delete mode 100644 MMVII/src/MeshDisplacement/TriangleDeformationRad.cpp delete mode 100644 MMVII/src/MeshDisplacement/TriangleDeformationRad.h delete mode 100644 MMVII/src/MeshDisplacement/TriangleDeformationTrRad.cpp delete mode 100644 MMVII/src/MeshDisplacement/TriangleDeformationTrRad.h create mode 100644 MMVII/src/MeshDisplacement/TriangleDeformationUtils.cpp create mode 100644 MMVII/src/MeshDisplacement/TriangleDeformationUtils.h diff --git a/MMVII/include/MMVII_DeclareAllCmd.h b/MMVII/include/MMVII_DeclareAllCmd.h index 2048c1d161..057d32e542 100755 --- a/MMVII/include/MMVII_DeclareAllCmd.h +++ b/MMVII/include/MMVII_DeclareAllCmd.h @@ -82,12 +82,12 @@ extern cSpecMMVII_Appli TheSpec_ConvertV1V2_GCPIM; extern cSpecMMVII_Appli TheSpec_SpecSerial; extern cSpecMMVII_Appli TheSpec_CGPReport; extern cSpecMMVII_Appli TheSpec_TiePReport; +extern cSpecMMVII_Appli TheSpec_SimulDispl; extern cSpecMMVII_Appli TheSpec_RandomGeneratedDelaunay; extern cSpecMMVII_Appli TheSpec_ComputeTriangleDeformation; -extern cSpecMMVII_Appli TheSpec_ComputeTriangleDeformationTrRad; extern cSpecMMVII_Appli TheSpec_ComputeTriangleDeformationTranslation; extern cSpecMMVII_Appli TheSpec_ComputeTriangleDeformationRadiometry; -extern cSpecMMVII_Appli TheSpec_ComputeTriangleDeformationRad; +extern cSpecMMVII_Appli TheSpec_ComputeNodesPrecision; extern cSpecMMVII_Appli TheSpec_PoseCmpReport; extern cSpecMMVII_Appli TheSpec_BlockCamInit; // RIGIDBLOC extern cSpecMMVII_Appli TheSpec_ClinoInit; @@ -95,7 +95,6 @@ extern cSpecMMVII_Appli TheSpecRename; extern cSpecMMVII_Appli TheSpec_V2ImportCalib; extern cSpecMMVII_Appli TheSpec_ImportOri; extern cSpecMMVII_Appli TheSpecDicoRename; -extern cSpecMMVII_Appli TheSpec_SimulDispl; extern cSpecMMVII_Appli TheSpec_CreateRTL; extern cSpecMMVII_Appli TheSpec_TestProj; extern cSpecMMVII_Appli TheSpec_ChSysCo; diff --git a/MMVII/include/MMVII_PhgrDist.h b/MMVII/include/MMVII_PhgrDist.h index 698fb2d8db..3300a7076b 100755 --- a/MMVII/include/MMVII_PhgrDist.h +++ b/MMVII/include/MMVII_PhgrDist.h @@ -200,14 +200,10 @@ NS_SymbolicDerivative::cCalculator * EqDeformImHomotethy(bool WithDerive NS_SymbolicDerivative::cCalculator * EqDeformImLinearGradHomotethy(bool WithDerive,int aSzBuf); /// Equation used to optimize translation and radiometry transformation between two images. NS_SymbolicDerivative::cCalculator *EqDeformTri(bool WithDerive, int aSzBuf); -/// Equation used to optimize translation and radiometry transformation between two images with alternative equation -NS_SymbolicDerivative::cCalculator *EqDeformTriTrRad(bool WithDerive, int aSzBuf); /// Equation used to optimize translation transformation between two images. NS_SymbolicDerivative::cCalculator *EqDeformTriTranslation(bool WithDerive, int aSzBuf); /// Equation used to optimize radiometric transformation between two images. NS_SymbolicDerivative::cCalculator *EqDeformTriRadiometry(bool WithDerive, int aSzBuf); -/// Equation used to optimize radiometric transformation between two images with alternate equation -NS_SymbolicDerivative::cCalculator *EqDeformTriRad(bool WithDerive, int aSzBuf); // ............. Covariance propagation ............. diff --git a/MMVII/include/MMVII_TplSymbTriangle.h b/MMVII/include/MMVII_TplSymbTriangle.h index d13757a48b..49e33e603c 100644 --- a/MMVII/include/MMVII_TplSymbTriangle.h +++ b/MMVII/include/MMVII_TplSymbTriangle.h @@ -7,7 +7,7 @@ #include "MMVII_Ptxd.h" #include "MMVII_Geom2D.h" -#include "../src/MeshDisplacement/TriangleDeformation.h" +#include "../src/MeshDisplacement/TriangleDeformationUtils.h" /** \file MMVII_TplSymbTriangle.h diff --git a/MMVII/src/Appli/cSpecMMVII_Appli.cpp b/MMVII/src/Appli/cSpecMMVII_Appli.cpp index a1d1cc607d..223ce003b3 100755 --- a/MMVII/src/Appli/cSpecMMVII_Appli.cpp +++ b/MMVII/src/Appli/cSpecMMVII_Appli.cpp @@ -176,8 +176,8 @@ std::vector & cSpecMMVII_Appli::InternVecAll() TheVecAll.push_back(&TheSpecCalcDiscIm); TheVecAll.push_back(&TheSpecCalcDescPCar); TheVecAll.push_back(&TheSpecMatchTieP); - TheVecAll.push_back(&TheSpec_TiePConv); - TheVecAll.push_back(&TheSpec_ToTiePMul); + TheVecAll.push_back(&TheSpec_TiePConv); + TheVecAll.push_back(&TheSpec_ToTiePMul); TheVecAll.push_back(&TheSpecEpipGenDenseMatch); TheVecAll.push_back(&TheSpecEpipDenseMatchEval); TheVecAll.push_back(&TheSpecGenSymbDer); @@ -234,17 +234,16 @@ std::vector & cSpecMMVII_Appli::InternVecAll() TheVecAll.push_back(&TheSpec_V2ImportCalib); TheVecAll.push_back(&TheSpec_ImportOri); TheVecAll.push_back(&TheSpecDicoRename); - TheVecAll.push_back(&TheSpec_SimulDispl); TheVecAll.push_back(&TheSpec_CreateRTL); TheVecAll.push_back(&TheSpec_TestProj); TheVecAll.push_back(&TheSpec_ChSysCo); TheVecAll.push_back(&TheSpec_CreateCalib); + TheVecAll.push_back(&TheSpec_SimulDispl); TheVecAll.push_back(&TheSpec_RandomGeneratedDelaunay); TheVecAll.push_back(&TheSpec_ComputeTriangleDeformation); - TheVecAll.push_back(&TheSpec_ComputeTriangleDeformationTrRad); TheVecAll.push_back(&TheSpec_ComputeTriangleDeformationTranslation); TheVecAll.push_back(&TheSpec_ComputeTriangleDeformationRadiometry); - TheVecAll.push_back(&TheSpec_ComputeTriangleDeformationRad); + TheVecAll.push_back(&TheSpec_ComputeNodesPrecision); TheVecAll.push_back(&TheSpec_ImportTiePMul); TheVecAll.push_back(&TheSpec_ImportMesImGCP); TheVecAll.push_back(&TheSpecImportExtSens); diff --git a/MMVII/src/MeshDisplacement/ApplyDelaunayOnRandomGeneratedPoints.cpp b/MMVII/src/MeshDisplacement/ApplyDelaunayOnRandomGeneratedPoints.cpp index 63077a9308..6937b62ced 100644 --- a/MMVII/src/MeshDisplacement/ApplyDelaunayOnRandomGeneratedPoints.cpp +++ b/MMVII/src/MeshDisplacement/ApplyDelaunayOnRandomGeneratedPoints.cpp @@ -1,7 +1,6 @@ #include "cMMVII_Appli.h" #include "MMVII_Geom2D.h" - /** \file ApplyDelaunayOnRandomGeneratedPoints.cpp @@ -33,44 +32,53 @@ namespace MMVII cCollecSpecArg2007 &ArgObl(cCollecSpecArg2007 &anArgObl) override; cCollecSpecArg2007 &ArgOpt(cCollecSpecArg2007 &anArgOpt) override; - void ApplyAndSaveDelaunayTriangulationOnPoints(); - void GeneratePointsForDelaunay(); - void ConstructUniformRandomVector(); - void ComputeShiftedTrianglesAndPoints(const cTriangle & aTri, std::vector & ShiftedTriangleCoordinates, - const double aUniformRandomRedChannel, const double aUniformRandomGreenChannel, - const double aUniformRandomBlueChannel); + void ApplyAndSaveDelaunayTriangulationOnPoints(); // Apply triangulation and save to .ply file + void DefineValueLimitsForPointGeneration(); // Define limits of values for uniform law + void ConstructUniformRandomVector(); // Build vector with node coordinates drawn from uniform law + void GeneratePointsForRectangularGrid(); // Build vector with node coordinates that form a rectangular grid + // Shift triangles by a certain quantity defined in method + void ComputeShiftedTrianglesAndPoints(const cTriangle &aTri, std::vector &ShiftedTriangleCoordinates, + const tREAL8 aUniformRandomRedChannel, const tREAL8 aUniformRandomGreenChannel, + const tREAL8 aUniformRandomBlueChannel); private: // == Mandatory args ==== - - std::string mNameInputImage; - std::string mNamePlyFile; - int mNumberPointsToGenerate; // number of generated points + + std::string mNameInputImage; // Name of input image + std::string mNamePlyFile; // Name of .ply file to save delaunay triangles to + int mNumberPointsToGenerate; // number of generated points // == Optionnal args ==== - int mRandomUniformLawUpperBoundXAxis; // Uniform law generate numbers from [0, mRandomUniformLawUpperBound [ for x-axis - int mRandomUniformLawUpperBoundYAxis; // Uniform law generate numbers from [0, mRandomUniformLawUpperBound [ for y-axis - bool mPlyFileisBinary; - bool mShiftTriangles; - std::string mNameModifedTrianglePlyFile; + int mNumberOfCols; // Uniform law generate numbers from [0, mRandomUniformLawUpperBound [ for x-axis + int mNumberOfLines; // Uniform law generate numbers from [0, mRandomUniformLawUpperBound [ for y-axis + bool mBuildRandomUniformGrid; // Whether to draw coordinates of nodes from uniform law or by rectangular grid + bool mShiftTriangles; // Whether or not to shift triangles + bool mPlyFileisBinary; // Whether the .ply file is binary or not + std::string mNameModifedTrianglePlyFile; // Name of .ply file to which the shifted triangles can be saved // == Internal variables ==== - - tIm mImIn; ///< memory representation of the image - tDIm *mDImIn; ///< memory representation of the image - cPt2di mSz; // Size of images - std::vector mVectorPts; // A vector containing a set of points + + cPt2di mSzImIn; // Size of images + tIm mImIn; // memory representation of the image + tDIm *mDImIn; // memory representation of the image + std::vector mVectorPts; // A vector containing a set of points + cTriangulation2D mDelTri; // A delaunay triangle }; cAppli_RandomGeneratedDelaunay::cAppli_RandomGeneratedDelaunay(const std::vector &aVArgs, const cSpecMMVII_Appli &aSpec) : cMMVII_Appli(aVArgs, aSpec), - mRandomUniformLawUpperBoundXAxis(1), - mRandomUniformLawUpperBoundYAxis(1), - mPlyFileisBinary(false), + mNumberOfCols(1), + mNumberOfLines(1), + mBuildRandomUniformGrid(true), mShiftTriangles(true), - mImIn(cPt2di(1, 1)), - mDImIn(nullptr) + mPlyFileisBinary(false), + mNameModifedTrianglePlyFile("ShiftedTriangles.ply"), + mSzImIn(cPt2di(1, 1)), + mImIn(mSzImIn), + mDImIn(nullptr), + mVectorPts({tPt2dr(0, 0)}), + mDelTri(mVectorPts) { } @@ -85,74 +93,37 @@ namespace MMVII cCollecSpecArg2007 &cAppli_RandomGeneratedDelaunay::ArgOpt(cCollecSpecArg2007 &anArgOpt) { return anArgOpt - << AOpt2007(mRandomUniformLawUpperBoundXAxis, "RandomUniformLawXAxis", "Maximum value that the uniform law can draw from for x-axis.", {eTA2007::HDV}) - << AOpt2007(mRandomUniformLawUpperBoundYAxis, "RandomUniformLawYAxis", "Maximum value that the uniform law can draw from for y-axis.", {eTA2007::HDV}) - << AOpt2007(mShiftTriangles, "ShiftTriangles", "Whether to shift points of triangles after application of Delaunay triangulation.", {eTA2007::HDV}) - << AOpt2007(mPlyFileisBinary, "PlyFileIsBinary", "Whether to save the .ply file binarised or not.", {eTA2007::HDV}) - << AOpt2007(mNameModifedTrianglePlyFile, "NamePlyFileShiftedTriangles", "Name of .ply file for shifted triangles.", {eTA2007::FileCloud}); + << AOpt2007(mNumberOfCols, "MaximumValueNumberOfCols", "Maximum value that the uniform law can draw from for x-axis.", {eTA2007::HDV}) + << AOpt2007(mNumberOfLines, "MaximumValueNumberOfLines", "Maximum value that the uniform law can draw from for y-axis.", {eTA2007::HDV}) + << AOpt2007(mBuildRandomUniformGrid, "GenerateRandomUniformGrid", + "Whether to build a grid to be triangulated thanks to points generated randomly with a uniform law or build a grid made of rectangles.", {eTA2007::HDV}) + << AOpt2007(mShiftTriangles, "ShiftTriangles", "Whether to shift points of triangles after application of Delaunay triangulation.", {eTA2007::HDV}) + << AOpt2007(mPlyFileisBinary, "PlyFileIsBinary", "Whether to save the .ply file binarised or not.", {eTA2007::HDV}) + << AOpt2007(mNameModifedTrianglePlyFile, "NamePlyFileShiftedTriangles", "Name of .ply file for shifted triangles.", {eTA2007::HDV, eTA2007::FileCloud}); } //========================================================= - void cAppli_RandomGeneratedDelaunay::ComputeShiftedTrianglesAndPoints(const cTriangle & aTri, - std::vector & ShiftedTriangleCoordinates, - const double aUniformRandomRedChannel, - const double aUniformRandomGreenChannel, - const double aUniformRandomBlueChannel) - { - const cTriangle2DCompiled aCompTri(aTri); - - // Compute shifts depending on point of triangle - const cPt2dr PercentDiffA = 0.01 * (aTri.Pt(0) - aTri.Pt(2)); - const cPt2dr PercentDiffB = 0.015 * (aTri.Pt(1) - aTri.Pt(0)); - const cPt2dr PercentDiffC = 0.02 * (aTri.Pt(2) - aTri.Pt(1)); - - ShiftedTriangleCoordinates.push_back(aTri.Pt(0) + PercentDiffA); - ShiftedTriangleCoordinates.push_back(aTri.Pt(1) + PercentDiffB); - ShiftedTriangleCoordinates.push_back(aTri.Pt(2) + PercentDiffC); - - // Get pixels inside each triangle and shift them - std::vector aVectorToFillwithInsidePixels; - aCompTri.PixelsInside(aVectorToFillwithInsidePixels); - for (long unsigned int FilledPixel=0; FilledPixel < aVectorToFillwithInsidePixels.size(); FilledPixel++) - { - if (FilledPixel % 10 == 0) - { - const cPt2dr aFilledPoint(aVectorToFillwithInsidePixels[FilledPixel].x(), aVectorToFillwithInsidePixels[FilledPixel].y()); - const cPt3dr barycenter_coordinates = aCompTri.CoordBarry(aFilledPoint); - const cPt2dr ShiftedInsidePixels = cPt2dr(aFilledPoint.x() + barycenter_coordinates.x() * PercentDiffA.x() + - barycenter_coordinates.y() * PercentDiffB.x() + barycenter_coordinates.z() * PercentDiffC.x(), - aFilledPoint.y() + barycenter_coordinates.x() * PercentDiffA.y() + - barycenter_coordinates.y() * PercentDiffB.y() + barycenter_coordinates.z() * PercentDiffC.y()); - - StdOut() << aFilledPoint.x() << " " << aFilledPoint.y() << " " << aUniformRandomRedChannel - << " " << aUniformRandomGreenChannel << " " << aUniformRandomBlueChannel << std::endl; - StdOut() << ShiftedInsidePixels.x() << " " << ShiftedInsidePixels.y() << " " - << aUniformRandomRedChannel << " " << aUniformRandomGreenChannel << " " << aUniformRandomBlueChannel << std::endl; - } - } - } - void cAppli_RandomGeneratedDelaunay::ApplyAndSaveDelaunayTriangulationOnPoints() { - tTriangule2dr aDelTri(mVectorPts); - - aDelTri.MakeDelaunay(); + mDelTri.MakeDelaunay(); std::vector ShiftedTriangleCoordinates; + const int aMaxValueUniformLaw = 256; + // Loop over all triangle - for (size_t aKt = 0; aKt < aDelTri.NbFace(); aKt++) + for (size_t aKt = 0; aKt < mDelTri.NbFace(); aKt++) { - const cTriangle aTri = aDelTri.KthTri(aKt); + const cTriangle aTri = mDelTri.KthTri(aKt); if (mShiftTriangles) { // for colouring points in representation - const double aUniformRandomRedChannel = RandUnif_N(256); - const double aUniformRandomGreenChannel = RandUnif_N(256); - const double aUniformRandomBlueChannel = RandUnif_N(256); - ComputeShiftedTrianglesAndPoints(aTri, ShiftedTriangleCoordinates, aUniformRandomRedChannel, + const double aUniformRandomRedChannel = RandUnif_N(aMaxValueUniformLaw); + const double aUniformRandomGreenChannel = RandUnif_N(aMaxValueUniformLaw); + const double aUniformRandomBlueChannel = RandUnif_N(aMaxValueUniformLaw); + ComputeShiftedTrianglesAndPoints(aTri, ShiftedTriangleCoordinates, aUniformRandomRedChannel, aUniformRandomGreenChannel, aUniformRandomBlueChannel); } } @@ -166,53 +137,116 @@ namespace MMVII } // Save files to .ply format - aDelTri.WriteFile(mNamePlyFile, mPlyFileisBinary); + mDelTri.WriteFile(mNamePlyFile, mPlyFileisBinary); } void cAppli_RandomGeneratedDelaunay::ConstructUniformRandomVector() { - // Use current time as seed for random generator - srand(time(0)); + // Use current time as seed for random generator + srand(time(0)); // Generate coordinates from drawing lines and columns of coordinates from a uniform distribution for (int aNbPt = 0; aNbPt < mNumberPointsToGenerate; aNbPt++) { - const double aUniformRandomXAxis = RandUnif_N(mRandomUniformLawUpperBoundXAxis); - const double aUniformRandomYAxis = RandUnif_N(mRandomUniformLawUpperBoundYAxis); + const double aUniformRandomXAxis = RandUnif_N(mNumberOfCols); + const double aUniformRandomYAxis = RandUnif_N(mNumberOfLines); const cPt2dr aUniformRandomPt(aUniformRandomXAxis, aUniformRandomYAxis); // cPt2dr format mVectorPts.push_back(aUniformRandomPt); } + + mDelTri = mVectorPts; + } + + void cAppli_RandomGeneratedDelaunay::GeneratePointsForRectangularGrid() + { + std::vector aGridVector; + const int anEdge = 10; // To take away variations linked to edges + + const int aDistanceLines = mNumberOfLines / std::sqrt(mNumberPointsToGenerate); + const int aDistanceCols = mNumberOfCols / std::sqrt(mNumberPointsToGenerate); + + for (int aLineNumber = anEdge; aLineNumber < mNumberOfLines; aLineNumber += aDistanceLines) + { + for (int aColNumber = anEdge; aColNumber < mNumberOfCols; aColNumber += aDistanceCols) + { + const tPt2dr aGridPt = tPt2dr(aColNumber, aLineNumber); + aGridVector.push_back(aGridPt); + } + } + + mDelTri = aGridVector; } - void cAppli_RandomGeneratedDelaunay::GeneratePointsForDelaunay() + void cAppli_RandomGeneratedDelaunay::DefineValueLimitsForPointGeneration() { // If user hasn't defined another value than the default value, it is changed - if (mRandomUniformLawUpperBoundXAxis == 1 && mRandomUniformLawUpperBoundXAxis == 1) - { - // Maximum value of coordinates are drawn from [0, NumberOfImageLines[ - mRandomUniformLawUpperBoundXAxis = mSz.x(); - mRandomUniformLawUpperBoundYAxis = mSz.y(); - } - else - { - if (mRandomUniformLawUpperBoundXAxis != 1 && mRandomUniformLawUpperBoundYAxis == 1) - mRandomUniformLawUpperBoundYAxis = mSz.y(); - else - { - if (mRandomUniformLawUpperBoundXAxis == 1 && mRandomUniformLawUpperBoundYAxis != 1) - mRandomUniformLawUpperBoundXAxis = mSz.x(); - } - } - - ConstructUniformRandomVector(); + if (mNumberOfCols == 1 && mNumberOfCols == 1) + { + // Maximum value of coordinates are drawn from [0, NumberOfImageLines[ + mNumberOfCols = mSzImIn.x(); + mNumberOfLines = mSzImIn.y(); + } + else + { + if (mNumberOfCols != 1 && mNumberOfLines == 1) + mNumberOfLines = mSzImIn.y(); + else + { + if (mNumberOfCols == 1 && mNumberOfLines != 1) + mNumberOfCols = mSzImIn.x(); + } + } + if (mBuildRandomUniformGrid) + ConstructUniformRandomVector(); + else + GeneratePointsForRectangularGrid(); ApplyAndSaveDelaunayTriangulationOnPoints(); // Apply Delaunay triangulation on generated points. } + void cAppli_RandomGeneratedDelaunay::ComputeShiftedTrianglesAndPoints(const cTriangle &aTri, + std::vector &ShiftedTriangleCoordinates, + const tREAL8 aUniformRandomRedChannel, + const tREAL8 aUniformRandomGreenChannel, + const tREAL8 aUniformRandomBlueChannel) + { + const cTriangle2DCompiled aCompTri(aTri); + + // Compute shifts depending on point of triangle + const cPt2dr PercentDiffA = 0.01 * (aTri.Pt(0) - aTri.Pt(2)); + const cPt2dr PercentDiffB = 0.015 * (aTri.Pt(1) - aTri.Pt(0)); // arbitrary values are chosen for displacement + const cPt2dr PercentDiffC = 0.02 * (aTri.Pt(2) - aTri.Pt(1)); + + ShiftedTriangleCoordinates.push_back(aTri.Pt(0) + PercentDiffA); + ShiftedTriangleCoordinates.push_back(aTri.Pt(1) + PercentDiffB); + ShiftedTriangleCoordinates.push_back(aTri.Pt(2) + PercentDiffC); + + // Get pixels inside each triangle and shift them + std::vector aVectorToFillwithInsidePixels; + aCompTri.PixelsInside(aVectorToFillwithInsidePixels); + for (size_t aFilledPixel = 0; aFilledPixel < aVectorToFillwithInsidePixels.size(); aFilledPixel++) + { + if (aFilledPixel % 40 == 0) + { + const cPt2dr aFilledPoint(aVectorToFillwithInsidePixels[aFilledPixel].x(), aVectorToFillwithInsidePixels[aFilledPixel].y()); + const cPt3dr barycenter_coordinates = aCompTri.CoordBarry(aFilledPoint); + const cPt2dr ShiftedInsidePixels = cPt2dr(aFilledPoint.x() + barycenter_coordinates.x() * PercentDiffA.x() + + barycenter_coordinates.y() * PercentDiffB.x() + barycenter_coordinates.z() * PercentDiffC.x(), + aFilledPoint.y() + barycenter_coordinates.x() * PercentDiffA.y() + + barycenter_coordinates.y() * PercentDiffB.y() + barycenter_coordinates.z() * PercentDiffC.y()); + + StdOut() << aFilledPoint.x() << " " << aFilledPoint.y() << " " << aUniformRandomRedChannel + << " " << aUniformRandomGreenChannel << " " << aUniformRandomBlueChannel << std::endl; + StdOut() << ShiftedInsidePixels.x() << " " << ShiftedInsidePixels.y() << " " + << aUniformRandomRedChannel << " " << aUniformRandomGreenChannel << " " << aUniformRandomBlueChannel << std::endl; + } + } + } + //---------------------------------------- int cAppli_RandomGeneratedDelaunay::Exe() { - /* + /* MMVII RandomGeneratedDelaunay pair18_im1_720.png OriginalTriangles.ply 20 50 NamePlyFileShiftedTriangles=ShiftedTriangles.ply > OriginalAndShiftedPoints.xyz awk NR%2==1 < OriginalAndShiftedPoints.xyz > OriginalPoints.xyz awk NR%2==0 < OriginalAndShiftedPoints.xyz > ShiftedPoints.xyz @@ -221,9 +255,9 @@ namespace MMVII mImIn = tIm::FromFile(mNameInputImage); mDImIn = &mImIn.DIm(); - mSz = mDImIn->Sz(); + mSzImIn = mDImIn->Sz(); - GeneratePointsForDelaunay(); + DefineValueLimitsForPointGeneration(); return EXIT_SUCCESS; } @@ -242,7 +276,7 @@ namespace MMVII cSpecMMVII_Appli TheSpec_RandomGeneratedDelaunay( "RandomGeneratedDelaunay", Alloc_RandomGeneratedDelaunay, - "Generate random points and apply Delaunay triangulation", + "Generate random points thanks to uniform law and apply Delaunay triangulation", {eApF::ImProc}, // category {eApDT::Image}, // input {eApDT::Ply}, // output diff --git a/MMVII/src/MeshDisplacement/ComputeNodesPrecision.cpp b/MMVII/src/MeshDisplacement/ComputeNodesPrecision.cpp new file mode 100644 index 0000000000..9272cf5e3f --- /dev/null +++ b/MMVII/src/MeshDisplacement/ComputeNodesPrecision.cpp @@ -0,0 +1,190 @@ +#include "ComputeNodesPrecision.h" + +/** + \file ComputeNodesPrecision.cpp + + \brief file for computing finding the best compromise between + how many nodes to use in triangulation and the possible displacement precision +**/ + +namespace MMVII +{ + /************************************************/ + /* */ + /* cAppli_ComputeNodesPrecision */ + /* */ + /************************************************/ + + cAppli_ComputeNodesPrecision::cAppli_ComputeNodesPrecision(const std::vector &aVArgs, + const cSpecMMVII_Appli &aSpec) : cMMVII_Appli(aVArgs, aSpec), + mNumberOfLines(1), + mNumberOfCols(1), + mBuildRandomUniformGrid(false), + mComputeDiffDispMaps(true), + mComputeInterpTranslationDispMaps(true), + mNameDiffDispX("DiffComputedDispX"), + mNameDiffDispY("DiffComputedDispY"), + mNameComputedTranslatedDispX("ComputedTranslationDispX"), + mNameComputedTranslatedDispY("ComputedTranslationDispY"), + mSzImDispX(tPt2di(1, 1)), + mImDispX(mSzImDispX), + mDImDispX(nullptr), + mSzImDispY(tPt2di(1, 1)), + mImDispY(mSzImDispY), + mDImDispY(nullptr), + mSzImDiffDispX(tPt2di(1, 1)), + mImDiffDispX(mSzImDiffDispX), + mDImDiffDispX(nullptr), + mSzImDiffDispY(tPt2di(1, 1)), + mImDiffDispY(mSzImDiffDispY), + mDImDiffDispY(nullptr), + mSzImTranslatedDispX(tPt2di(1, 1)), + mImTranslatedDispX(mSzImTranslatedDispX), + mDImTranslatedDispX(nullptr), + mSzImTranslatedDispY(tPt2di(1, 1)), + mImTranslatedDispY(mSzImTranslatedDispY), + mDImTranslatedDispY(nullptr), + mDelTri({tPt2dr(0, 0)}) + { + } + + cAppli_ComputeNodesPrecision::~cAppli_ComputeNodesPrecision() + { + } + + cCollecSpecArg2007 &cAppli_ComputeNodesPrecision::ArgObl(cCollecSpecArg2007 &anArgObl) + { + return anArgObl + << Arg2007(mNameDispXMap, "Name of x-displacement ground-truth file.", {eTA2007::FileImage, eTA2007::FileDirProj}) + << Arg2007(mNameDispYMap, "Name of y-displacement ground-truth file.", {eTA2007::FileImage}) + << Arg2007(mNumberPointsToGenerate, "Number of points you want to generate for triangulation."); + } + + cCollecSpecArg2007 &cAppli_ComputeNodesPrecision::ArgOpt(cCollecSpecArg2007 &anArgOpt) + { + return anArgOpt + << AOpt2007(mNumberOfLines, "MaximumValueNumberOfLines", + "Maximum value that the uniform law can draw from for on the y-axis.", {eTA2007::HDV, eTA2007::Tuning}) + << AOpt2007(mNumberOfCols, "MaximumValueNumberOfCols", + "Maximum value that the uniform law can draw from on the x-axis.", {eTA2007::HDV, eTA2007::Tuning}) + << AOpt2007(mBuildRandomUniformGrid, "GenerateRandomUniformGrid", + "Whether to build a grid to be triangulated thanks to points generated randomly with a uniform law or build a grid made of rectangles.", {eTA2007::HDV}) + << AOpt2007(mComputeDiffDispMaps, "ComputeDiffDisplacementMaps", + "Whether to compute difference displacement maps or not.", {eTA2007::HDV}) + << AOpt2007(mComputeInterpTranslationDispMaps, "ComputeInterpTranslationDispMaps", + "Whether to compute displacement maps containing translations by barycentric interpolation formula or not.", {eTA2007::HDV}) + << AOpt2007(mNameDiffDispX, "NameXDisplacementDiffMap", + "File name to use to save the difference x-displacement map.", {eTA2007::HDV}) + << AOpt2007(mNameDiffDispY, "NameYDisplacementDiffMap", + "File name to use to save the difference y-displacement map.", {eTA2007::HDV}) + << AOpt2007(mNameComputedTranslatedDispX, "NameXTranslatedDispMap", + "File name to use to save the x-translated displacement map.", {eTA2007::HDV}) + << AOpt2007(mNameComputedTranslatedDispY, "NameYTranslatedDispMap", + "File name to use to save the y-translated displacement map.", {eTA2007::HDV}); + } + + void cAppli_ComputeNodesPrecision::LoopOverTrianglesAndGetDiffDispMaps() + { + if (mComputeDiffDispMaps) + { + InitialiseDisplacementMaps(mSzImDispX, mImDiffDispX, mDImDiffDispX, mSzImDiffDispX); + InitialiseDisplacementMaps(mSzImDispY, mImDiffDispY, mDImDiffDispY, mSzImDiffDispY); + } + + if (mComputeInterpTranslationDispMaps) + { + InitialiseDisplacementMaps(mSzImDispX, mImTranslatedDispX, mDImTranslatedDispX, mSzImTranslatedDispX); + InitialiseDisplacementMaps(mSzImDispY, mImTranslatedDispY, mDImTranslatedDispY, mSzImTranslatedDispY); + } + + for (size_t aTr = 0; aTr < mDelTri.NbFace(); aTr++) + { + const tTri2dr aTri = mDelTri.KthTri(aTr); + + const cTriangle2DCompiled aLastCompTri(aTri); + + std::vector aLastVectorToFillWithInsidePixels; + aLastCompTri.PixelsInside(aLastVectorToFillWithInsidePixels); + + const tPt2dr aRealCoordPointA = aTri.Pt(0); // Get real value coordinates 1st point of triangle + const tPt2dr aRealCoordPointB = aTri.Pt(1); // Get real value coordinates 2nd point of triangle + const tPt2dr aRealCoordPointC = aTri.Pt(2); // Get real value coordinates 3rd point of triangle + + const tPt2di aIntCoordPointA = tPt2di(aRealCoordPointA.x(), aRealCoordPointA.y()); // Get integer value coordinates 1st point of triangle + const tPt2di aIntCoordPointB = tPt2di(aRealCoordPointB.x(), aRealCoordPointB.y()); // Get integer value coordinates 2nd point of triangle + const tPt2di aIntCoordPointC = tPt2di(aRealCoordPointC.x(), aRealCoordPointC.y()); // Get integer value coordinates 3rd point of triangle + + const tPt2dr aTrPointA = CheckReturnOfBilinearValue(mDImDispX, mDImDispY, aRealCoordPointA, aIntCoordPointA); // Get value value from real or int coordinates 1st point + const tPt2dr aTrPointB = CheckReturnOfBilinearValue(mDImDispX, mDImDispY, aRealCoordPointB, aIntCoordPointB); // Get value value from real or int coordinates 2nd point + const tPt2dr aTrPointC = CheckReturnOfBilinearValue(mDImDispX, mDImDispY, aRealCoordPointC, aIntCoordPointC); // Get value value from real or int coordinates 3rd point + + const size_t aLastNumberOfInsidePixels = aLastVectorToFillWithInsidePixels.size(); + + for (size_t aLastFilledPixel = 0; aLastFilledPixel < aLastNumberOfInsidePixels; aLastFilledPixel++) + { + const cPtInsideTriangles aPixInsideTriangleDispX = cPtInsideTriangles(aLastCompTri, aLastVectorToFillWithInsidePixels, + aLastFilledPixel, mDImDispX); + const cPtInsideTriangles aPixInsideTriangleDispY = cPtInsideTriangles(aLastCompTri, aLastVectorToFillWithInsidePixels, + aLastFilledPixel, mDImDispY); + + // apply barycentric interpolation formula + const tPt2dr aTranslatedDispPoint = ApplyBarycenterTranslationFormulaToFilledPixel(aTrPointA, aTrPointB, + aTrPointC, aPixInsideTriangleDispX); + + FillDiffDisplacementMap(mDImDispX, mDImDiffDispX, mDImTranslatedDispX, aPixInsideTriangleDispX, + aPixInsideTriangleDispX.GetCartesianCoordinates().x(), aTranslatedDispPoint.x(), + mComputeDiffDispMaps, mComputeInterpTranslationDispMaps); + FillDiffDisplacementMap(mDImDispY, mDImDiffDispY, mDImTranslatedDispY, aPixInsideTriangleDispY, + aPixInsideTriangleDispY.GetCartesianCoordinates().y(), aTranslatedDispPoint.y(), + mComputeDiffDispMaps, mComputeInterpTranslationDispMaps); + // aTranslatedDispPoint has same translated coordinates as aTranslatedDispYPoint, the computation of formula doesn't need to be done twice + } + } + + if (mComputeDiffDispMaps) + { + mDImDiffDispX->ToFile(mNameDiffDispX + "_" + ToStr(mNumberPointsToGenerate) + ".tif"); + mDImDiffDispX->ToFile(mNameDiffDispY + "_" + ToStr(mNumberPointsToGenerate) + ".tif"); + } + if (mComputeInterpTranslationDispMaps) + { + mDImTranslatedDispX->ToFile(mNameComputedTranslatedDispX + "_" + ToStr(mNumberPointsToGenerate) + ".tif"); + mDImTranslatedDispY->ToFile(mNameComputedTranslatedDispY + "_" + ToStr(mNumberPointsToGenerate) + ".tif"); + } + } + + int cAppli_ComputeNodesPrecision::Exe() + { + // read pre and post images and update their sizes + ReadFileNameLoadData(mNameDispXMap, mImDispX, mDImDispX, mSzImDispX); + ReadFileNameLoadData(mNameDispYMap, mImDispY, mDImDispY, mSzImDispY); + + // Build uniform or rectangular grid + DefineValueLimitsForPointGenerationAndBuildGrid(mNumberPointsToGenerate, mNumberOfLines, + mNumberOfCols, mDelTri, mSzImDispX, mBuildRandomUniformGrid); + + LoopOverTrianglesAndGetDiffDispMaps(); + + return EXIT_SUCCESS; + } + + /********************************************/ + // ::MMVII // + /********************************************/ + + tMMVII_UnikPApli Alloc_cAppli_ComputeNodesPrecision(const std::vector &aVArgs, + const cSpecMMVII_Appli &aSpec) + { + return tMMVII_UnikPApli(new cAppli_ComputeNodesPrecision(aVArgs, aSpec)); + } + + cSpecMMVII_Appli TheSpec_ComputeNodesPrecision( + "ComputeNodesPrecision", + Alloc_cAppli_ComputeNodesPrecision, + "Compute compromise between number of nodes used in triangulation and obtained precision", + {eApF::ImProc}, // category + {eApDT::Image}, // input + {eApDT::Image}, // output + __FILE__); + +}; // MMVII \ No newline at end of file diff --git a/MMVII/src/MeshDisplacement/ComputeNodesPrecision.h b/MMVII/src/MeshDisplacement/ComputeNodesPrecision.h new file mode 100644 index 0000000000..ecffedc364 --- /dev/null +++ b/MMVII/src/MeshDisplacement/ComputeNodesPrecision.h @@ -0,0 +1,86 @@ +#ifndef _COMPUTENODESPRECISION_H_ +#define _COMPUTENODESPRECISION_H_ + +#include "cMMVII_Appli.h" + +#include "MMVII_Geom2D.h" +#include "MMVII_PhgrDist.h" + +#include "TriangleDeformationUtils.h" + +namespace MMVII +{ + + /************************************************/ + /* */ + /* cAppli_ComputeNodesPrecision */ + /* */ + /************************************************/ + + class cAppli_ComputeNodesPrecision : public cMMVII_Appli + { + public: + typedef cIm2D tIm; + typedef cDataIm2D tDIm; + typedef cTriangle tTri2dr; + + cAppli_ComputeNodesPrecision(const std::vector &aVArgs, + const cSpecMMVII_Appli &aSpec); + ~cAppli_ComputeNodesPrecision(); + + int Exe() override; + cCollecSpecArg2007 &ArgObl(cCollecSpecArg2007 &anArgObl) override; + cCollecSpecArg2007 &ArgOpt(cCollecSpecArg2007 &anArgOpt) override; + + void LoopOverTrianglesAndGetDiffDispMaps(); // Loop over triangles and save displacement map between ground truth and interpolation value + + private: + // == Mandatory args == + + std::string mNameDispXMap; // Name of given pre-image + std::string mNameDispYMap; // Name of given post-image + int mNumberPointsToGenerate; // Number of generated points + + // == Optionnal args == + + int mNumberOfLines; // Uniform law generates random coordinates in interval [0, mNumberOfLines [ + int mNumberOfCols; // Uniform law generates random coordinates in interval [0, mNumberOfCols [ + bool mBuildRandomUniformGrid; // Whether to triangulate grid made of points whose coordinates follow a uniform law or have coordinates that form rectangles + bool mComputeDiffDispMaps; // Whether to compute difference displacement maps or not + bool mComputeInterpTranslationDispMaps; // Whether to compute translated dispalcement maps or not + std::string mNameDiffDispX; // File name to use to save the x-displacement difference map between interpolation ground truth and ground truth + std::string mNameDiffDispY; // File name to use to save the y-displacement difference map between interpolation ground truth and ground truth + std::string mNameComputedTranslatedDispX; // File name to use to save the x-translated displacement map + std::string mNameComputedTranslatedDispY; // File name to use to save the y-translated displacement map + + // == Internal variables == + + tPt2di mSzImDispX; // size of image + tIm mImDispX; // memory representation of the image + tDIm *mDImDispX; // memory representation of the image + + tPt2di mSzImDispY; // size of image + tIm mImDispY; // memory representation of the image + tDIm *mDImDispY; // memory representation of the image + + tPt2di mSzImDiffDispX; // size of image + tIm mImDiffDispX; // memory representation of the image + tDIm *mDImDiffDispX; // memory representation of the image + + tPt2di mSzImDiffDispY; // size of image + tIm mImDiffDispY; // memory representation of the image + tDIm *mDImDiffDispY; // memory representation of the image + + tPt2di mSzImTranslatedDispX; // size of image + tIm mImTranslatedDispX; // memory representation of the image + tDIm *mDImTranslatedDispX; // memory representation of the image + + tPt2di mSzImTranslatedDispY; // size of image + tIm mImTranslatedDispY; // memory representation of the image + tDIm *mDImTranslatedDispY; // memory representation of the image + + cTriangulation2D mDelTri; // A Delaunay triangle + }; +} // MMVII + +#endif // _COMPUTENODESPRECISION_H_ \ No newline at end of file diff --git a/MMVII/src/MeshDisplacement/SerialiseTriangleDeformation.cpp b/MMVII/src/MeshDisplacement/SerialiseTriangleDeformation.cpp new file mode 100644 index 0000000000..4425e3e97e --- /dev/null +++ b/MMVII/src/MeshDisplacement/SerialiseTriangleDeformation.cpp @@ -0,0 +1,115 @@ +#include "SerialiseTriangleDeformation.h" + +/** + \file SerialiseDeformation.cpp + \brief File containing methods to serialise objects + linked to triangle deformation between optimisation executions + **/ + +namespace MMVII +{ + cSerialiseTriangleDeformation::cSerialiseTriangleDeformation() + { + } + + cSerialiseTriangleDeformation::cSerialiseTriangleDeformation(const tDenseVect &aVecSol, + const tIntVect &aIndicesVec, + const int aXIndices, + const int aYIndices, + const int aRadTrIndices, + const int aRadScIndices, + const tTri2dr &aTri, + const tPt3di &aFace, + const int aPointNumberInTri, + const int anIdOfPoint) : cNodeOfTriangles(aVecSol, aIndicesVec, aXIndices, + aYIndices, aRadTrIndices, aRadScIndices, + aTri, aPointNumberInTri), + mIdOfPt(anIdOfPoint) + { + if (aPointNumberInTri == 0) + mFaceOfTriangle = aFace.x(); + else if (aPointNumberInTri == 1) + mFaceOfTriangle = aFace.y(); + else + mFaceOfTriangle = aFace.z(); + } + + cSerialiseTriangleDeformation::~cSerialiseTriangleDeformation() + { + } + + std::ostream& operator<<(std::ostream& os, const cSerialiseTriangleDeformation& obj) + { + obj.ShowTriangleDeformationObjectCarateristics(); + return os; + } + + void cSerialiseTriangleDeformation::AddData(const cAuxAr2007 &anAux, cSerialiseTriangleDeformation &aPtToSerialise) + { + MMVII::AddData(cAuxAr2007("Id", anAux), aPtToSerialise.GetPointId()); + MMVII::AddData(cAuxAr2007("Face", anAux), aPtToSerialise.GetTriangleFace()); + MMVII::AddData(cAuxAr2007("x", anAux), aPtToSerialise.GetInitialNodeCoordinates().x()); + MMVII::AddData(cAuxAr2007("y", anAux), aPtToSerialise.GetInitialNodeCoordinates().y()); + MMVII::AddData(cAuxAr2007("dx", anAux), aPtToSerialise.GetCurrentXYDisplacementValues().x()); + MMVII::AddData(cAuxAr2007("dy", anAux), aPtToSerialise.GetCurrentXYDisplacementValues().y()); + MMVII::AddData(cAuxAr2007("RadiometryTranslation", anAux), aPtToSerialise.GetCurrentRadiometryTranslation()); + MMVII::AddData(cAuxAr2007("RadiometryScaling", anAux), aPtToSerialise.GetCurrentRadiometryScaling()); + } + + void AddData(const cAuxAr2007 &anAux, cSerialiseTriangleDeformation &aPtToSerialise) { aPtToSerialise.AddData(anAux, aPtToSerialise); } + + void cSerialiseTriangleDeformation::ShowTriangleDeformationObjectCarateristics() const + { + StdOut() << "Id of this point : " << this->GetPointId() << std::endl; + StdOut() << "Face of triangle associated to point : " << this->GetTriangleFace() << std::endl; + StdOut() << "Initial node coordinates : " << this->GetInitialNodeCoordinates() << "." << std::endl; + StdOut() << "Current displacement coefficient values : " << this->GetCurrentXYDisplacementValues() + << "." << std::endl; + StdOut() << "Current radiometric coefficient values : " << this->GetCurrentRadiometryTranslation() + << " for translation and " << this->GetCurrentRadiometryScaling() << " for scaling." << std::endl; + } + + void cSerialiseTriangleDeformation::SaveTriangleDeformationObjectToFile() const + { + SaveInFile(*this, NameFileToSaveOneObj(mIdOfPt)); + } + + std::unique_ptr cSerialiseTriangleDeformation::ReadSerialisedTriangleDeformation(const tDenseVect &aVecSol, const tIntVect &aIndVec, + const int aXInd, const int aYInd, const int aRadTrInd, + const int aRadScInd, const tTri2dr &aTriangle, const tPt3di &aFace, + const int aPointNumberInTri, const int anIdOfPoint) + { + std::unique_ptr aReReadSerialisedObj = std::make_unique(aVecSol, aIndVec, aXInd, aYInd, aRadTrInd, + aRadScInd, aTriangle, aFace, aPointNumberInTri, + anIdOfPoint); + ReadFromFile(*aReReadSerialisedObj, NameFileToSaveOneObj(anIdOfPoint)); + + return aReReadSerialisedObj; + } + + std::string cSerialiseTriangleDeformation::NameFileToSaveOneObj(const int anId) + { + return "Id_" + ToStr(anId) + ".xml"; + } + + int cSerialiseTriangleDeformation::GetPointId() const + { + return mIdOfPt; + } + + int cSerialiseTriangleDeformation::GetTriangleFace() const + { + return mFaceOfTriangle; + } + + int& cSerialiseTriangleDeformation::GetPointId() + { + return mIdOfPt; + } + + int& cSerialiseTriangleDeformation::GetTriangleFace() + { + return mFaceOfTriangle; + } + +}; // MMVII diff --git a/MMVII/src/MeshDisplacement/SerialiseTriangleDeformation.h b/MMVII/src/MeshDisplacement/SerialiseTriangleDeformation.h new file mode 100644 index 0000000000..1bd53fa4d0 --- /dev/null +++ b/MMVII/src/MeshDisplacement/SerialiseTriangleDeformation.h @@ -0,0 +1,56 @@ +#include "MMVII_2Include_Serial_Tpl.h" +#include "TriangleDeformationUtils.h" + +namespace MMVII +{ + /******************************************/ + /* */ + /* cSerialiseTriangleDeformation */ + /* */ + /******************************************/ + + class cSerialiseTriangleDeformation : public cNodeOfTriangles + { + + public: + typedef cDenseVect tDenseVect; + typedef std::vector tIntVect; + + cSerialiseTriangleDeformation(); // default constructor + ~cSerialiseTriangleDeformation(); // destructor + + cSerialiseTriangleDeformation(const tDenseVect &aVecSol, // Current solution vector + const tIntVect &aIndicesVec, // Indices of current triangle in solution vector + const int aXIndices, // Index for current x-displacement in solution vector + const int aYIndices, // Index for current y-displacement in solution vector + const int aRadTrIndices, // Index for current radiometry translation in solution vector + const int aRadScIndices, // Index for current radiometry scaling in solution vector + const tTri2dr &aTri, // Current triangle + const tPt3di &aFace, // Current face of triangle + const int aPointNumberInTri, // Index of point in triangle : 0, 1 or 2 + const int IdOfPoint); // Id of point when looping over triangles + + void AddData(const cAuxAr2007 &anAux, cSerialiseTriangleDeformation &aPtToSerialise); // Add data to xml file + void SaveTriangleDeformationObjectToFile() const; // Save to xml file + void ShowTriangleDeformationObjectCarateristics() const; // Display information about object + // Adds ability to re-read already saved object + static std::unique_ptr ReadSerialisedTriangleDeformation(const tDenseVect &aVecSol, const tIntVect &aIndVec, + const int aXInd, const int aYInd, const int aRadTrInd, + const int aRadScInd, const tTri2dr &aTriangle, const tPt3di &aFace, + const int aPointNumberInTri, const int anIdOfPoint); + + static std::string NameFileToSaveOneObj(const int anId); // Gives name to saved file + int GetPointId() const; + int& GetPointId(); + int GetTriangleFace() const; + int& GetTriangleFace(); + + private: + int mIdOfPt; // Id of point when looping over triangles + int mFaceOfTriangle; // The face number associated to the point + + friend std::ostream& operator<<(std::ostream& os, const cSerialiseTriangleDeformation& obj); + }; + + void AddData(const cAuxAr2007 &anAux, cSerialiseTriangleDeformation &aPtToSerialise); +}; // MMVII \ No newline at end of file diff --git a/MMVII/src/MeshDisplacement/TriangleDeformation.cpp b/MMVII/src/MeshDisplacement/TriangleDeformation.cpp index 26c7f3f3c8..3fc72be93c 100644 --- a/MMVII/src/MeshDisplacement/TriangleDeformation.cpp +++ b/MMVII/src/MeshDisplacement/TriangleDeformation.cpp @@ -1,11 +1,5 @@ -#include "cMMVII_Appli.h" - -#include "MMVII_TplSymbTriangle.h" - #include "TriangleDeformation.h" -#include - /** \file TriangleDeformation.cpp @@ -15,331 +9,166 @@ namespace MMVII { - /****************************************/ - /* */ - /* cPtInsideTriangles */ - /* */ - /****************************************/ - - cPtInsideTriangles::cPtInsideTriangles(const cTriangle2DCompiled &aCompTri, // a compiled triangle - const std::vector &aVectorFilledwithInsidePixels, // vector containing pixels insisde triangles - const size_t aFilledPixel, // a counter that is looping over pixels in triangles - const cDataIm2D &aDIm) // image - { - mFilledIndices = cPt2dr(aVectorFilledwithInsidePixels[aFilledPixel].x(), aVectorFilledwithInsidePixels[aFilledPixel].y()); - mBarycenterCoordinatesOfPixel = aCompTri.CoordBarry(mFilledIndices); - mValueOfPixel = aDIm.GetV(cPt2di(mFilledIndices.x(), mFilledIndices.y())); - } - - cPt3dr cPtInsideTriangles::GetBarycenterCoordinates() const { return mBarycenterCoordinatesOfPixel; } // Accessor - cPt2dr cPtInsideTriangles::GetCartesianCoordinates() const { return mFilledIndices; } // Accessor - tREAL8 cPtInsideTriangles::GetPixelValue() const { return mValueOfPixel; } // Accessor - /******************************************/ /* */ - /* cTriangleDeformation */ + /* cAppli_TriangleDeformation */ /* */ /******************************************/ - cAppli_cTriangleDeformation::cAppli_cTriangleDeformation(const std::vector &aVArgs, - const cSpecMMVII_Appli &aSpec) : cMMVII_Appli(aVArgs, aSpec), - mRandomUniformLawUpperBoundLines(1), - mRandomUniformLawUpperBoundCols(1), - mShow(true), - mComputeAvgMax(false), - mUseMultiScaleApproach(true), - mSigmaGaussFilterStep(1), - mGenerateDisplacementImage(true), - mInitialiseWithPreviousIter(false), - mFreezeTranslationX(false), - mFreezeTranslationY(false), - mFreezeRadTranslation(false), - mFreezeRadScale(false), - mWeightRadTranslation(-1), - mWeightRadScale(-1), - mNumberOfIterGaussFilter(3), - mNumberOfEndIterations(2), - mFolderSaveResult(""), - mDisplayLastTranslationValues(false), - mSzImPre(cPt2di(1, 1)), - mImPre(mSzImPre), - mDImPre(nullptr), - mSzImPost(cPt2di(1, 1)), - mImPost(mSzImPost), - mDImPost(nullptr), - mSzImOut(cPt2di(1, 1)), - mImOut(mSzImOut), - mDImOut(nullptr), - mSzImDiff(cPt2di(1, 1)), - mImDiff(mSzImDiff), - mDImDiff(nullptr), - mSzImDepX(cPt2di(1, 1)), - mImDepX(mSzImDepX), - mDImDepX(nullptr), - mSzImDepY(cPt2di(1, 1)), - mImDepY(mSzImDepY), - mDImDepY(nullptr), - mVectorPts({cPt2dr(0, 0)}), - mDelTri(mVectorPts), - mSys(nullptr), - mEqTriDeform(nullptr) + cAppli_TriangleDeformation::cAppli_TriangleDeformation(const std::vector &aVArgs, + const cSpecMMVII_Appli &aSpec) : cMMVII_Appli(aVArgs, aSpec), + mNumberOfLines(1), + mNumberOfCols(1), + mShow(true), + mComputeAvgMax(false), + mUseMultiScaleApproach(false), + mBuildRandomUniformGrid(false), + mInitialiseTranslationWithPreviousExecution(false), + mInitialiseRadiometryWithPreviousExecution(false), + mInitialiseWithUserValues(true), + mInitialiseXTranslationValue(0), + mInitialiseYTranslationValue(0), + mInitialiseRadTrValue(0), + mInitialiseRadScValue(1), + mInitialiseWithMMVI(false), + mNameInitialDepX("InitialXDisplacementMap.tif"), + mNameInitialDepY("InitialYDisplacementMap.tif"), + mNameIntermediateDepX("IntermediateDispXMap.tif"), + mNameIntermediateDepY("IntermediateDispYMap.tif"), + mIsFirstExecution(false), + mSigmaGaussFilterStep(1), + mGenerateDisplacementImage(true), + mFreezeTranslationX(false), + mFreezeTranslationY(false), + mFreezeRadTranslation(false), + mFreezeRadScale(false), + mWeightRadTranslation(-1), + mWeightRadScale(-1), + mNumberOfIterGaussFilter(3), + mNumberOfEndIterations(2), + mFolderSaveResult(""), + mDisplayLastTranslationValues(false), + mSzImPre(tPt2di(1, 1)), + mImPre(mSzImPre), + mDImPre(nullptr), + mSzImPost(tPt2di(1, 1)), + mImPost(mSzImPost), + mDImPost(nullptr), + mSzImOut(tPt2di(1, 1)), + mImOut(mSzImOut), + mDImOut(nullptr), + mSzImDepX(tPt2di(1, 1)), + mImDepX(mSzImDepX), + mDImDepX(nullptr), + mSzImDepY(tPt2di(1, 1)), + mImDepY(mSzImDepY), + mDImDepY(nullptr), + mSzIntermediateImOut(tPt2di(1, 1)), + mImIntermediateOut(mSzIntermediateImOut), + mDImIntermediateOut(nullptr), + mSzImIntermediateDepX(tPt2di(1, 1)), + mImIntermediateDepX(mSzImIntermediateDepX), + mDImIntermediateDepX(nullptr), + mSzImIntermediateDepY(tPt2di(1, 1)), + mImIntermediateDepY(mSzImIntermediateDepY), + mDImIntermediateDepY(nullptr), + mSzCorrelationMask(tPt2di(1, 1)), + mImCorrelationMask(mSzImIntermediateDepY), + mDImCorrelationMask(nullptr), + mSzImDiff(tPt2di(1, 1)), + mImDiff(mSzImDiff), + mDImDiff(nullptr), + mDelTri({tPt2dr(0, 0)}), + mSys(nullptr), + mEqTriDeform(nullptr) { mEqTriDeform = EqDeformTri(true, 1); // true means with derivative, 1 is size of buffer } - cAppli_cTriangleDeformation::~cAppli_cTriangleDeformation() + cAppli_TriangleDeformation::~cAppli_TriangleDeformation() { delete mSys; delete mEqTriDeform; } - cCollecSpecArg2007 &cAppli_cTriangleDeformation::ArgObl(cCollecSpecArg2007 &anArgObl) + cCollecSpecArg2007 &cAppli_TriangleDeformation::ArgObl(cCollecSpecArg2007 &anArgObl) { return anArgObl - << Arg2007(mNamePreImage, "Name of pre-image file.", {{eTA2007::FileImage}, {eTA2007::FileDirProj}}) - << Arg2007(mNamePostImage, "Name of post-image file.", {eTA2007::FileImage}) - << Arg2007(mNumberPointsToGenerate, "Number of points you want to generate for triangulation.") - << Arg2007(mNumberOfScales, "Total number of scales to run in multi-scale approach or iterations if multi-scale approach is not applied in optimisation process."); + << Arg2007(mNamePreImage, "Name of pre-image file.", {{eTA2007::FileImage}, {eTA2007::FileDirProj}}) + << Arg2007(mNamePostImage, "Name of post-image file.", {eTA2007::FileImage}) + << Arg2007(mNumberPointsToGenerate, "Number of points you want to generate for triangulation.") + << Arg2007(mNumberOfScales, "Total number of scales to run in multi-scale approach or iterations if multi-scale approach is not applied in optimisation process."); } - cCollecSpecArg2007 &cAppli_cTriangleDeformation::ArgOpt(cCollecSpecArg2007 &anArgOpt) + cCollecSpecArg2007 &cAppli_TriangleDeformation::ArgOpt(cCollecSpecArg2007 &anArgOpt) { return anArgOpt - << AOpt2007(mRandomUniformLawUpperBoundCols, "RandomUniformLawUpperBoundXAxis", - "Maximum value that the uniform law can draw from on the x-axis.", {eTA2007::HDV}) - << AOpt2007(mRandomUniformLawUpperBoundLines, "RandomUniformLawUpperBoundYAxis", - "Maximum value that the uniform law can draw from for on the y-axis.", {eTA2007::HDV}) - << AOpt2007(mShow, "Show", "Whether to print minimisation results.", {eTA2007::HDV}) - << AOpt2007(mComputeAvgMax, "ComputeAvgMaxDiffIm", - "Whether to compute the average and maximum pixel value of the difference image between post and pre image or not.", {eTA2007::HDV}) - << AOpt2007(mUseMultiScaleApproach, "UseMultiScaleApproach", "Whether to use multi-scale approach or not.", {eTA2007::HDV}) - << AOpt2007(mSigmaGaussFilterStep, "SigmaGaussFilterStep", "Sigma value to use for Gauss filter in multi-stage approach.", {eTA2007::HDV}) - << AOpt2007(mGenerateDisplacementImage, "GenerateDisplacementImage", - "Whether to generate and save an image having been translated.", {eTA2007::HDV}) - << AOpt2007(mInitialiseWithPreviousIter, "InitialiseWithPreviousIteration", - "Whether to initialise or not the solution with the values obtained at the previous iteration.", {eTA2007::HDV}) - << AOpt2007(mFreezeTranslationX, "FreezeXTranslation", - "Whether to freeze or not x-translation to certain value during computation.", {eTA2007::HDV}) - << AOpt2007(mFreezeTranslationY, "FreezeYTranslation", - "Whether to freeze or not y-translation to certain value during computation.", {eTA2007::HDV}) - << AOpt2007(mFreezeRadTranslation, "FreezeRadTranslation", - "Whether to freeze radiometry translation factor in computation or not.", {eTA2007::HDV}) - << AOpt2007(mFreezeRadScale, "FreezeRadScaling", - "Whether to freeze radiometry scaling factor in computation or not.", {eTA2007::HDV}) - << AOpt2007(mWeightRadTranslation, "WeightRadiometryTranslation", - "A value to weight radiometry translation for soft freezing of coefficient.", {eTA2007::HDV}) - << AOpt2007(mWeightRadScale, "WeightRadiometryScaling", - "A value to weight radiometry scaling for soft freezing of coefficient.", {eTA2007::HDV}) - << AOpt2007(mNumberOfIterGaussFilter, "NumberOfIterationsGaussFilter", - "Number of iterations to run in Gauss filter algorithm.", {eTA2007::HDV}) - << AOpt2007(mNumberOfEndIterations, "NumberOfEndIterations", - "Number of iterations to run on original images in multi-scale approach.", {eTA2007::HDV}) - << AOpt2007(mFolderSaveResult, "FolderToSaveResults", - "Folder name where to store produced results", {eTA2007::HDV}) - << AOpt2007(mDisplayLastTranslationValues, "DisplayLastTranslationsValues", - "Whether to display the final values of unknowns linked to point translation.", {eTA2007::HDV}) - << AOpt2007(mDisplayLastRadiometryValues, "DisplayLastRadiometryValues", - "Whether to display or not the last values of radiometry unknowns after optimisation process.", {eTA2007::HDV}); - } - - void cAppli_cTriangleDeformation::ConstructUniformRandomVectorAndApplyDelaunay(std::vector aVectorPts, const int aNumberOfPointsToGenerate, - const int aRandomUniformLawUpperBoundLines, const int aRandomUniformLawUpperBoundCols, - cTriangulation2D &aDelaunayTri) - { - aVectorPts.pop_back(); // eliminate initialisation values - // Generate coordinates from drawing lines and columns of coordinates from a uniform distribution - for (int aNbPt = 0; aNbPt < aNumberOfPointsToGenerate; aNbPt++) - { - const tREAL8 aUniformRandomLine = RandUnif_N(aRandomUniformLawUpperBoundLines); - const tREAL8 aUniformRandomCol = RandUnif_N(aRandomUniformLawUpperBoundCols); - const cPt2dr aUniformRandomPt(aUniformRandomCol, aUniformRandomLine); // cPt2dr format - aVectorPts.push_back(aUniformRandomPt); - } - aDelaunayTri = aVectorPts; - - aDelaunayTri.MakeDelaunay(); // Delaunay triangulate randomly generated points. - } - - void cAppli_cTriangleDeformation::GeneratePointsForDelaunay(std::vector aVectorPts, const int aNumberOfPointsToGenerate, - int aRandomUniformLawUpperBoundLines, int aRandomUniformLawUpperBoundCols, - cTriangulation2D &aDelaunayTri, const cPt2di &aSzImPre) - { - // If user hasn't defined another value than the default value, it is changed - if (aRandomUniformLawUpperBoundLines == 1 && aRandomUniformLawUpperBoundCols == 1) - { - // Maximum value of coordinates are drawn from [0, NumberOfImageLines[ for lines - aRandomUniformLawUpperBoundLines = aSzImPre.y(); - // Maximum value of coordinates are drawn from [0, NumberOfImageColumns[ for columns - aRandomUniformLawUpperBoundCols = aSzImPre.x(); - } - else - { - if (aRandomUniformLawUpperBoundLines != 1 && aRandomUniformLawUpperBoundCols == 1) - aRandomUniformLawUpperBoundCols = aSzImPre.x(); - else - { - if (aRandomUniformLawUpperBoundLines == 1 && aRandomUniformLawUpperBoundCols != 1) - aRandomUniformLawUpperBoundLines = aSzImPre.y(); - } - } - - ConstructUniformRandomVectorAndApplyDelaunay(aVectorPts, aNumberOfPointsToGenerate, - aRandomUniformLawUpperBoundLines, aRandomUniformLawUpperBoundCols, - aDelaunayTri); - } - - void cAppli_cTriangleDeformation::InitialisationAfterExe(cTriangulation2D &aDelaunayTri, - cResolSysNonLinear *&aSys) - { - const size_t aStartNumberPts = 4 * aDelaunayTri.NbPts(); - tDenseVect aVInit(aStartNumberPts, eModeInitImage::eMIA_Null); - - for (size_t aStartKtNumber = 0; aStartKtNumber < aStartNumberPts; aStartKtNumber++) - { - if (aStartKtNumber % 4 == 3) - aVInit(aStartKtNumber) = 1; - } - - aSys = new cResolSysNonLinear(eModeSSR::eSSR_LsqDense, aVInit); - } - - void cAppli_cTriangleDeformation::InitialisationBeforeIteration(cTriangulation2D &aDelaunayTri, - cResolSysNonLinear *&aSys) - { - const size_t aINumberPts = 4 * aDelaunayTri.NbPts(); - tDenseVect aVInitBeforeIteration(aINumberPts, eModeInitImage::eMIA_Null); - - tDenseVect aIntermediateVCur = aSys->CurGlobSol(); // Get current solution. - - for (size_t aITr = 0; aITr < aDelaunayTri.NbFace(); aITr++) - { - const cPt3di aIntermediateIndicesOfTriKnots = aDelaunayTri.KthFace(aITr); - - const tIntVect aIntermediateVecInd = {4 * aIntermediateIndicesOfTriKnots.x(), 4 * aIntermediateIndicesOfTriKnots.x() + 1, - 4 * aIntermediateIndicesOfTriKnots.y(), 4 * aIntermediateIndicesOfTriKnots.y() + 1, - 4 * aIntermediateIndicesOfTriKnots.z(), 4 * aIntermediateIndicesOfTriKnots.z() + 1}; - - for (size_t aIKnotNumber=0; aIKnotNumber < aIntermediateVecInd.size(); aIKnotNumber += 2) - { - aVInitBeforeIteration(aIntermediateVecInd.at(aIKnotNumber)) = aIntermediateVCur(aIntermediateVecInd.at(aIKnotNumber)); - aVInitBeforeIteration(aIntermediateVecInd.at(aIKnotNumber + 1)) = aIntermediateVCur(aIntermediateVecInd.at(aIKnotNumber + 1)); - } - } - - aSys = new cResolSysNonLinear(eModeSSR::eSSR_LsqDense, aVInitBeforeIteration); - } - - void cAppli_cTriangleDeformation::SubtractPrePostImageAndComputeAvgAndMax() - { - mImDiff = tIm(mSzImPre); - mDImDiff = &mImDiff.DIm(); - - for (const cPt2di &aDiffPix : *mDImDiff) - mDImDiff->SetV(aDiffPix, mDImPre->GetV(aDiffPix) - mDImPost->GetV(aDiffPix)); - const int aNumberOfPixelsInImage = mSzImPre.x() * mSzImPre.y(); - - tREAL8 aSumPixelValuesInDiffImage = 0; - tREAL8 aMaxPixelValuesInDiffImage = 0; - tREAL8 aDiffImPixelValue = 0; - for (const cPt2di &aDiffPix : *mDImDiff) - { - aDiffImPixelValue = mDImDiff->GetV(aDiffPix); - aSumPixelValuesInDiffImage += aDiffImPixelValue; - if (aDiffImPixelValue > aMaxPixelValuesInDiffImage) - aMaxPixelValuesInDiffImage = aDiffImPixelValue; - } - StdOut() << "The average value of the difference image between the Pre and Post images is : " - << aSumPixelValuesInDiffImage / (tREAL8)aNumberOfPixelsInImage << std::endl; - StdOut() << "The maximum value of the difference image between the Pre and Post images is : " - << aMaxPixelValuesInDiffImage << std::endl; - } - - cPt2dr cAppli_cTriangleDeformation::ApplyBarycenterTranslationFormulaToFilledPixel(const cPt2dr &aCurrentTranslationPointA, - const cPt2dr &aCurrentTranslationPointB, - const cPt2dr &aCurrentTranslationPointC, - const tDoubleVect &aVObs) - { - // apply current barycenter translation formula for x and y on current observations. - const tREAL8 aXTriCoord = aVObs[0] + aVObs[2] * aCurrentTranslationPointA.x() + aVObs[3] * aCurrentTranslationPointB.x() + - aVObs[4] * aCurrentTranslationPointC.x(); - const tREAL8 aYTriCoord = aVObs[1] + aVObs[2] * aCurrentTranslationPointA.y() + aVObs[3] * aCurrentTranslationPointB.y() + - aVObs[4] * aCurrentTranslationPointC.y(); - - const cPt2dr aCurrentTranslatedPixel = cPt2dr(aXTriCoord, aYTriCoord); - - return aCurrentTranslatedPixel; - } - - tREAL8 cAppli_cTriangleDeformation::ApplyBarycenterTranslationFormulaForTranslationRadiometry(const tREAL8 aCurrentRadTranslationPointA, - const tREAL8 aCurrentRadTranslationPointB, - const tREAL8 aCurrentRadTranslationPointC, - const tDoubleVect &aVObs) - { - const tREAL8 aCurentRadTranslation = aVObs[2] * aCurrentRadTranslationPointA + aVObs[3] * aCurrentRadTranslationPointB + - aVObs[4] * aCurrentRadTranslationPointC; - return aCurentRadTranslation; - } - - tREAL8 cAppli_cTriangleDeformation::ApplyBarycenterTranslationFormulaForScalingRadiometry(const tREAL8 aCurrentRadScalingPointA, - const tREAL8 aCurrentRadScalingPointB, - const tREAL8 aCurrentRadScalingPointC, - const tDoubleVect &aVObs) - { - const tREAL8 aCurrentRadScaling = aVObs[2] * aCurrentRadScalingPointA + aVObs[3] * aCurrentRadScalingPointB + - aVObs[4] * aCurrentRadScalingPointC; - return aCurrentRadScaling; - } - - void cAppli_cTriangleDeformation::LoadImageAndData(tIm &aCurIm, tDIm *&aCurDIm, const std::string &aPreOrPostImage, tIm &aImPre, tIm &aImPost) - { - (aPreOrPostImage == "pre") ? aCurIm = aImPre : aCurIm = aImPost; - aCurDIm = &aCurIm.DIm(); - } - - bool cAppli_cTriangleDeformation::ManageDifferentCasesOfEndIterations(const int aIterNumber, const int aNumberOfScales, const int aNumberOfEndIterations, - bool aIsLastIters, tIm &aImPre, tIm &aImPost, tIm aCurPreIm, tDIm *aCurPreDIm, - tIm aCurPostIm, tDIm *aCurPostDIm) - { - switch (aNumberOfEndIterations) - { - case 1: // one last iteration - if (aIterNumber == aNumberOfScales) - { - aIsLastIters = true; - LoadImageAndData(aCurPreIm, aCurPreDIm, "pre", aImPre, aImPost); - LoadImageAndData(aCurPostIm, aCurPostDIm, "post", aImPre, aImPost); - } - break; - case 2: // two last iterations - if ((aIterNumber == aNumberOfScales) || (aIterNumber == aNumberOfScales + aNumberOfEndIterations - 1)) - { - aIsLastIters = true; - LoadImageAndData(aCurPreIm, aCurPreDIm, "pre", aImPre, aImPost); - LoadImageAndData(aCurPostIm, aCurPostDIm, "post", aImPre, aImPost); - } - break; - case 3: // three last iterations - if ((aIterNumber == aNumberOfScales) || (aIterNumber == mNumberOfScales + aNumberOfEndIterations - 2) || - (aIterNumber == aNumberOfScales + aNumberOfEndIterations - 1)) - { - aIsLastIters = true; - LoadImageAndData(aCurPreIm, aCurPreDIm, "pre", aImPre, aImPost); - LoadImageAndData(aCurPostIm, aCurPostDIm, "post", aImPre, aImPost); - } - break; - default: // default is two last iterations - if ((aIterNumber == aNumberOfScales) || (aIterNumber == aNumberOfScales + aNumberOfEndIterations - 1)) - { - aIsLastIters = true; - LoadImageAndData(aCurPreIm, aCurPreDIm, "pre", aImPre, aImPost); - LoadImageAndData(aCurPostIm, aCurPostDIm, "post", aImPre, aImPost); - } - break; - } - return aIsLastIters; + << AOpt2007(mNumberOfCols, "MaximumValueNumberOfCols", + "Maximum value that the uniform law can draw from on the x-axis.", {eTA2007::HDV, eTA2007::Tuning}) + << AOpt2007(mNumberOfLines, "MaximumValueNumberOfLines", + "Maximum value that the uniform law can draw from for on the y-axis.", {eTA2007::HDV, eTA2007::Tuning}) + << AOpt2007(mShow, "Show", "Whether to print minimisation results.", {eTA2007::HDV, eTA2007::Tuning}) + << AOpt2007(mComputeAvgMax, "ComputeAvgMaxDiffIm", + "Whether to compute the average and maximum pixel value of the difference image between post and pre image or not.", {eTA2007::HDV, eTA2007::Tuning}) + << AOpt2007(mUseMultiScaleApproach, "UseMultiScaleApproach", "Whether to use multi-scale approach or not.", {eTA2007::HDV}) + << AOpt2007(mBuildRandomUniformGrid, "GenerateRandomUniformGrid", + "Whether to build a grid to be triangulated thanks to points generated randomly with a uniform law or build a grid made of rectangles.", {eTA2007::HDV}) + << AOpt2007(mInitialiseTranslationWithPreviousExecution, "InitialiseTranslationWithPreviousExecution", + "Whether to initialise or not with unknown translation values obtained at previous execution", {eTA2007::HDV}) + << AOpt2007(mInitialiseRadiometryWithPreviousExecution, "InitialiseRadiometryWithPreviousExecution", + "Whether to initialise or not with unknown radiometry values obtained at previous execution", {eTA2007::HDV}) + << AOpt2007(mInitialiseWithUserValues, "InitialiseWithUserValues", + "Whether the user wishes or not to initialise unknowns with personalised values.", {eTA2007::HDV}) + << AOpt2007(mInitialiseXTranslationValue, "InitialXTranslationValue", + "Value to use for initialising x-translation unknowns.", {eTA2007::HDV}) + << AOpt2007(mInitialiseYTranslationValue, "InitialYTranslationValue", + "Value to use for initialising y-translation unknowns.", {eTA2007::HDV}) + << AOpt2007(mInitialiseRadTrValue, "InitialeRadiometryTranslationValue", + "Value to use for initialising radiometry translation unknown values", {eTA2007::HDV}) + << AOpt2007(mInitialiseRadScValue, "InitialeRadiometryScalingValue", + "Value to use for initialising radiometry scaling unknown values", {eTA2007::HDV}) + << AOpt2007(mInitialiseWithMMVI, "InitialiseWithMMVI", + "Whether to initialise or not values of unknowns with pre-computed values from MicMacV1 at first execution", {eTA2007::HDV}) + + << AOpt2007(mNameInitialDepX, "InitialDispXMapFilename", "Name of file of initial X-displacement map", {eTA2007::HDV, eTA2007::FileImage}) + << AOpt2007(mNameInitialDepY, "InitialDispYMapFilename", "Name of file of initial Y-displacement map", {eTA2007::HDV, eTA2007::FileImage}) + << AOpt2007(mNameIntermediateDepX, "NameForIntermediateXDispMap", + "File name to use when saving intermediate x-displacement maps between executions", {eTA2007::HDV, eTA2007::FileImage, eTA2007::Tuning}) + << AOpt2007(mNameIntermediateDepY, "NameForIntermediateYDispMap", + "File name to use when saving intermediate y-displacement maps between executions", {eTA2007::HDV, eTA2007::FileImage, eTA2007::Tuning}) + << AOpt2007(mNameCorrelationMaskMMVI, "NameOfCorrelationMask", + "File name of mask file from MMVI giving locations where correlation is computed", {eTA2007::HDV, eTA2007::FileImage}) + << AOpt2007(mIsFirstExecution, "IsFirstExecution", + "Whether this is the first execution of optimisation algorithm or not", {eTA2007::HDV}) + << AOpt2007(mSigmaGaussFilterStep, "SigmaGaussFilterStep", "Sigma value to use for Gauss filter in multi-stage approach.", {eTA2007::HDV, eTA2007::Tuning}) + << AOpt2007(mGenerateDisplacementImage, "GenerateDisplacementImage", + "Whether to generate and save an image having been translated.", {eTA2007::HDV}) + << AOpt2007(mFreezeTranslationX, "FreezeXTranslation", + "Whether to freeze or not x-translation to certain value during computation.", {eTA2007::HDV}) + << AOpt2007(mFreezeTranslationY, "FreezeYTranslation", + "Whether to freeze or not y-translation to certain value during computation.", {eTA2007::HDV}) + << AOpt2007(mFreezeRadTranslation, "FreezeRadTranslation", + "Whether to freeze radiometry translation factor in computation or not.", {eTA2007::HDV}) + << AOpt2007(mFreezeRadScale, "FreezeRadScaling", + "Whether to freeze radiometry scaling factor in computation or not.", {eTA2007::HDV}) + << AOpt2007(mWeightRadTranslation, "WeightRadiometryTranslation", + "A value to weight radiometry translation for soft freezing of coefficient.", {eTA2007::HDV}) + << AOpt2007(mWeightRadScale, "WeightRadiometryScaling", + "A value to weight radiometry scaling for soft freezing of coefficient.", {eTA2007::HDV}) + << AOpt2007(mNumberOfIterGaussFilter, "NumberOfIterationsGaussFilter", + "Number of iterations to run in Gauss filter algorithm.", {eTA2007::HDV, eTA2007::Tuning}) + << AOpt2007(mNumberOfEndIterations, "NumberOfEndIterations", + "Number of iterations to run on original images in multi-scale approach.", {eTA2007::HDV, eTA2007::Tuning}) + << AOpt2007(mFolderSaveResult, "FolderToSaveResults", + "Folder name where to store produced results", {eTA2007::HDV}) + << AOpt2007(mDisplayLastTranslationValues, "DisplayLastTranslationsValues", + "Whether to display the final values of unknowns linked to point translation.", {eTA2007::HDV}) + << AOpt2007(mDisplayLastRadiometryValues, "DisplayLastRadiometryValues", + "Whether to display or not the last values of radiometry unknowns after optimisation process.", {eTA2007::HDV}); } - void cAppli_cTriangleDeformation::LoopOverTrianglesAndUpdateParameters(const int aIterNumber, const bool aUserDefinedFolderName) + void cAppli_TriangleDeformation::LoopOverTrianglesAndUpdateParameters(const int aIterNumber, const int aTotalNumberOfIterations, + const bool aUserDefinedFolderName) { //----------- allocate vec of obs : tDoubleVect aVObs(12, 0.0); // 6 for ImagePre and 6 for ImagePost @@ -352,13 +181,6 @@ namespace MMVII StdOut() << aVCur(aUnk) << " " ; StdOut() << std::endl; */ - bool aUserDefinedDir = false; - if (!mFolderSaveResult.empty()) - { - aUserDefinedDir = true; - if (!std::filesystem::exists(mFolderSaveResult)) - std::filesystem::create_directory(mFolderSaveResult); - } tIm aCurPreIm = tIm(mSzImPre); tDIm *aCurPreDIm = nullptr; @@ -373,8 +195,8 @@ namespace MMVII aCurPostIm, aCurPostDIm); else { - LoadImageAndData(aCurPreIm, aCurPreDIm, "pre", mImPre, mImPost); - LoadImageAndData(aCurPostIm, aCurPostDIm, "post", mImPre, mImPost); + LoadPrePostImageAndData(aCurPreIm, aCurPreDIm, "pre", mImPre, mImPost); + LoadPrePostImageAndData(aCurPostIm, aCurPostDIm, "post", mImPre, mImPost); } if (mUseMultiScaleApproach && !mIsLastIters) @@ -390,16 +212,16 @@ namespace MMVII const bool aSaveGaussImage = false; // if a save of image filtered by Gauss filter is wanted if (aSaveGaussImage) { - if (aUserDefinedDir) - aCurPreDIm->ToFile(mFolderSaveResult + "/GaussFilteredImPre_iter_" + std::to_string(aIterNumber) + ".tif"); + if (aUserDefinedFolderName) + aCurPreDIm->ToFile(mFolderSaveResult + "/GaussFilteredImPre_iter_" + ToStr(aIterNumber) + ".tif"); else - aCurPreDIm->ToFile("GaussFilteredImPre_iter_" + std::to_string(aIterNumber) + ".tif"); + aCurPreDIm->ToFile("GaussFilteredImPre_iter_" + ToStr(aIterNumber) + ".tif"); } } else if (mUseMultiScaleApproach && mIsLastIters) { - LoadImageAndData(aCurPreIm, aCurPreDIm, "pre", mImPre, mImPost); - LoadImageAndData(aCurPostIm, aCurPostDIm, "post", mImPre, mImPost); + LoadPrePostImageAndData(aCurPreIm, aCurPreDIm, "pre", mImPre, mImPost); + LoadPrePostImageAndData(aCurPostIm, aCurPostDIm, "post", mImPre, mImPost); } //----------- declaration of indicators of convergence @@ -415,7 +237,7 @@ namespace MMVII { for (size_t aTr = 0; aTr < mDelTri.NbFace(); aTr++) { - const cPt3di aIndicesOfTriKnots = mDelTri.KthFace(aTr); + const tPt3di aIndicesOfTriKnots = mDelTri.KthFace(aTr); const tIntVect aVecInd = {4 * aIndicesOfTriKnots.x(), 4 * aIndicesOfTriKnots.x() + 1, 4 * aIndicesOfTriKnots.x() + 2, 4 * aIndicesOfTriKnots.x() + 3, @@ -426,27 +248,27 @@ namespace MMVII if (mFreezeTranslationX) { - mSys->SetFrozenVar(aVecInd.at(2), aVCur(0)); - mSys->SetFrozenVar(aVecInd.at(6), aVCur(4)); - mSys->SetFrozenVar(aVecInd.at(10), aVCur(8)); + mSys->SetFrozenVar(aVecInd.at(0), aVCur(aVecInd.at(0))); + mSys->SetFrozenVar(aVecInd.at(4), aVCur(aVecInd.at(4))); + mSys->SetFrozenVar(aVecInd.at(8), aVCur(aVecInd.at(8))); } if (mFreezeTranslationY) { - mSys->SetFrozenVar(aVecInd.at(2), aVCur(1)); - mSys->SetFrozenVar(aVecInd.at(6), aVCur(5)); - mSys->SetFrozenVar(aVecInd.at(10), aVCur(9)); + mSys->SetFrozenVar(aVecInd.at(1), aVCur(aVecInd.at(1))); + mSys->SetFrozenVar(aVecInd.at(5), aVCur(aVecInd.at(5))); + mSys->SetFrozenVar(aVecInd.at(9), aVCur(aVecInd.at(9))); } if (mFreezeRadTranslation) { - mSys->SetFrozenVar(aVecInd.at(2), aVCur(2)); - mSys->SetFrozenVar(aVecInd.at(6), aVCur(6)); - mSys->SetFrozenVar(aVecInd.at(10), aVCur(10)); + mSys->SetFrozenVar(aVecInd.at(2), aVCur(aVecInd.at(2))); + mSys->SetFrozenVar(aVecInd.at(6), aVCur(aVecInd.at(6))); + mSys->SetFrozenVar(aVecInd.at(10), aVCur(aVecInd.at(10))); } if (mFreezeRadScale) { - mSys->SetFrozenVar(aVecInd.at(3), aVCur(3)); - mSys->SetFrozenVar(aVecInd.at(7), aVCur(7)); - mSys->SetFrozenVar(aVecInd.at(11), aVCur(11)); + mSys->SetFrozenVar(aVecInd.at(3), aVCur(aVecInd.at(3))); + mSys->SetFrozenVar(aVecInd.at(7), aVCur(aVecInd.at(7))); + mSys->SetFrozenVar(aVecInd.at(11), aVCur(aVecInd.at(11))); } } } @@ -455,11 +277,11 @@ namespace MMVII for (size_t aTr = 0; aTr < mDelTri.NbFace(); aTr++) { const tTri2dr aTri = mDelTri.KthTri(aTr); - const cPt3di aIndicesOfTriKnots = mDelTri.KthFace(aTr); + const tPt3di aIndicesOfTriKnots = mDelTri.KthFace(aTr); const cTriangle2DCompiled aCompTri(aTri); - std::vector aVectorToFillWithInsidePixels; + std::vector aVectorToFillWithInsidePixels; aCompTri.PixelsInside(aVectorToFillWithInsidePixels); // get pixels inside triangle //----------- index of unknown, finds the associated pixels of current triangle @@ -470,19 +292,20 @@ namespace MMVII 4 * aIndicesOfTriKnots.z(), 4 * aIndicesOfTriKnots.z() + 1, 4 * aIndicesOfTriKnots.z() + 2, 4 * aIndicesOfTriKnots.z() + 3}; - const cPt2dr aCurTrPointA = cPt2dr(aVCur(aVecInd.at(0)), - aVCur(aVecInd.at(1))); // current translation 1st point of triangle - const cPt2dr aCurTrPointB = cPt2dr(aVCur(aVecInd.at(4)), - aVCur(aVecInd.at(5))); // current translation 2nd point of triangle - const cPt2dr aCurTrPointC = cPt2dr(aVCur(aVecInd.at(8)), - aVCur(aVecInd.at(9))); // current translation 3rd point of triangle + const cNodeOfTriangles aFirstPointOfTri = cNodeOfTriangles(aVCur, aVecInd, 0, 1, 2, 3, aTri, 0); + const cNodeOfTriangles aSecondPointOfTri = cNodeOfTriangles(aVCur, aVecInd, 4, 5, 6, 7, aTri, 1); + const cNodeOfTriangles aThirdPointOfTri = cNodeOfTriangles(aVCur, aVecInd, 8, 9, 10, 11, aTri, 2); + + const tPt2dr aCurTrPointA = aFirstPointOfTri.GetCurrentXYDisplacementValues(); // current translation 1st point of triangle + const tPt2dr aCurTrPointB = aSecondPointOfTri.GetCurrentXYDisplacementValues(); // current translation 2nd point of triangle + const tPt2dr aCurTrPointC = aThirdPointOfTri.GetCurrentXYDisplacementValues(); // current translation 3rd point of triangle - const tREAL8 aCurRadTrPointA = aVCur(aVecInd.at(2)); // current translation on radiometry 1st point of triangle - const tREAL8 aCurRadScPointA = aVCur(aVecInd.at(3)); // current scale on radiometry 3rd point of triangle - const tREAL8 aCurRadTrPointB = aVCur(aVecInd.at(6)); // current translation on radiometry 2nd point of triangle - const tREAL8 aCurRadScPointB = aVCur(aVecInd.at(7)); // current scale on radiometry 3rd point of triangle - const tREAL8 aCurRadTrPointC = aVCur(aVecInd.at(10)); // current translation on radiometry 3rd point of triangle - const tREAL8 aCurRadScPointC = aVCur(aVecInd.at(11)); // current scale on radiometry 3rd point of triangle + const tREAL8 aCurRadTrPointA = aFirstPointOfTri.GetCurrentRadiometryTranslation(); // current translation on radiometry 1st point of triangle + const tREAL8 aCurRadScPointA = aFirstPointOfTri.GetCurrentRadiometryScaling(); // current scale on radiometry 3rd point of triangle + const tREAL8 aCurRadTrPointB = aSecondPointOfTri.GetCurrentRadiometryTranslation(); // current translation on radiometry 2nd point of triangle + const tREAL8 aCurRadScPointB = aSecondPointOfTri.GetCurrentRadiometryScaling(); // current scale on radiometry 3rd point of triangle + const tREAL8 aCurRadTrPointC = aThirdPointOfTri.GetCurrentRadiometryTranslation(); // current translation on radiometry 3rd point of triangle + const tREAL8 aCurRadScPointC = aThirdPointOfTri.GetCurrentRadiometryScaling(); // current scale on radiometry 3rd point of triangle // soft constraint radiometric translation if (!mFreezeRadTranslation) @@ -521,12 +344,12 @@ namespace MMVII for (size_t aFilledPixel = 0; aFilledPixel < aNumberOfInsidePixels; aFilledPixel++) { const cPtInsideTriangles aPixInsideTriangle = cPtInsideTriangles(aCompTri, aVectorToFillWithInsidePixels, - aFilledPixel, *aCurPreDIm); + aFilledPixel, aCurPreDIm); // prepare for barycenter translation formula by filling aVObs with different coordinates FormalInterpBarycenter_SetObs(aVObs, 0, aPixInsideTriangle); // image of a point in triangle by current translation - const cPt2dr aTranslatedFilledPoint = ApplyBarycenterTranslationFormulaToFilledPixel(aCurTrPointA, aCurTrPointB, + const tPt2dr aTranslatedFilledPoint = ApplyBarycenterTranslationFormulaToFilledPixel(aCurTrPointA, aCurTrPointB, aCurTrPointC, aVObs); // radiometry translation of pixel by current radiometry translation of triangle knots const tREAL8 aRadiometryTranslation = ApplyBarycenterTranslationFormulaForTranslationRadiometry(aCurRadTrPointA, @@ -549,7 +372,7 @@ namespace MMVII // compute indicators const tREAL8 aRadiomValueImPre = aRadiometryScaling * aVObs[5] + aRadiometryTranslation; - const tREAL8 aDif = aRadiomValueImPre - aCurPostDIm->GetVBL(aTranslatedFilledPoint); // residual + const tREAL8 aDif = aRadiomValueImPre - aCurPostDIm->GetVBL(aTranslatedFilledPoint); // residual : IntensiteImPreWithRadiometry - TranslatedCoordImPost aSomDif += std::abs(aDif); } else @@ -563,7 +386,7 @@ namespace MMVII { const bool aGenerateIntermediateMaps = false; // if a generating intermediate displacement maps is wanted if (aGenerateIntermediateMaps) - GenerateDisplacementMapsAndOutputImages(aVCur, aIterNumber, aUserDefinedDir); + GenerateDisplacementMapsAndOutputImages(aVCur, aIterNumber, aTotalNumberOfIterations, aUserDefinedFolderName); } // Update all parameter taking into account previous observation @@ -574,69 +397,19 @@ namespace MMVII << ", " << aNbOut << std::endl; } - void cAppli_cTriangleDeformation::FillDisplacementMapsAndOutputImage(const cPtInsideTriangles &aLastPixInsideTriangle, - const cPt2dr &aLastTranslatedFilledPoint, - const tREAL8 aLastRadiometryTranslation, - const tREAL8 aLastRadiometryScaling) - { - const tREAL8 aLastXCoordinate = aLastPixInsideTriangle.GetCartesianCoordinates().x(); - const tREAL8 aLastYCoordinate = aLastPixInsideTriangle.GetCartesianCoordinates().y(); - const tREAL8 aLastPixelValue = aLastPixInsideTriangle.GetPixelValue(); - - const cPt2di aLastCoordinate = cPt2di(aLastXCoordinate, aLastYCoordinate); - mDImDepX->SetV(aLastCoordinate, - aLastTranslatedFilledPoint.x() - aLastXCoordinate); - mDImDepY->SetV(aLastCoordinate, - aLastTranslatedFilledPoint.y() - aLastYCoordinate); - const tREAL8 aLastXTranslatedCoord = aLastXCoordinate + mDImDepX->GetV(aLastCoordinate); - const tREAL8 aLastYTranslatedCoord = aLastYCoordinate + mDImDepY->GetV(aLastCoordinate); - - const tREAL8 aLastRadiometryValue = aLastRadiometryScaling * aLastPixelValue + - aLastRadiometryTranslation; - - // Build image with intensities displaced - // deal with different cases of pixel being translated out of image - if (aLastXTranslatedCoord < 0 && aLastYTranslatedCoord < 0) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(0, 0))); - else if (aLastXTranslatedCoord >= mSzImOut.x() && aLastYTranslatedCoord >= mSzImOut.y()) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(mSzImOut.x() - 1, mSzImOut.y() - 1))); - else if (aLastXTranslatedCoord < 0 && aLastYTranslatedCoord >= mSzImOut.y()) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(0, mSzImOut.y() - 1))); - else if (aLastXTranslatedCoord >= mSzImOut.x() && aLastYTranslatedCoord < 0) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(mSzImOut.x() - 1, 0))); - else if (aLastXTranslatedCoord >= 0 && aLastXTranslatedCoord < mSzImOut.x() && - aLastYTranslatedCoord < 0) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(aLastXTranslatedCoord, 0))); - else if (aLastXTranslatedCoord >= 0 && aLastXTranslatedCoord < mSzImOut.x() && - aLastYTranslatedCoord > mSzImOut.y()) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(aLastXTranslatedCoord, mSzImOut.y() - 1))); - else if (aLastYTranslatedCoord >= 0 && aLastYTranslatedCoord < mSzImOut.y() && - aLastXTranslatedCoord < 0) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(0, aLastYTranslatedCoord))); - else if (aLastYTranslatedCoord >= 0 && aLastYTranslatedCoord < mSzImOut.y() && - aLastXTranslatedCoord > mSzImOut.x()) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(mSzImOut.x() - 1, aLastYTranslatedCoord))); - else - // at the translated pixel the untranslated pixel value is given computed with the right radiometry values - mDImOut->SetV(cPt2di(aLastXTranslatedCoord, aLastYTranslatedCoord), aLastRadiometryValue); - } - - void cAppli_cTriangleDeformation::GenerateDisplacementMapsAndOutputImages(const tDenseVect &aVFinalSol, const int aIterNumber, - const bool aUserDefinedFolderName) + void cAppli_TriangleDeformation::GenerateDisplacementMapsAndOutputImages(const tDenseVect &aVFinalSol, const int aIterNumber, + const int aTotalNumberOfIterations, const bool aUserDefinedFolderName) { mImOut = tIm(mSzImPre); mDImOut = &mImOut.DIm(); - mSzImOut = cPt2di(mDImOut->Sz().x(), mDImOut->Sz().y()); + mSzImOut = mDImOut->Sz(); - mImDepX = tIm(mSzImPre, 0, eModeInitImage::eMIA_Null); - mDImDepX = &mImDepX.DIm(); - - mImDepY = tIm(mSzImPre, 0, eModeInitImage::eMIA_Null); - mDImDepY = &mImDepY.DIm(); + InitialiseDisplacementMaps(mSzImPre, mImDepX, mDImDepX, mSzImDepX); + InitialiseDisplacementMaps(mSzImPre, mImDepY, mDImDepY, mSzImDepY); tIm aLastPreIm = tIm(mSzImPre); tDIm *aLastPreDIm = nullptr; - LoadImageAndData(aLastPreIm, aLastPreDIm, "pre", mImPre, mImPost); + LoadPrePostImageAndData(aLastPreIm, aLastPreDIm, "pre", mImPre, mImPost); if (mUseMultiScaleApproach && !mIsLastIters) { @@ -646,59 +419,53 @@ namespace MMVII tDoubleVect aLastVObs(12, 0.0); - for (const cPt2di &aOutPix : *mDImOut) // Initialise output images + // Prefill output image with ImPre to not have null values + for (const tPt2di &aOutPix : *mDImOut) mDImOut->SetV(aOutPix, aLastPreDIm->GetV(aOutPix)); for (size_t aLTr = 0; aLTr < mDelTri.NbFace(); aLTr++) { const tTri2dr aLastTri = mDelTri.KthTri(aLTr); - const cPt3di aLastIndicesOfTriKnots = mDelTri.KthFace(aLTr); + const tPt3di aLastIndicesOfTriKnots = mDelTri.KthFace(aLTr); const cTriangle2DCompiled aLastCompTri(aLastTri); - std::vector aLastVectorToFillWithInsidePixels; + std::vector aLastVectorToFillWithInsidePixels; aLastCompTri.PixelsInside(aLastVectorToFillWithInsidePixels); - const tIntVect aLastVecInd = { - 4 * aLastIndicesOfTriKnots.x(), - 4 * aLastIndicesOfTriKnots.x() + 1, - 4 * aLastIndicesOfTriKnots.x() + 2, - 4 * aLastIndicesOfTriKnots.x() + 3, - 4 * aLastIndicesOfTriKnots.y(), - 4 * aLastIndicesOfTriKnots.y() + 1, - 4 * aLastIndicesOfTriKnots.y() + 2, - 4 * aLastIndicesOfTriKnots.y() + 3, - 4 * aLastIndicesOfTriKnots.z(), - 4 * aLastIndicesOfTriKnots.z() + 1, - 4 * aLastIndicesOfTriKnots.z() + 2, - 4 * aLastIndicesOfTriKnots.z() + 3, - }; - - const cPt2dr aLastTrPointA = cPt2dr(aVFinalSol(aLastVecInd.at(0)), - aVFinalSol(aLastVecInd.at(1))); // last translation 1st point of triangle - const cPt2dr aLastTrPointB = cPt2dr(aVFinalSol(aLastVecInd.at(4)), - aVFinalSol(aLastVecInd.at(5))); // last translation 2nd point of triangle - const cPt2dr aLastTrPointC = cPt2dr(aVFinalSol(aLastVecInd.at(8)), - aVFinalSol(aLastVecInd.at(9))); // last translation 3rd point of triangle - - const tREAL8 aLastRadTrPointA = aVFinalSol(aLastVecInd.at(2)); // last translation on radiometry 1st point of triangle - const tREAL8 aLastRadScPointA = aVFinalSol(aLastVecInd.at(3)); // last scale on radiometry 3rd point of triangle - const tREAL8 aLastRadTrPointB = aVFinalSol(aLastVecInd.at(6)); // last translation on radiometry 2nd point of triangle - const tREAL8 aLastRadScPointB = aVFinalSol(aLastVecInd.at(7)); // last scale on radiometry 3rd point of triangle - const tREAL8 aLastRadTrPointC = aVFinalSol(aLastVecInd.at(10)); // last translation on radiometry 3rd point of triangle - const tREAL8 aLastRadScPointC = aVFinalSol(aLastVecInd.at(11)); // last scale on radiometry 3rd point of triangle + const tIntVect aLastVecInd = {4 * aLastIndicesOfTriKnots.x(), 4 * aLastIndicesOfTriKnots.x() + 1, + 4 * aLastIndicesOfTriKnots.x() + 2, 4 * aLastIndicesOfTriKnots.x() + 3, + 4 * aLastIndicesOfTriKnots.y(), 4 * aLastIndicesOfTriKnots.y() + 1, + 4 * aLastIndicesOfTriKnots.y() + 2, 4 * aLastIndicesOfTriKnots.y() + 3, + 4 * aLastIndicesOfTriKnots.z(), 4 * aLastIndicesOfTriKnots.z() + 1, + 4 * aLastIndicesOfTriKnots.z() + 2, 4 * aLastIndicesOfTriKnots.z() + 3}; + + const cNodeOfTriangles aLastFirstPointOfTri = cNodeOfTriangles(aVFinalSol, aLastVecInd, 0, 1, 2, 3, aLastTri, 0); + const cNodeOfTriangles aLastSecondPointOfTri = cNodeOfTriangles(aVFinalSol, aLastVecInd, 4, 5, 6, 7, aLastTri, 1); + const cNodeOfTriangles aLastThirdPointOfTri = cNodeOfTriangles(aVFinalSol, aLastVecInd, 8, 9, 10, 11, aLastTri, 2); + + const tPt2dr aLastTrPointA = aLastFirstPointOfTri.GetCurrentXYDisplacementValues(); + const tPt2dr aLastTrPointB = aLastSecondPointOfTri.GetCurrentXYDisplacementValues(); + const tPt2dr aLastTrPointC = aLastThirdPointOfTri.GetCurrentXYDisplacementValues(); + + const tREAL8 aLastRadTrPointA = aLastFirstPointOfTri.GetCurrentRadiometryTranslation(); + const tREAL8 aLastRadScPointA = aLastFirstPointOfTri.GetCurrentRadiometryScaling(); + const tREAL8 aLastRadTrPointB = aLastSecondPointOfTri.GetCurrentRadiometryTranslation(); + const tREAL8 aLastRadScPointB = aLastSecondPointOfTri.GetCurrentRadiometryScaling(); + const tREAL8 aLastRadTrPointC = aLastThirdPointOfTri.GetCurrentRadiometryTranslation(); + const tREAL8 aLastRadScPointC = aLastThirdPointOfTri.GetCurrentRadiometryScaling(); const size_t aLastNumberOfInsidePixels = aLastVectorToFillWithInsidePixels.size(); for (size_t aLastFilledPixel = 0; aLastFilledPixel < aLastNumberOfInsidePixels; aLastFilledPixel++) { const cPtInsideTriangles aLastPixInsideTriangle = cPtInsideTriangles(aLastCompTri, aLastVectorToFillWithInsidePixels, - aLastFilledPixel, *aLastPreDIm); + aLastFilledPixel, aLastPreDIm); // prepare for barycenter translation formula by filling aVObs with different coordinates FormalInterpBarycenter_SetObs(aLastVObs, 0, aLastPixInsideTriangle); // image of a point in triangle by current translation - const cPt2dr aLastTranslatedFilledPoint = ApplyBarycenterTranslationFormulaToFilledPixel(aLastTrPointA, aLastTrPointB, + const tPt2dr aLastTranslatedFilledPoint = ApplyBarycenterTranslationFormulaToFilledPixel(aLastTrPointA, aLastTrPointB, aLastTrPointC, aLastVObs); const tREAL8 aLastRadiometryTranslation = ApplyBarycenterTranslationFormulaForTranslationRadiometry(aLastRadTrPointA, @@ -712,7 +479,8 @@ namespace MMVII aLastVObs); FillDisplacementMapsAndOutputImage(aLastPixInsideTriangle, aLastTranslatedFilledPoint, - aLastRadiometryTranslation, aLastRadiometryScaling); + aLastRadiometryTranslation, aLastRadiometryScaling, + mSzImOut, mDImDepX, mDImDepY, mDImOut); } } @@ -721,141 +489,110 @@ namespace MMVII { if (aUserDefinedFolderName) { - mDImDepX->ToFile(mFolderSaveResult + "/DisplacedPixelsX_iter_" + std::to_string(aIterNumber) + "_" + - std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales + mNumberOfEndIterations) + ".tif"); - mDImDepY->ToFile(mFolderSaveResult + "/DisplacedPixelsY_iter_" + std::to_string(aIterNumber) + "_" + - std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales + mNumberOfEndIterations) + ".tif"); + mDImDepX->ToFile(mFolderSaveResult + "/DisplacedPixelsX_iter_" + ToStr(aIterNumber) + "_" + + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); + mDImDepY->ToFile(mFolderSaveResult + "/DisplacedPixelsY_iter_" + ToStr(aIterNumber) + "_" + + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); } else { - mDImDepX->ToFile("DisplacedPixelsX_iter_" + std::to_string(aIterNumber) + "_" + - std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales + mNumberOfEndIterations) + ".tif"); - mDImDepY->ToFile("DisplacedPixelsY_iter_" + std::to_string(aIterNumber) + "_" + - std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales + mNumberOfEndIterations) + ".tif"); + mDImDepX->ToFile("DisplacedPixelsX_iter_" + ToStr(aIterNumber) + "_" + + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); + mDImDepY->ToFile("DisplacedPixelsY_iter_" + ToStr(aIterNumber) + "_" + + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); } - if (aIterNumber == mNumberOfScales + mNumberOfEndIterations - 1) + if (aIterNumber == aTotalNumberOfIterations - 1) { if (aUserDefinedFolderName) - mDImOut->ToFile(mFolderSaveResult + "/DisplacedPixels_iter_" + std::to_string(aIterNumber) + "_" + - std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales + mNumberOfEndIterations) + ".tif"); + mDImOut->ToFile(mFolderSaveResult + "/DisplacedPixels_iter_" + ToStr(aIterNumber) + "_" + + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); else - mDImOut->ToFile("DisplacedPixels_iter_" + std::to_string(aIterNumber) + "_" + - std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales + mNumberOfEndIterations) + ".tif"); + mDImOut->ToFile("DisplacedPixels_iter_" + ToStr(aIterNumber) + "_" + + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); } } + else if (mInitialiseTranslationWithPreviousExecution) + { + mDImDepX->ToFile(mNameIntermediateDepX + ".tif"); + mDImDepY->ToFile(mNameIntermediateDepY + ".tif"); + } else { if (aUserDefinedFolderName) { - mDImDepX->ToFile(mFolderSaveResult + "/DisplacedPixelsX_" + std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales) + ".tif"); - mDImDepY->ToFile(mFolderSaveResult + "/DisplacedPixelsY_" + std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales) + ".tif"); - mDImOut->ToFile(mFolderSaveResult + "/DisplacedPixels_" + std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales) + ".tif"); + mDImDepX->ToFile(mFolderSaveResult + "/DisplacedPixelsX_" + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); + mDImDepY->ToFile(mFolderSaveResult + "/DisplacedPixelsY_" + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); + mDImOut->ToFile(mFolderSaveResult + "/DisplacedPixels_" + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); } else { - mDImDepX->ToFile("DisplacedPixelsX_" + std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales) + ".tif"); - mDImDepY->ToFile("DisplacedPixelsY_" + std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales) + ".tif"); - mDImOut->ToFile("DisplacedPixels_" + std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales) + ".tif"); - } - } - } - - void cAppli_cTriangleDeformation::DisplayLastUnknownValues(const tDenseVect &aVFinalSol, const bool aDisplayLastRadiometryValues, - const bool aDisplayLastTranslationValues) - { - if (aDisplayLastRadiometryValues && aDisplayLastTranslationValues) - { - for (int aFinalUnk = 0; aFinalUnk < aVFinalSol.DIm().Sz(); aFinalUnk++) - { - StdOut() << aVFinalSol(aFinalUnk) << " "; - if (aFinalUnk % 4 == 3 && aFinalUnk != 0) - StdOut() << std::endl; - } - } - if (aDisplayLastRadiometryValues && !aDisplayLastTranslationValues) - { - for (int aFinalUnk = 0; aFinalUnk < aVFinalSol.DIm().Sz(); aFinalUnk++) - { - if (aFinalUnk % 4 == 0 || aFinalUnk % 4 == 1) - StdOut() << aVFinalSol(aFinalUnk) << " "; - if (aFinalUnk % 4 == 3 && aFinalUnk != 0) - StdOut() << std::endl; - } - } - else if (aDisplayLastRadiometryValues && !aDisplayLastTranslationValues) - { - for (int aFinalUnk = 0; aFinalUnk < aVFinalSol.DIm().Sz(); aFinalUnk++) - { - if (aFinalUnk % 4 == 2 || aFinalUnk % 4 == 3) - StdOut() << aVFinalSol(aFinalUnk) << " "; - if (aFinalUnk % 4 == 3 && aFinalUnk != 0) - StdOut() << std::endl; + mDImDepX->ToFile("DisplacedPixelsX_" + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); + mDImDepY->ToFile("DisplacedPixelsY_" + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); + mDImOut->ToFile("DisplacedPixels_" + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); } } } - void cAppli_cTriangleDeformation::GenerateDisplacementMapsAndDisplayLastValuesUnknowns(const int aIterNumber, const bool aDisplayLastRadiometryValues, - const bool aDisplayLastTranslationValues, const bool aUserDefinedFolderName) + void cAppli_TriangleDeformation::GenerateDisplacementMapsAndDisplayLastValuesUnknowns(const int aIterNumber, const int aTotalNumberOfIterations, + const bool aDisplayLastRadiometryValues, const bool aDisplayLastTranslationValues, + const bool aUserDefinedFolderName) { tDenseVect aVFinalSol = mSys->CurGlobSol(); if (mGenerateDisplacementImage) - GenerateDisplacementMapsAndOutputImages(aVFinalSol, aIterNumber, aUserDefinedFolderName); + GenerateDisplacementMapsAndOutputImages(aVFinalSol, aIterNumber, aTotalNumberOfIterations, aUserDefinedFolderName); if (aDisplayLastRadiometryValues || aDisplayLastTranslationValues) DisplayLastUnknownValues(aVFinalSol, aDisplayLastRadiometryValues, aDisplayLastTranslationValues); } - void cAppli_cTriangleDeformation::DoOneIteration(const int aIterNumber, const bool aUserDefinedFolderName) + void cAppli_TriangleDeformation::DoOneIteration(const int aIterNumber, const int aTotalNumberOfIterations, + const bool aUserDefinedFolderName) { - LoopOverTrianglesAndUpdateParameters(aIterNumber, aUserDefinedFolderName); // Iterate over triangles and solve system + LoopOverTrianglesAndUpdateParameters(aIterNumber, aTotalNumberOfIterations, + aUserDefinedFolderName); // Iterate over triangles and solve system // Show final translation results and produce displacement maps - if (mUseMultiScaleApproach) - { - if (aIterNumber == (mNumberOfScales + mNumberOfEndIterations - 1)) - GenerateDisplacementMapsAndDisplayLastValuesUnknowns(aIterNumber, mDisplayLastRadiometryValues, - mDisplayLastTranslationValues, aUserDefinedFolderName); - } - else - { - if (aIterNumber == (mNumberOfScales - 1)) - GenerateDisplacementMapsAndDisplayLastValuesUnknowns(aIterNumber, mDisplayLastRadiometryValues, - mDisplayLastTranslationValues, aUserDefinedFolderName); - } + if (aIterNumber == (aTotalNumberOfIterations - 1)) + GenerateDisplacementMapsAndDisplayLastValuesUnknowns(aIterNumber, aTotalNumberOfIterations, + mDisplayLastRadiometryValues, mDisplayLastTranslationValues, + aUserDefinedFolderName); } //----------------------------------------- - int cAppli_cTriangleDeformation::Exe() + int cAppli_TriangleDeformation::Exe() { - // read pre and post images and their sizes - mImPre = tIm::FromFile(mNamePreImage); - mImPost = tIm::FromFile(mNamePostImage); + // read pre and post images and update their sizes + ReadFileNameLoadData(mNamePreImage, mImPre, mDImPre, mSzImPre); + ReadFileNameLoadData(mNamePostImage, mImPost, mDImPost, mSzImPost); - mDImPre = &mImPre.DIm(); - mSzImPre = mDImPre->Sz(); - - mDImPost = &mImPost.DIm(); - mSzImPost = mDImPost->Sz(); + bool aUserDefinedFolderName = false; + if (!mFolderSaveResult.empty()) + { + aUserDefinedFolderName = true; + if (!ExistFile(mFolderSaveResult)) + CreateDirectories(mFolderSaveResult, aUserDefinedFolderName); + } if (mUseMultiScaleApproach) mSigmaGaussFilter = mNumberOfScales * mSigmaGaussFilterStep; if (mComputeAvgMax) - SubtractPrePostImageAndComputeAvgAndMax(); + SubtractPrePostImageAndComputeAvgAndMax(mImDiff, mDImDiff, mDImPre, + mDImPost, mSzImPre); if (mShow) StdOut() << "Iter, " @@ -863,39 +600,35 @@ namespace MMVII << "NbOut" << std::endl; // Generate triangulated knots coordinates - GeneratePointsForDelaunay(mVectorPts, mNumberPointsToGenerate, mRandomUniformLawUpperBoundLines, - mRandomUniformLawUpperBoundCols, mDelTri, mSzImPre); - - // Initialise unknown values of problem - InitialisationAfterExe(mDelTri, mSys); - - bool aUseDefinedFolderName = false; - if (!mFolderSaveResult.empty()) - { - aUseDefinedFolderName = true; - if (!std::filesystem::exists(mFolderSaveResult)) - std::filesystem::create_directory(mFolderSaveResult); - } + DefineValueLimitsForPointGenerationAndBuildGrid(mNumberPointsToGenerate, mNumberOfLines, + mNumberOfCols, mDelTri, mSzImPre, mBuildRandomUniformGrid); - if (mUseMultiScaleApproach) - { - for (int aIterNumber = 0; aIterNumber < mNumberOfScales + mNumberOfEndIterations; aIterNumber++) - { - DoOneIteration(aIterNumber, aUseDefinedFolderName); - if (mInitialiseWithPreviousIter) - InitialisationBeforeIteration(mDelTri, mSys); - } - } + // If initialisation with previous excution is not wanted initialise the problem with zeros everywhere apart from radiometry scaling, with one + if ((!mInitialiseTranslationWithPreviousExecution && !mInitialiseRadiometryWithPreviousExecution) || mInitialiseWithUserValues) + InitialisationAfterExe(mDelTri, mSys, mInitialiseWithUserValues, mInitialiseXTranslationValue, + mInitialiseYTranslationValue, mInitialiseRadTrValue, mInitialiseRadScValue); else { - for (int aIterNumber = 0; aIterNumber < mNumberOfScales; aIterNumber++) - { - DoOneIteration(aIterNumber, aUseDefinedFolderName); - if (mInitialiseWithPreviousIter) - InitialisationBeforeIteration(mDelTri, mSys); - } + if (mIsFirstExecution && mInitialiseWithMMVI) + InitialiseWithPreviousExecutionValues(mDelTri, mSys, mNameInitialDepX, mImIntermediateDepX, + mDImIntermediateDepX, mSzImIntermediateDepX, mNameInitialDepY, + mImIntermediateDepY, mDImIntermediateDepY, mSzImDepY, + mNameCorrelationMaskMMVI, mImCorrelationMask, + mDImCorrelationMask, mSzCorrelationMask); + else if (!mIsFirstExecution && mInitialiseWithMMVI) + InitialiseWithPreviousExecutionValues(mDelTri, mSys, mNameInitialDepX, mImIntermediateDepX, + mDImIntermediateDepX, mSzImIntermediateDepX, mNameInitialDepY, + mImIntermediateDepY, mDImIntermediateDepY, mSzImDepY, + mNameCorrelationMaskMMVI, mImCorrelationMask, + mDImCorrelationMask, mSzCorrelationMask); } + int aTotalNumberOfIterations = 0; + (mUseMultiScaleApproach) ? aTotalNumberOfIterations = mNumberOfScales + mNumberOfEndIterations : aTotalNumberOfIterations = mNumberOfScales; + + for (int aIterNumber = 0; aIterNumber < aTotalNumberOfIterations; aIterNumber++) + DoOneIteration(aIterNumber, aTotalNumberOfIterations, aUserDefinedFolderName); + return EXIT_SUCCESS; } @@ -903,19 +636,19 @@ namespace MMVII // ::MMVII // /********************************************/ - tMMVII_UnikPApli Alloc_cTriangleDeformation(const std::vector &aVArgs, - const cSpecMMVII_Appli &aSpec) + tMMVII_UnikPApli Alloc_cAppli_TriangleDeformation(const std::vector &aVArgs, + const cSpecMMVII_Appli &aSpec) { - return tMMVII_UnikPApli(new cAppli_cTriangleDeformation(aVArgs, aSpec)); + return tMMVII_UnikPApli(new cAppli_TriangleDeformation(aVArgs, aSpec)); } cSpecMMVII_Appli TheSpec_ComputeTriangleDeformation( "ComputeTriangleDeformation", - Alloc_cTriangleDeformation, - "Compute 2D deformation of triangles between images using triangles", + Alloc_cAppli_TriangleDeformation, + "Compute 2D deformation between images using triangles", {eApF::ImProc}, // category {eApDT::Image}, // input {eApDT::Image}, // output __FILE__); -}; // namespace MMVII \ No newline at end of file +}; // namespace MMVII diff --git a/MMVII/src/MeshDisplacement/TriangleDeformation.h b/MMVII/src/MeshDisplacement/TriangleDeformation.h index ed48e4f7e8..20de0b019b 100644 --- a/MMVII/src/MeshDisplacement/TriangleDeformation.h +++ b/MMVII/src/MeshDisplacement/TriangleDeformation.h @@ -1,179 +1,148 @@ #ifndef _TRIANGLEDEFORMATION_H_ #define _TRIANGLEDEFORMATION_H_ +#include "cMMVII_Appli.h" #include "MMVII_Geom2D.h" #include "MMVII_PhgrDist.h" +#include "MMVII_util.h" +#include "MMVII_TplSymbTriangle.h" +#include "TriangleDeformationUtils.h" + using namespace NS_SymbolicDerivative; namespace MMVII { - /****************************************/ - /* */ - /* cPtInsideTriangles */ - /* */ - /****************************************/ - - class cPtInsideTriangles - { - public: - cPtInsideTriangles(const cTriangle2DCompiled &aCompTri, // a compiled triangle - const std::vector &aVectorFilledwithInsidePixels, // vector containing pixels inside triangles - const size_t aFilledPixel, // a counter that is looping over pixels in triangles - const cDataIm2D &aDIm); // image - cPt3dr GetBarycenterCoordinates() const; // Accessor for barycenter coordinates - cPt2dr GetCartesianCoordinates() const; // Accessor for cartesian coordinates - tREAL8 GetPixelValue() const; // Accessor for pixel value at coordinates - - private: - cPt3dr mBarycenterCoordinatesOfPixel; // Barycentric coordinates of pixel. - cPt2dr mFilledIndices; // 2D cartesian coordinates of pixel. - tREAL8 mValueOfPixel; // Intensity in image at pixel. - }; - /******************************************/ /* */ - /* cTriangleDeformation */ + /* cAppli_TriangleDeformation */ /* */ /******************************************/ - class cAppli_cTriangleDeformation : public cMMVII_Appli + class cAppli_TriangleDeformation : public cMMVII_Appli { public: typedef cIm2D tIm; typedef cDataIm2D tDIm; - typedef cTriangle tTri2dr; - typedef cDenseVect tDenseVect; + typedef cDenseVect tDenseVect; typedef std::vector tIntVect; - typedef std::vector tDoubleVect; - cAppli_cTriangleDeformation(const std::vector &aVArgs, - const cSpecMMVII_Appli &aSpec); - ~cAppli_cTriangleDeformation(); + cAppli_TriangleDeformation(const std::vector &aVArgs, + const cSpecMMVII_Appli &aSpec); + ~cAppli_TriangleDeformation(); int Exe() override; cCollecSpecArg2007 &ArgObl(cCollecSpecArg2007 &anArgObl) override; cCollecSpecArg2007 &ArgOpt(cCollecSpecArg2007 &anArgOpt) override; - // Build uniform vector of coordinates and apply Delaunay triangulation - void ConstructUniformRandomVectorAndApplyDelaunay(std::vector aVectorPts, const int aNumberOfPointsToGenerate, - const int aRandomUniformLawUpperBoundLines, const int aRandomUniformLawUpperBoundCols, - cTriangulation2D &aDelaunayTri); - // Generate coordinates from uniform law for Delaunay triangulation application - void GeneratePointsForDelaunay(std::vector aVectorPts, const int aNumberOfPointsToGenerate, - int aRandomUniformLawUpperBoundLines, int aRandomUniformLawUpperBoundCols, - cTriangulation2D &aDelaunayTri, const cPt2di &aSzImPre); - // Construct difference image and compute average and max pixel value on ths image - void SubtractPrePostImageAndComputeAvgAndMax(); // Iterate of triangles and inside pixels - virtual void DoOneIteration(const int aIterNumber, const bool aUserDefinedFolderName); + void DoOneIteration(const int aIterNumber, const int aTotalNumberOfIterations, + const bool aUserDefinedFolderName); // Loops over all triangles and solves system to update parameters at end of iteration - virtual void LoopOverTrianglesAndUpdateParameters(const int aIterNumber, const bool aUserDefinedFolderName); + void LoopOverTrianglesAndUpdateParameters(const int aIterNumber, const int aTotalNumberOfIterations, + const bool aUserDefinedFolderName); // Generate displacement maps of last solution - virtual void GenerateDisplacementMapsAndOutputImages(const tDenseVect &aVFinalSol, const int aIterNumber, - const bool aUserDefinedFolderName); - // Display values of unknowns at last iteration of optimisation process - void DisplayLastUnknownValues(const tDenseVect &aVFinalSol, const bool aDisplayLastRadiometryValues, - const bool aDisplayLastTranslationValues); + void GenerateDisplacementMapsAndOutputImages(const tDenseVect &aVFinalSol, const int aIterNumber, + const int aTotalNumberOfIterations, const bool aUserDefinedFolderName); // Generates Displacement maps and coordinates of points in triangulation at last iteration - virtual void GenerateDisplacementMapsAndDisplayLastValuesUnknowns(const int aIterNumber, const bool aDisplayLastRadiometryValues, - const bool aDisplayLastTranslationValues, const bool aUserDefinedFolderName); - // Initialise values of unknowns at the beginning of optimsation process after user has input information - void InitialisationAfterExe(cTriangulation2D &aDelaunayTri, - cResolSysNonLinear *&aSys); - // Initialise values of unknowns before current iteration - void InitialisationBeforeIteration(cTriangulation2D &aDelaunayTri, cResolSysNonLinear *&aSys); - // Loads current pre and post images - void LoadImageAndData(tIm &aCurIm, tDIm *&aCurDIm, const std::string &aPreOrPostImage, tIm &aImPre, tIm &aImPost); - // Load image and data according to number of iterations to optimise on original image - bool ManageDifferentCasesOfEndIterations(const int aIterNumber, const int aNumberOfScales, const int aNumberOfEndIterations, - bool aIsLastIters, tIm &aImPre, tIm &aImPost, tIm aCurPreIm, tDIm *aCurPreDIm, - tIm aCurPostIm, tDIm *aCurPostDIm); - // Fill displacement maps and output image - virtual void FillDisplacementMapsAndOutputImage(const cPtInsideTriangles &aLastPixInsideTriangle, - const cPt2dr &aLastTranslatedFilledPoint, - const tREAL8 aLastRadiometryTranslation, - const tREAL8 aLastRadiometryScaling); - // Apply barycentric translation formula to current translation values - cPt2dr ApplyBarycenterTranslationFormulaToFilledPixel(const cPt2dr &aCurrentTranslationPointA, - const cPt2dr &aCurrentTranslationPointB, - const cPt2dr &aCurrentTranslationPointC, - const tDoubleVect &aVObs); - // Apply barycentric translation formula to current radiometric translation values - tREAL8 ApplyBarycenterTranslationFormulaForTranslationRadiometry(const tREAL8 aCurrentRadTranslationPointA, - const tREAL8 aCurrentRadTranslationPointB, - const tREAL8 aCurrentRadTranslationPointC, - const tDoubleVect &aVObs); - // Apply barycentric translation formula to current radiometric scaling values - tREAL8 ApplyBarycenterTranslationFormulaForScalingRadiometry(const tREAL8 aCurrentRadScalingPointA, - const tREAL8 aCurrentRadScalingPointB, - const tREAL8 aCurrentRadScalingPointC, - const tDoubleVect &aVObs); + void GenerateDisplacementMapsAndDisplayLastValuesUnknowns(const int aIterNumber, const int aTotalNumberOfIterations, + const bool aDisplayLastRadiometryValues, const bool aDisplayLastTranslationValues, + const bool aUserDefinedFolderName); private: // == Mandatory args ==== - std::string mNamePreImage; // Name of given pre-image - std::string mNamePostImage; // Name of given post-image - int mNumberPointsToGenerate; // number of generated points - int mNumberOfScales; // number of iterations in optimisation process + std::string mNamePreImage; // Name of given pre-image + std::string mNamePostImage; // Name of given post-image + int mNumberPointsToGenerate; // number of generated points + int mNumberOfScales; // number of iterations in optimisation process // == Optionnal args ==== - int mRandomUniformLawUpperBoundLines; // Uniform law generates random coordinates in interval [0, mRandomUniformLawUpperBoundLines [ - int mRandomUniformLawUpperBoundCols; // Uniform law generates random coordinates in interval [0, mRandomUniformLawUpperBoundCols [ - bool mShow; // Print result, export image ... - bool mComputeAvgMax; // Compute average and maximum pixel value of difference image between pre and post images - bool mUseMultiScaleApproach; // Apply multi-scale approach or not - int mSigmaGaussFilterStep; // Decreasing step of sigma value during iterations - bool mGenerateDisplacementImage; // Generate image with displaced pixels - bool mInitialiseWithPreviousIter; // Initialise unknown value at beginning of every iteration with values obtained at previous iteration - bool mFreezeTranslationX; // Freeze x-translation or not during optimisation - bool mFreezeTranslationY; // Freeze y-translation or not during optimisation - bool mFreezeRadTranslation; // Freeze radiometry translation or not during optimisation - bool mFreezeRadScale; // Freeze radiometry scaling or not during optimisation - double mWeightRadTranslation; // Weight given to radiometry translation if soft freezing is applied (default : negative => not applied) - double mWeightRadScale; // Weight given to radiometry scaling if soft freezing is applied (default : negative => not applied) - int mNumberOfIterGaussFilter; // Number of iterations to be done in Gauss filter algorithm - int mNumberOfEndIterations; // Number of iterations to do while using original image in multi-scale approach - std::string mFolderSaveResult; // Folder name to save results - bool mDisplayLastTranslationValues; // Whether to display the final coordinates of the translated points - bool mDisplayLastRadiometryValues; // Display final values of radiometry unknowns at last iteration of optimisation process + int mNumberOfLines; // Uniform law generates random coordinates in interval [0, mNumberOfLines [ + int mNumberOfCols; // Uniform law generates random coordinates in interval [0, mNumberOfCols [ + bool mShow; // Print result, export image ... + bool mComputeAvgMax; // Compute average and maximum pixel value of difference image between pre and post images + bool mUseMultiScaleApproach; // Apply multi-scale approach or not + bool mBuildRandomUniformGrid; // Whether to triangulate grid made of points whose coordinates follow a uniform law or have coordinates that form rectangles + bool mInitialiseTranslationWithPreviousExecution; // Initialise values of translation unknowns with values obtained at previous algorithm execution + bool mInitialiseRadiometryWithPreviousExecution; // Initialise values of radiometry unknowns with values obtained at previous algorithm execution + bool mInitialiseWithUserValues; // Initalise or not with values given by user + tREAL8 mInitialiseXTranslationValue; // Value given by user to initialise x-translation unknowns + tREAL8 mInitialiseYTranslationValue; // Value given by user to initialise y-translation unknowns + tREAL8 mInitialiseRadTrValue; // Value given by user to initialise radiometry transltion unknowns + tREAL8 mInitialiseRadScValue; // Value given by user to initialise radiometry scaling unknowns + bool mInitialiseWithMMVI; // Whether to initialise values of unknowns with pre-computed values from MicMacV1 or not + std::string mNameInitialDepX; // File name of initial X-displacement map + std::string mNameInitialDepY; // File name of initial Y-displacement map + std::string mNameIntermediateDepX; // File name to save to of intermediate X-displacement map between executions if initialisation with previous unknown values is true + std::string mNameIntermediateDepY; // File name to save to of intermediate Y-displacement map between executions if initialisation with previous unknown values is true + std::string mNameCorrelationMaskMMVI; // File name of mask file produced by MMVI that gives pixel locations where correlation was computed + bool mIsFirstExecution; // Whether current execution of algorithm is first execution or not + int mSigmaGaussFilterStep; // Decreasing step of sigma value during iterations + bool mGenerateDisplacementImage; // Generate image with displaced pixels + bool mFreezeTranslationX; // Freeze x-translation or not during optimisation + bool mFreezeTranslationY; // Freeze y-translation or not during optimisation + bool mFreezeRadTranslation; // Freeze radiometry translation or not during optimisation + bool mFreezeRadScale; // Freeze radiometry scaling or not during optimisation + tREAL8 mWeightRadTranslation; // Weight given to radiometry translation if soft freezing is applied (default : negative => not applied) + tREAL8 mWeightRadScale; // Weight given to radiometry scaling if soft freezing is applied (default : negative => not applied) + int mNumberOfIterGaussFilter; // Number of iterations to be done in Gauss filter algorithm + int mNumberOfEndIterations; // Number of iterations to do while using original image in multi-scale approach + std::string mFolderSaveResult; // Folder name to save results + bool mDisplayLastTranslationValues; // Whether to display the final coordinates of the translated points + bool mDisplayLastRadiometryValues; // Display final values of radiometry unknowns at last iteration of optimisation process // == Internal variables ==== - cPt2di mSzImPre; // size of image - tIm mImPre; // memory representation of the image - tDIm *mDImPre; // memory representation of the image + tPt2di mSzImPre; // size of image + tIm mImPre; // memory representation of the image + tDIm *mDImPre; // memory representation of the image + + tPt2di mSzImPost; // size of image + tIm mImPost; // memory representation of the image + tDIm *mDImPost; // memory representation of the image + + tPt2di mSzImOut; // size of image + tIm mImOut; // memory representation of the image + tDIm *mDImOut; // memory representation of the image + + tPt2di mSzImDepX; // size of image + tIm mImDepX; // memory representation of the image + tDIm *mDImDepX; // memory representation of the image + + tPt2di mSzImDepY; // size of image + tIm mImDepY; // memory representation of the image + tDIm *mDImDepY; // memory representation of the image - cPt2di mSzImPost; // size of image - tIm mImPost; // memory representation of the image - tDIm *mDImPost; // memory representation of the image + tPt2di mSzIntermediateImOut; // size of image + tIm mImIntermediateOut; // memory representation of the image + tDIm *mDImIntermediateOut; // memory representation of the image - cPt2di mSzImOut; // size of image - tIm mImOut; // memory representation of the image - tDIm *mDImOut; // memory representation of the image + tPt2di mSzImIntermediateDepX; // size of image + tIm mImIntermediateDepX; // memory representation of the image + tDIm *mDImIntermediateDepX; // memory representation of the image - cPt2di mSzImDiff; // size of image - tIm mImDiff; // memory representation of the image - tDIm *mDImDiff; // memory representation of the image + tPt2di mSzImIntermediateDepY; // size of image + tIm mImIntermediateDepY; // memory representation of the image + tDIm *mDImIntermediateDepY; // memory representation of the image - cPt2di mSzImDepX; // size of image - tIm mImDepX; // memory representation of the image - tDIm *mDImDepX; // memory representation of the image + tPt2di mSzCorrelationMask; // size of image + tIm mImCorrelationMask; // memory representation of the image + tDIm *mDImCorrelationMask; // memory representation of the image - cPt2di mSzImDepY; // size of image - tIm mImDepY; // memory representation of the image - tDIm *mDImDepY; // memory representation of the image + tPt2di mSzImDiff; // size of image + tIm mImDiff; // memory representation of the image + tDIm *mDImDiff; // memory representation of the image - std::vector mVectorPts; // A vector containing a set of points - cTriangulation2D mDelTri; // A Delaunay triangle + //std::vector mVectorPts; // A vector containing a set of points + cTriangulation2D mDelTri; // A Delaunay triangle - double mSigmaGaussFilter; // Value of sigma in gauss filter - bool mIsLastIters; // Determines whether optimisation process is at last iters to optimise on original image + tREAL8 mSigmaGaussFilter; // Value of sigma in gauss filter + bool mIsLastIters; // Determines whether optimisation process is at last iters to optimise on original image - cResolSysNonLinear *mSys; // Non Linear Sys for solving problem - cCalculator *mEqTriDeform; // calculator giving access to values and derivatives + cResolSysNonLinear *mSys; // Non Linear Sys for solving problem + cCalculator *mEqTriDeform; // calculator giving access to values and derivatives }; } diff --git a/MMVII/src/MeshDisplacement/TriangleDeformationRad.cpp b/MMVII/src/MeshDisplacement/TriangleDeformationRad.cpp deleted file mode 100644 index 6936ed57aa..0000000000 --- a/MMVII/src/MeshDisplacement/TriangleDeformationRad.cpp +++ /dev/null @@ -1,405 +0,0 @@ -#include "MMVII_TplSymbTriangle.h" - -#include "TriangleDeformationRad.h" - -/** - \file TriangleDeformationRad.cpp - - \brief file computing radiometric deformations - between 2 images using triangles. -**/ - -namespace MMVII -{ - - /**********************************************/ - /* */ - /* cTriangleDeformationRad */ - /* */ - /**********************************************/ - - cAppli_cTriangleDeformationRad::cAppli_cTriangleDeformationRad(const std::vector &aVArgs, - const cSpecMMVII_Appli &aSpec) : cAppli_cTriangleDeformationRadiometry(aVArgs, aSpec), - mRandomUniformLawUpperBoundLines(1), - mRandomUniformLawUpperBoundCols(1), - mShow(true), - mGenerateOutputImage(true), - mUseMultiScaleApproach(false), - mWeightRadTranslation(-1), - mWeightRadScale(-1), - mDisplayLastRadiometryValues(false), - mSigmaGaussFilterStep(1), - mNumberOfIterGaussFilter(3), - mNumberOfEndIterations(2), - mSzImPre(cPt2di(1, 1)), - mImPre(mSzImPre), - mDImPre(nullptr), - mSzImPost(cPt2di(1, 1)), - mImPost(mSzImPost), - mDImPost(nullptr), - mSzImOut(cPt2di(1, 1)), - mImOut(mSzImOut), - mDImOut(nullptr), - mVectorPts({cPt2dr(0, 0)}), - mDelTri(mVectorPts), - mSys(nullptr), - mEqRadTri(nullptr) - - { - mEqRadTri = EqDeformTriRad(true, 1); // true means with derivative, 1 is size of buffer - // mEqRadiometryTri->SetDebugEnabled(true); - } - - cAppli_cTriangleDeformationRad::~cAppli_cTriangleDeformationRad() - { - delete mSys; - delete mEqRadTri; - } - - cCollecSpecArg2007 &cAppli_cTriangleDeformationRad::ArgObl(cCollecSpecArg2007 &anArgObl) - { - return anArgObl - << Arg2007(mNamePreImage, "Name of pre-image file.", {{eTA2007::FileImage}, {eTA2007::FileDirProj}}) - << Arg2007(mNamePostImage, "Name of post-image file.", {eTA2007::FileImage}) - << Arg2007(mNumberPointsToGenerate, "Number of points you want to generate for triangulation.") - << Arg2007(mNumberOfScales, "Total number of scales to run in multi-scale approach optimisation process."); - } - - cCollecSpecArg2007 &cAppli_cTriangleDeformationRad::ArgOpt(cCollecSpecArg2007 &anArgOpt) - { - return anArgOpt - << AOpt2007(mRandomUniformLawUpperBoundCols, "RandomUniformLawUpperBoundXAxis", - "Maximum value that the uniform law can draw from on the x-axis.", {eTA2007::HDV}) - << AOpt2007(mRandomUniformLawUpperBoundLines, "RandomUniformLawUpperBoundYAxis", - "Maximum value that the uniform law can draw from for on the y-axis.", {eTA2007::HDV}) - << AOpt2007(mShow, "Show", "Whether to print minimisation results.", {eTA2007::HDV}) - << AOpt2007(mGenerateOutputImage, "GenerateDisplacementImage", - "Whether to generate and save the output image with computed radiometry", {eTA2007::HDV}) - << AOpt2007(mUseMultiScaleApproach, "UseMultiScaleApproach", "Whether to use multi-scale approach or not.", {eTA2007::HDV}) - << AOpt2007(mWeightRadTranslation, "WeightRadiometryTranslation", - "A value to weight radiometry translation for soft freezing of coefficient.", {eTA2007::HDV}) - << AOpt2007(mWeightRadScale, "WeightRadiometryScaling", - "A value to weight radiometry scaling for soft freezing of coefficient.", {eTA2007::HDV}) - << AOpt2007(mDisplayLastRadiometryValues, "DisplayLastRadiometryValues", - "Whether to display or not the last values of radiometry unknowns after optimisation process.", {eTA2007::HDV}) - << AOpt2007(mSigmaGaussFilterStep, "SigmaGaussFilterStep", - "Sigma value to use for Gauss filter in multi-stage approach.", {eTA2007::HDV}) - << AOpt2007(mNumberOfIterGaussFilter, "NumberOfIterationsGaussFilter", - "Number of iterations to run in Gauss filter algorithm.", {eTA2007::HDV}) - << AOpt2007(mNumberOfEndIterations, "NumberOfEndIterations", - "Number of iterations to run on original images in multi-scale approach.", {eTA2007::HDV}); - } - - void cAppli_cTriangleDeformationRad::LoopOverTrianglesAndUpdateParametersRadiometry(const int aIterNumber) - { - //----------- allocate vec of obs : - tDoubleVect aVObs(12, 0.0); // 6 for ImagePre and 6 for ImagePost - - //----------- extract current parameters - tDenseVect aVCur = mSys->CurGlobSol(); // Get current solution. - - tIm aCurPreIm = tIm(mSzImPre); - tDIm *aCurPreDIm = nullptr; - tIm aCurPostIm = tIm(mSzImPost); - tDIm *aCurPostDIm = nullptr; - - mIsLastIters = false; - - if (mUseMultiScaleApproach) - mIsLastIters = cAppli_cTriangleDeformation::ManageDifferentCasesOfEndIterations(aIterNumber, mNumberOfScales, mNumberOfEndIterations, - mIsLastIters, mImPre, mImPost, aCurPreIm, aCurPreDIm, - aCurPostIm, aCurPostDIm); - else - { - cAppli_cTriangleDeformation::LoadImageAndData(aCurPreIm, aCurPreDIm, "pre", mImPre, mImPost); - cAppli_cTriangleDeformation::LoadImageAndData(aCurPostIm, aCurPostDIm, "post", mImPre, mImPost); - } - - if (mUseMultiScaleApproach && !mIsLastIters) - { - aCurPreIm = mImPre.GaussFilter(mSigmaGaussFilter, mNumberOfIterGaussFilter); - aCurPostIm = mImPost.GaussFilter(mSigmaGaussFilter, mNumberOfIterGaussFilter); - - aCurPreDIm = &aCurPreIm.DIm(); - aCurPostDIm = &aCurPostIm.DIm(); - - mSigmaGaussFilter -= 1; - - const bool aSaveGaussImage = false; - if (aSaveGaussImage) - aCurPreDIm->ToFile("GaussFilteredImPre_iter_" + std::to_string(aIterNumber) + ".tif"); - } - else if (mUseMultiScaleApproach && mIsLastIters) - { - LoadImageAndData(aCurPreIm, aCurPreDIm, "pre", mImPre, mImPost); - LoadImageAndData(aCurPostIm, aCurPostDIm, "post", mImPre, mImPost); - } - - //----------- declaration of indicator of convergence - tREAL8 aSomDif = 0; // sum of difference between untranslated pixel and translated one. - size_t aNbOut = 0; // number of translated pixels out of image - - // Count number of pixels inside triangles for normalisation - size_t aTotalNumberOfInsidePixels = 0; - - // Loop over all triangles to add the observations on each point - for (size_t aTr = 0; aTr < mDelTri.NbFace(); aTr++) - { - const tTri2dr aTri = mDelTri.KthTri(aTr); - const cPt3di aIndicesOfTriKnots = mDelTri.KthFace(aTr); - - const cTriangle2DCompiled aCompTri(aTri); - - std::vector aVectorToFillWithInsidePixels; - aCompTri.PixelsInside(aVectorToFillWithInsidePixels); // get pixels inside triangle - - //----------- index of unknown, finds the associated pixels of current triangle knots - const tIntVect aVecInd = {2 * aIndicesOfTriKnots.x(), 2 * aIndicesOfTriKnots.x() + 1, - 2 * aIndicesOfTriKnots.y(), 2 * aIndicesOfTriKnots.y() + 1, - 2 * aIndicesOfTriKnots.z(), 2 * aIndicesOfTriKnots.z() + 1}; - - const tREAL8 aCurRadTrPointA = aVCur(aVecInd.at(0)); // current translation on radiometry 1st point of triangle - const tREAL8 aCurRadScPointA = aVCur(aVecInd.at(1)); // current scale on radiometry 3rd point of triangle - const tREAL8 aCurRadTrPointB = aVCur(aVecInd.at(2)); // current translation on radiometry 2nd point of triangle - const tREAL8 aCurRadScPointB = aVCur(aVecInd.at(3)); // current scale on radiometry 3rd point of triangle - const tREAL8 aCurRadTrPointC = aVCur(aVecInd.at(4)); // current translation on radiometry 3rd point of triangle - const tREAL8 aCurRadScPointC = aVCur(aVecInd.at(5)); // current scale on radiometry 3rd point of triangle - - // soft constraint radiometric translation - if (mWeightRadTranslation >= 0) - { - const int aSolStep = 2; // adapt step to solution vector configuration - const int aSolStart = 0; - for (size_t aIndCurSol = aSolStart; aIndCurSol < aVecInd.size() - 1; aIndCurSol += aSolStep) - { - const int aIndices = aVecInd.at(aIndCurSol); - mSys->AddEqFixVar(aIndices, aVCur(aIndices), mWeightRadTranslation); - } - } - - // soft constraint radiometric scaling - if (mWeightRadScale >= 0) - { - const int aSolStep = 2; // adapt step to solution vector configuration - const int aSolStart = 1; - for (size_t aIndCurSol = aSolStart; aIndCurSol < aVecInd.size(); aIndCurSol += aSolStep) - { - const int aIndices = aVecInd.at(aIndCurSol); - mSys->AddEqFixVar(aIndices, aVCur(aIndices), mWeightRadScale); - } - } - - const size_t aNumberOfInsidePixels = aVectorToFillWithInsidePixels.size(); - - // Loop over all pixels inside triangle - // size_t is necessary as there can be a lot of pixels in triangles - for (size_t aFilledPixel = 0; aFilledPixel < aNumberOfInsidePixels; aFilledPixel++) - { - const cPtInsideTriangles aPixInsideTriangle = cPtInsideTriangles(aCompTri, aVectorToFillWithInsidePixels, - aFilledPixel, *aCurPreDIm); - // prepare for barycenter translation formula by filling aVObs with different coordinates - FormalInterpBarycenter_SetObs(aVObs, 0, aPixInsideTriangle); - - // radiometry translation of pixel by current radiometry translation of triangle knots - const tREAL8 aRadiometryTranslation = cAppli_cTriangleDeformation::ApplyBarycenterTranslationFormulaForTranslationRadiometry(aCurRadTrPointA, - aCurRadTrPointB, - aCurRadTrPointC, - aVObs); - - // radiometry scaling of pixel by current radiometry scaling of triangle knots - const tREAL8 aRadiometryScaling = cAppli_cTriangleDeformation::ApplyBarycenterTranslationFormulaForScalingRadiometry(aCurRadScPointA, - aCurRadScPointB, - aCurRadScPointC, - aVObs); - - const cPt2dr aInsideTrianglePoint = aPixInsideTriangle.GetCartesianCoordinates(); - const cPt2di aEastTranslatedPoint = cPt2di(aInsideTrianglePoint.x(), aInsideTrianglePoint.y()) + cPt2di(1, 0); - const cPt2di aSouthTranslatedPoint = cPt2di(aInsideTrianglePoint.x(), aInsideTrianglePoint.y()) + cPt2di(0, 1); - - if (aCurPostDIm->InsideBL(cPt2dr(aEastTranslatedPoint.x(), aEastTranslatedPoint.y()))) // avoid errors - { - if (aCurPostDIm->InsideBL(cPt2dr(aSouthTranslatedPoint.x(), aSouthTranslatedPoint.y()))) // avoid errors - { - // prepare for application of bilinear formula - FormalBilinTri_SetObs(aVObs, TriangleDisplacement_NbObs, aInsideTrianglePoint, *aCurPostDIm); - - // Now add observation - mSys->CalcAndAddObs(mEqRadTri, aVecInd, aVObs); - - // compute indicators - const tREAL8 aBilinearRadiomValue = aRadiometryScaling * aCurPostDIm->GetVBL(aPixInsideTriangle.GetCartesianCoordinates()) + - aRadiometryTranslation; - const tREAL8 aDif = aVObs[5] - aBilinearRadiomValue; // residual : aValueImPre - aBilinearRadiomValue - aSomDif += std::abs(aDif); - } - } - else - aNbOut++; - aTotalNumberOfInsidePixels += aNumberOfInsidePixels; - } - } - - // Update all parameter taking into account previous observation - mSys->SolveUpdateReset(); - - if (mShow) - StdOut() << aIterNumber + 1 << ", " << aSomDif / aTotalNumberOfInsidePixels - << ", " << aNbOut << std::endl; - } - - void cAppli_cTriangleDeformationRad::GenerateOutputImageAndDisplayLastRadiometryValues(const tDenseVect &aVFinalSol, const int aIterNumber) - { - mImOut = tIm(mSzImPre); - mDImOut = &mImOut.DIm(); - mSzImOut = cPt2di(mDImOut->Sz().x(), mDImOut->Sz().y()); - - tIm aLastPostIm = tIm(mSzImPost); - tDIm *aLastPostDIm = nullptr; - cAppli_cTriangleDeformation::LoadImageAndData(aLastPostIm, aLastPostDIm, "post", mImPre, mImPost); - - if (mUseMultiScaleApproach && !mIsLastIters) - { - aLastPostIm = mImPost.GaussFilter(mSigmaGaussFilter, mNumberOfIterGaussFilter); - aLastPostDIm = &aLastPostIm.DIm(); - } - - for (const cPt2di &aOutPix : *mDImOut) // Initialise output image - mDImOut->SetV(aOutPix, aLastPostDIm->GetV(aOutPix)); - - for (size_t aLTr = 0; aLTr < mDelTri.NbFace(); aLTr++) - { - const tTri2dr aLastTri = mDelTri.KthTri(aLTr); - const cPt3di aLastIndicesOfTriKnots = mDelTri.KthFace(aLTr); - - const cTriangle2DCompiled aLastCompTri(aLastTri); - - std::vector aLastVectorToFillWithInsidePixels; - aLastCompTri.PixelsInside(aLastVectorToFillWithInsidePixels); - - const tIntVect aLastVecInd = {2 * aLastIndicesOfTriKnots.x(), 2 * aLastIndicesOfTriKnots.x() + 1, - 2 * aLastIndicesOfTriKnots.y(), 2 * aLastIndicesOfTriKnots.y() + 1, - 2 * aLastIndicesOfTriKnots.z(), 2 * aLastIndicesOfTriKnots.z() + 1}; - - const tREAL8 aLastRadTrPointA = aVFinalSol(aLastVecInd.at(0)); // last translation on radiometry 1st point of triangle - const tREAL8 aLastRadScPointA = aVFinalSol(aLastVecInd.at(1)); // last scale on radiometry 1st point of triangle - const tREAL8 aLastRadTrPointB = aVFinalSol(aLastVecInd.at(2)); // last translation on radiometry 2nd point of triangle - const tREAL8 aLastRadScPointB = aVFinalSol(aLastVecInd.at(3)); // last scale on radiometry 2nd point of triangle - const tREAL8 aLastRadTrPointC = aVFinalSol(aLastVecInd.at(4)); // last translation on radiometry 3rd point of triangle - const tREAL8 aLastRadScPointC = aVFinalSol(aLastVecInd.at(5)); // last scale on radiometry 3rd point of triangle - - const size_t aLastNumberOfInsidePixels = aLastVectorToFillWithInsidePixels.size(); - - for (size_t aLastFilledPixel = 0; aLastFilledPixel < aLastNumberOfInsidePixels; aLastFilledPixel++) - { - const cPtInsideTriangles aLastPixInsideTriangle = cPtInsideTriangles(aLastCompTri, aLastVectorToFillWithInsidePixels, - aLastFilledPixel, *aLastPostDIm); - - // radiometry translation of pixel by current radiometry translation - const tREAL8 aLastRadiometryTranslation = cAppli_cTriangleDeformationRadiometry::ApplyLastBarycenterInterpolationFormulaRadiometryTranslation(aLastRadTrPointA, - aLastRadTrPointB, - aLastRadTrPointC, - aLastPixInsideTriangle); - - const tREAL8 aLastRadiometryScaling = cAppli_cTriangleDeformationRadiometry::ApplyLastBarycenterInterpolationFormulaRadiometryScaling(aLastRadScPointA, - aLastRadScPointB, - aLastRadScPointC, - aLastPixInsideTriangle); - - cAppli_cTriangleDeformationRadiometry::FillOutputImage(aLastPixInsideTriangle, aLastRadiometryTranslation, - aLastRadiometryScaling); - } - } - - // save output image with calculated radiometries to image file - mDImOut->ToFile("OutputImage_" + std::to_string(mNumberOfScales) + "_" + std::to_string(mNumberPointsToGenerate) + ".tif"); - - if (mDisplayLastRadiometryValues) - { - for (int aFinalUnk = 0; aFinalUnk < aVFinalSol.DIm().Sz(); aFinalUnk++) - { - StdOut() << aVFinalSol(aFinalUnk) << " "; - if (aFinalUnk % 2 == 1 && aFinalUnk != 0) - StdOut() << std::endl; - } - } - } - - void cAppli_cTriangleDeformationRad::DoOneIterationRadiometry(const int aIterNumber) - { - LoopOverTrianglesAndUpdateParametersRadiometry(aIterNumber); // Iterate over triangles and solve system - - tDenseVect aVFinalSol = mSys->CurGlobSol(); - // Show final translation results and produce displacement maps - if (mUseMultiScaleApproach) - { - if (aIterNumber == (mNumberOfScales + mNumberOfEndIterations - 1)) - GenerateOutputImageAndDisplayLastRadiometryValues(aVFinalSol, aIterNumber); - } - else - { - if (aIterNumber == (mNumberOfScales - 1)) - GenerateOutputImageAndDisplayLastRadiometryValues(aVFinalSol, aIterNumber); - } - } - - //----------------------------------------- - - int cAppli_cTriangleDeformationRad::Exe() - { - // read pre and post images and their sizes - mImPre = tIm::FromFile(mNamePreImage); - mImPost = tIm::FromFile(mNamePostImage); - - mDImPre = &mImPre.DIm(); - mSzImPre = mDImPre->Sz(); - - mDImPost = &mImPost.DIm(); - mSzImPost = mDImPost->Sz(); - - if (mUseMultiScaleApproach) - mSigmaGaussFilter = mNumberOfScales * mSigmaGaussFilterStep; - - if (mShow) - StdOut() << "Iter, " - << "Diff, " - << "NbOut" << std::endl; - - cAppli_cTriangleDeformation::GeneratePointsForDelaunay(mVectorPts, mNumberPointsToGenerate, mRandomUniformLawUpperBoundLines, - mRandomUniformLawUpperBoundCols, mDelTri, mSzImPre); - - cAppli_cTriangleDeformationRadiometry::InitialisationAfterExeRadiometry(mDelTri, mSys); - - if (mUseMultiScaleApproach) - { - for (int aIterNumber = 0; aIterNumber < mNumberOfScales + mNumberOfEndIterations; aIterNumber++) - DoOneIterationRadiometry(aIterNumber); - } - else - { - for (int aIterNumber = 0; aIterNumber < mNumberOfScales; aIterNumber++) - DoOneIterationRadiometry(aIterNumber); - } - - return EXIT_SUCCESS; - } - - /********************************************/ - // ::MMVII // - /********************************************/ - - tMMVII_UnikPApli Alloc_cTriangleDeformationRad(const std::vector &aVArgs, - const cSpecMMVII_Appli &aSpec) - { - return tMMVII_UnikPApli(new cAppli_cTriangleDeformationRad(aVArgs, aSpec)); - } - - cSpecMMVII_Appli TheSpec_ComputeTriangleDeformationRad( - "ComputeTriangleDeformationRad", - Alloc_cTriangleDeformationRad, - "Compute radiometric deformation between images using triangles and alternative equation", - {eApF::ImProc}, // category - {eApDT::Image}, // input - {eApDT::Image}, // output - __FILE__); - -}; // namespace MMVII \ No newline at end of file diff --git a/MMVII/src/MeshDisplacement/TriangleDeformationRad.h b/MMVII/src/MeshDisplacement/TriangleDeformationRad.h deleted file mode 100644 index 43dd72d74c..0000000000 --- a/MMVII/src/MeshDisplacement/TriangleDeformationRad.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef _TRIANGLEDEFORMATIONRAD_H_ -#define _TRIANGLEDEFORMATIONRAD_H_ - -#include "MMVII_Geom2D.h" -#include "MMVII_PhgrDist.h" -#include "TriangleDeformation.h" -#include "TriangleDeformationRadiometry.h" - -using namespace NS_SymbolicDerivative; - -namespace MMVII -{ - - /******************************************************/ - /* */ - /* cAppli_cTriangleDeformationRad */ - /* */ - /******************************************************/ - - class cAppli_cTriangleDeformationRad : public cAppli_cTriangleDeformationRadiometry - { - public: - typedef cIm2D tIm; - typedef cDataIm2D tDIm; - typedef cTriangle tTri2dr; - typedef cDenseVect tDenseVect; - typedef std::vector tIntVect; - typedef std::vector tDoubleVect; - - cAppli_cTriangleDeformationRad(const std::vector &aVArgs, - const cSpecMMVII_Appli &aSpec); - ~cAppli_cTriangleDeformationRad(); - - int Exe() override; - cCollecSpecArg2007 &ArgObl(cCollecSpecArg2007 &anArgObl) override; - cCollecSpecArg2007 &ArgOpt(cCollecSpecArg2007 &anArgOpt) override; - - // Iterate of triangles and inside pixels - virtual void DoOneIterationRadiometry(const int aIterNumber); - // Loops over all triangles and solves system to update parameters at end of iteration - virtual void LoopOverTrianglesAndUpdateParametersRadiometry(const int aIterNumber); - // Generate displacement maps of last solution - virtual void GenerateOutputImageAndDisplayLastRadiometryValues(const tDenseVect &aVFinalSol, const int aIterNumber); - - private: - // == Mandatory args ==== - - std::string mNamePreImage; // Name of given pre-image - std::string mNamePostImage; // Name of given post-image - int mNumberPointsToGenerate; // number of generated points - int mNumberOfScales; // number of iterations in optimisation process - - // == Optionnal args ==== - - int mRandomUniformLawUpperBoundLines; // Uniform law generates random coordinates in interval [0, mRandomUniformLawUpperBoundLines [ - int mRandomUniformLawUpperBoundCols; // Uniform law generates random coordinates in interval [0, mRandomUniformLawUpperBoundCols [ - bool mShow; // Print result, export image ... - bool mGenerateOutputImage; // Generate image with displaced pixels - bool mUseMultiScaleApproach; // Apply multi-scale approach or not - tREAL8 mWeightRadTranslation; // Weight given to radiometry translation if soft freezing is applied (default : negative => not applied) - tREAL8 mWeightRadScale; // Weight given to radiometry scaling if soft freezing is applied (default : negative => not applied) - bool mDisplayLastRadiometryValues; // Display final values of radiometry unknowns at last iteration of optimisation process - int mSigmaGaussFilterStep; // Decreasing step of sigma value during iterations - int mNumberOfIterGaussFilter; // Number of iterations to be done in Gauss filter algorithm - int mNumberOfEndIterations; // Number of iterations to do while using original image in multi-scale approach - - // == Internal variables ==== - - cPt2di mSzImPre; // size of image - tIm mImPre; // memory representation of the image - tDIm *mDImPre; // memory representation of the image - - cPt2di mSzImPost; // size of image - tIm mImPost; // memory representation of the image - tDIm *mDImPost; // memory representation of the image - - cPt2di mSzImOut; // size of image - tIm mImOut; // memory representation of the image - tDIm *mDImOut; // memory representation of the image - - tREAL8 mSigmaGaussFilter; // Value of sigma in gauss filter - bool mIsLastIters; // Determines whether optimisation process is at last iters to optimise on original image - - std::vector mVectorPts; // A vector containing a set of points - cTriangulation2D mDelTri; // A Delaunay triangle - - cResolSysNonLinear *mSys; // Non Linear Sys for solving problem - cCalculator *mEqRadTri; // calculator giving access to values and derivatives - }; -} - -#endif // _TRIANGLEDEFORMATIONRAD_H_ diff --git a/MMVII/src/MeshDisplacement/TriangleDeformationRadiometry.cpp b/MMVII/src/MeshDisplacement/TriangleDeformationRadiometry.cpp index 487b64e344..1e8d2d0be3 100644 --- a/MMVII/src/MeshDisplacement/TriangleDeformationRadiometry.cpp +++ b/MMVII/src/MeshDisplacement/TriangleDeformationRadiometry.cpp @@ -1,5 +1,3 @@ -#include "MMVII_TplSymbTriangle.h" - #include "TriangleDeformationRadiometry.h" /** @@ -11,52 +9,52 @@ namespace MMVII { - - /**********************************************/ - /* */ - /* cTriangleDeformationRadiometry */ - /* */ - /**********************************************/ - - cAppli_cTriangleDeformationRadiometry::cAppli_cTriangleDeformationRadiometry(const std::vector &aVArgs, - const cSpecMMVII_Appli &aSpec) : cAppli_cTriangleDeformation(aVArgs, aSpec), - mRandomUniformLawUpperBoundLines(1), - mRandomUniformLawUpperBoundCols(1), - mShow(true), - mGenerateOutputImage(true), - mUseMultiScaleApproach(false), - mWeightRadTranslation(-1), - mWeightRadScale(-1), - mDisplayLastRadiometryValues(false), - mSigmaGaussFilterStep(1), - mNumberOfIterGaussFilter(3), - mNumberOfEndIterations(2), - mSzImPre(cPt2di(1, 1)), - mImPre(mSzImPre), - mDImPre(nullptr), - mSzImPost(cPt2di(1, 1)), - mImPost(mSzImPost), - mDImPost(nullptr), - mSzImOut(cPt2di(1, 1)), - mImOut(mSzImOut), - mDImOut(nullptr), - mVectorPts({cPt2dr(0, 0)}), - mDelTri(mVectorPts), - mSys(nullptr), - mEqRadiometryTri(nullptr) + /****************************************************/ + /* */ + /* cAppli_TriangleDeformationRadiometry */ + /* */ + /****************************************************/ + + cAppli_TriangleDeformationRadiometry::cAppli_TriangleDeformationRadiometry(const std::vector &aVArgs, + const cSpecMMVII_Appli &aSpec) : cAppli_TriangleDeformation(aVArgs, aSpec), + mNumberOfLines(1), + mNumberOfCols(1), + mShow(true), + mGenerateOutputImage(true), + mInitialiseWithUserValues(true), + mInitialiseRadTrValue(0), + mInitialiseRadScValue(1), + mUseMultiScaleApproach(false), + mWeightRadTranslation(-1), + mWeightRadScale(-1), + mDisplayLastRadiometryValues(false), + mSigmaGaussFilterStep(1), + mNumberOfIterGaussFilter(3), + mNumberOfEndIterations(2), + mSzImPre(tPt2di(1, 1)), + mImPre(mSzImPre), + mDImPre(nullptr), + mSzImPost(tPt2di(1, 1)), + mImPost(mSzImPost), + mDImPost(nullptr), + mSzImOut(tPt2di(1, 1)), + mImOut(mSzImOut), + mDImOut(nullptr), + mDelTri({tPt2dr(0, 0)}), + mSysRadiometry(nullptr), + mEqRadiometryTri(nullptr) { mEqRadiometryTri = EqDeformTriRadiometry(true, 1); // true means with derivative, 1 is size of buffer - // mEqRadiometryTri->SetDebugEnabled(true); } - cAppli_cTriangleDeformationRadiometry::~cAppli_cTriangleDeformationRadiometry() + cAppli_TriangleDeformationRadiometry::~cAppli_TriangleDeformationRadiometry() { - delete mSys; + delete mSysRadiometry; delete mEqRadiometryTri; } - cCollecSpecArg2007 &cAppli_cTriangleDeformationRadiometry::ArgObl(cCollecSpecArg2007 &anArgObl) + cCollecSpecArg2007 &cAppli_TriangleDeformationRadiometry::ArgObl(cCollecSpecArg2007 &anArgObl) { return anArgObl << Arg2007(mNamePreImage, "Name of pre-image file.", {{eTA2007::FileImage}, {eTA2007::FileDirProj}}) @@ -65,16 +63,24 @@ namespace MMVII << Arg2007(mNumberOfScales, "Total number of scales to run in multi-scale approach optimisation process."); } - cCollecSpecArg2007 &cAppli_cTriangleDeformationRadiometry::ArgOpt(cCollecSpecArg2007 &anArgOpt) + cCollecSpecArg2007 &cAppli_TriangleDeformationRadiometry::ArgOpt(cCollecSpecArg2007 &anArgOpt) { return anArgOpt - << AOpt2007(mRandomUniformLawUpperBoundCols, "RandomUniformLawUpperBoundXAxis", - "Maximum value that the uniform law can draw from on the x-axis.", {eTA2007::HDV}) - << AOpt2007(mRandomUniformLawUpperBoundLines, "RandomUniformLawUpperBoundYAxis", - "Maximum value that the uniform law can draw from for on the y-axis.", {eTA2007::HDV}) - << AOpt2007(mShow, "Show", "Whether to print minimisation results.", {eTA2007::HDV}) + << AOpt2007(mNumberOfCols, "RandomUniformLawUpperBoundXAxis", + "Maximum value that the uniform law can draw from on the x-axis.", {eTA2007::HDV, eTA2007::Tuning}) + << AOpt2007(mNumberOfLines, "RandomUniformLawUpperBoundYAxis", + "Maximum value that the uniform law can draw from for on the y-axis.", {eTA2007::HDV, eTA2007::Tuning}) + << AOpt2007(mShow, "Show", "Whether to print minimisation results.", {eTA2007::HDV, eTA2007::Tuning}) << AOpt2007(mGenerateOutputImage, "GenerateDisplacementImage", "Whether to generate and save the output image with computed radiometry", {eTA2007::HDV}) + << AOpt2007(mBuildRandomUniformGrid, "GenerateRandomUniformGrid", + "Whether to build a grid to be triangulated thanks to points generated randomly with a uniform law or build a grid made of rectangles.", {eTA2007::HDV}) + << AOpt2007(mInitialiseWithUserValues, "InitialiseWithUserValues", + "Whether the user wishes or not to initialise unknowns with personalised values.", {eTA2007::HDV}) + << AOpt2007(mInitialiseRadTrValue, "InitialeRadiometryTranslationValue", + "Value to use for initialising radiometry translation unknown values", {eTA2007::HDV}) + << AOpt2007(mInitialiseRadScValue, "InitialeRadiometryScalingValue", + "Value to use for initialising radiometry scaling unknown values", {eTA2007::HDV}) << AOpt2007(mUseMultiScaleApproach, "UseMultiScaleApproach", "Whether to use multi-scale approach or not.", {eTA2007::HDV}) << AOpt2007(mWeightRadTranslation, "WeightRadiometryTranslation", "A value to weight radiometry translation for soft freezing of coefficient.", {eTA2007::HDV}) @@ -83,35 +89,20 @@ namespace MMVII << AOpt2007(mDisplayLastRadiometryValues, "DisplayLastRadiometryValues", "Whether to display or not the last values of radiometry unknowns after optimisation process.", {eTA2007::HDV}) << AOpt2007(mSigmaGaussFilterStep, "SigmaGaussFilterStep", - "Sigma value to use for Gauss filter in multi-stage approach.", {eTA2007::HDV}) + "Sigma value to use for Gauss filter in multi-stage approach.", {eTA2007::HDV, eTA2007::Tuning}) << AOpt2007(mNumberOfIterGaussFilter, "NumberOfIterationsGaussFilter", - "Number of iterations to run in Gauss filter algorithm.", {eTA2007::HDV}) + "Number of iterations to run in Gauss filter algorithm.", {eTA2007::HDV, eTA2007::Tuning}) << AOpt2007(mNumberOfEndIterations, "NumberOfEndIterations", - "Number of iterations to run on original images in multi-scale approach.", {eTA2007::HDV}); + "Number of iterations to run on original images in multi-scale approach.", {eTA2007::HDV, eTA2007::Tuning}); } - void cAppli_cTriangleDeformationRadiometry::InitialisationAfterExeRadiometry(cTriangulation2D &aDelaunayTri, - cResolSysNonLinear *&aSys) - { - const size_t aNumberPts = 2 * aDelaunayTri.NbPts(); - tDenseVect aVInit(aNumberPts, eModeInitImage::eMIA_Null); // eMIA_V1 - - for (size_t aKtNumber = 0; aKtNumber < aNumberPts; aKtNumber++) - { - if (aKtNumber % 2 == 1) - aVInit(aKtNumber) = 1; - } - - aSys = new cResolSysNonLinear(eModeSSR::eSSR_LsqDense, aVInit); - } - - void cAppli_cTriangleDeformationRadiometry::LoopOverTrianglesAndUpdateParametersRadiometry(const int aIterNumber) + void cAppli_TriangleDeformationRadiometry::LoopOverTrianglesAndUpdateParametersRadiometry(const int aIterNumber) { //----------- allocate vec of obs : - tDoubleVect aVObs(12, 0.0); // 6 for ImagePre and 6 for ImagePost + tDoubleVect aVObsRad(12, 0.0); // 6 for ImagePre and 6 for ImagePost //----------- extract current parameters - tDenseVect aVCur = mSys->CurGlobSol(); // Get current solution. + tDenseVect aVCurSolRad = mSysRadiometry->CurGlobSol(); // Get current solution. tIm aCurPreIm = tIm(mSzImPre); tDIm *aCurPreDIm = nullptr; @@ -121,13 +112,13 @@ namespace MMVII mIsLastIters = false; if (mUseMultiScaleApproach) - mIsLastIters = cAppli_cTriangleDeformation::ManageDifferentCasesOfEndIterations(aIterNumber, mNumberOfScales, mNumberOfEndIterations, - mIsLastIters, mImPre, mImPost, aCurPreIm, aCurPreDIm, - aCurPostIm, aCurPostDIm); + mIsLastIters = ManageDifferentCasesOfEndIterations(aIterNumber, mNumberOfScales, mNumberOfEndIterations, + mIsLastIters, mImPre, mImPost, aCurPreIm, aCurPreDIm, + aCurPostIm, aCurPostDIm); else { - cAppli_cTriangleDeformation::LoadImageAndData(aCurPreIm, aCurPreDIm, "pre", mImPre, mImPost); - cAppli_cTriangleDeformation::LoadImageAndData(aCurPostIm, aCurPostDIm, "post", mImPre, mImPost); + LoadPrePostImageAndData(aCurPreIm, aCurPreDIm, "pre", mImPre, mImPost); + LoadPrePostImageAndData(aCurPostIm, aCurPostDIm, "post", mImPre, mImPost); } if (mUseMultiScaleApproach && !mIsLastIters) @@ -142,12 +133,7 @@ namespace MMVII const bool aSaveGaussImage = false; if (aSaveGaussImage) - aCurPreDIm->ToFile("GaussFilteredImPre_iter_" + std::to_string(aIterNumber) + ".tif"); - } - else if (mUseMultiScaleApproach && mIsLastIters) - { - cAppli_cTriangleDeformation::LoadImageAndData(aCurPreIm, aCurPreDIm, "pre", mImPre, mImPost); - cAppli_cTriangleDeformation::LoadImageAndData(aCurPostIm, aCurPostDIm, "post", mImPre, mImPost); + aCurPreDIm->ToFile("GaussFilteredImPre_iter_" + ToStr(aIterNumber) + ".tif"); } //----------- declaration of indicator of convergence @@ -160,47 +146,51 @@ namespace MMVII // Loop over all triangles to add the observations on each point for (size_t aTr = 0; aTr < mDelTri.NbFace(); aTr++) { - const tTri2dr aTri = mDelTri.KthTri(aTr); - const cPt3di aIndicesOfTriKnots = mDelTri.KthFace(aTr); + const tTri2dr aTriRad = mDelTri.KthTri(aTr); + const cPt3di aIndicesOfTriKnotsRad = mDelTri.KthFace(aTr); - const cTriangle2DCompiled aCompTri(aTri); + const cTriangle2DCompiled aCompTri(aTriRad); - std::vector aVectorToFillWithInsidePixels; + std::vector aVectorToFillWithInsidePixels; aCompTri.PixelsInside(aVectorToFillWithInsidePixels); // get pixels inside triangle //----------- index of unknown, finds the associated pixels of current triangle knots - const tIntVect aVecInd = {2 * aIndicesOfTriKnots.x(), 2 * aIndicesOfTriKnots.x() + 1, - 2 * aIndicesOfTriKnots.y(), 2 * aIndicesOfTriKnots.y() + 1, - 2 * aIndicesOfTriKnots.z(), 2 * aIndicesOfTriKnots.z() + 1}; + const tIntVect aVecInd = {2 * aIndicesOfTriKnotsRad.x(), 2 * aIndicesOfTriKnotsRad.x() + 1, + 2 * aIndicesOfTriKnotsRad.y(), 2 * aIndicesOfTriKnotsRad.y() + 1, + 2 * aIndicesOfTriKnotsRad.z(), 2 * aIndicesOfTriKnotsRad.z() + 1}; + + const cNodeOfTriangles aFirstPointOfTriRad = cNodeOfTriangles(aVCurSolRad, aVecInd, 0, 1, 0, 1, aTriRad, 0); + const cNodeOfTriangles aSecondPointOfTriRad = cNodeOfTriangles(aVCurSolRad, aVecInd, 2, 3, 2, 3, aTriRad, 1); + const cNodeOfTriangles aThirdPointOfTriRad = cNodeOfTriangles(aVCurSolRad, aVecInd, 4, 5, 4, 5, aTriRad, 2); - const tREAL8 aCurRadTrPointA = aVCur(aVecInd.at(0)); // current translation on radiometry 1st point of triangle - const tREAL8 aCurRadScPointA = aVCur(aVecInd.at(1)); // current scale on radiometry 3rd point of triangle - const tREAL8 aCurRadTrPointB = aVCur(aVecInd.at(2)); // current translation on radiometry 2nd point of triangle - const tREAL8 aCurRadScPointB = aVCur(aVecInd.at(3)); // current scale on radiometry 3rd point of triangle - const tREAL8 aCurRadTrPointC = aVCur(aVecInd.at(4)); // current translation on radiometry 3rd point of triangle - const tREAL8 aCurRadScPointC = aVCur(aVecInd.at(5)); // current scale on radiometry 3rd point of triangle + const tREAL8 aCurRadTrPointA = aFirstPointOfTriRad.GetCurrentRadiometryTranslation(); // current translation on radiometry 1st point of triangle + const tREAL8 aCurRadScPointA = aFirstPointOfTriRad.GetCurrentRadiometryScaling(); // current scale on radiometry 3rd point of triangle + const tREAL8 aCurRadTrPointB = aSecondPointOfTriRad.GetCurrentRadiometryTranslation(); // current translation on radiometry 2nd point of triangle + const tREAL8 aCurRadScPointB = aSecondPointOfTriRad.GetCurrentRadiometryScaling(); // current scale on radiometry 3rd point of triangle + const tREAL8 aCurRadTrPointC = aThirdPointOfTriRad.GetCurrentRadiometryTranslation(); // current translation on radiometry 3rd point of triangle + const tREAL8 aCurRadScPointC = aThirdPointOfTriRad.GetCurrentRadiometryScaling(); // current scale on radiometry 3rd point of triangle // soft constraint radiometric translation if (mWeightRadTranslation >= 0) { - const int aSolStep = 2; // adapt step to solution vector configuration const int aSolStart = 0; + const int aSolStep = 2; // adapt step to solution vector configuration for (size_t aIndCurSol = aSolStart; aIndCurSol < aVecInd.size() - 1; aIndCurSol += aSolStep) { const int aIndices = aVecInd.at(aIndCurSol); - mSys->AddEqFixVar(aIndices, aVCur(aIndices), mWeightRadTranslation); + mSysRadiometry->AddEqFixVar(aIndices, aVCurSolRad(aIndices), mWeightRadTranslation); } } // soft constraint radiometric scaling if (mWeightRadScale >= 0) { - const int aSolStep = 2; // adapt step to solution vector configuration const int aSolStart = 1; + const int aSolStep = 2; // adapt step to solution vector configuration for (size_t aIndCurSol = aSolStart; aIndCurSol < aVecInd.size(); aIndCurSol += aSolStep) { const int aIndices = aVecInd.at(aIndCurSol); - mSys->AddEqFixVar(aIndices, aVCur(aIndices), mWeightRadScale); + mSysRadiometry->AddEqFixVar(aIndices, aVCurSolRad(aIndices), mWeightRadScale); } } @@ -211,38 +201,38 @@ namespace MMVII for (size_t aFilledPixel = 0; aFilledPixel < aNumberOfInsidePixels; aFilledPixel++) { const cPtInsideTriangles aPixInsideTriangle = cPtInsideTriangles(aCompTri, aVectorToFillWithInsidePixels, - aFilledPixel, *aCurPreDIm); - // prepare for barycenter translation formula by filling aVObs with different coordinates - FormalInterpBarycenter_SetObs(aVObs, 0, aPixInsideTriangle); + aFilledPixel, aCurPreDIm); + // prepare for barycenter translation formula by filling aVObsRad with different coordinates + FormalInterpBarycenter_SetObs(aVObsRad, 0, aPixInsideTriangle); // radiometry translation of pixel by current radiometry translation of triangle knots - const tREAL8 aRadiometryTranslation = cAppli_cTriangleDeformation::ApplyBarycenterTranslationFormulaForTranslationRadiometry(aCurRadTrPointA, - aCurRadTrPointB, - aCurRadTrPointC, - aVObs); + const tREAL8 aRadiometryTranslation = ApplyBarycenterTranslationFormulaForTranslationRadiometry(aCurRadTrPointA, + aCurRadTrPointB, + aCurRadTrPointC, + aVObsRad); // radiometry scaling of pixel by current radiometry scaling of triangle knots - const tREAL8 aRadiometryScaling = cAppli_cTriangleDeformation::ApplyBarycenterTranslationFormulaForScalingRadiometry(aCurRadScPointA, - aCurRadScPointB, - aCurRadScPointC, - aVObs); + const tREAL8 aRadiometryScaling = ApplyBarycenterTranslationFormulaForScalingRadiometry(aCurRadScPointA, + aCurRadScPointB, + aCurRadScPointC, + aVObsRad); - const cPt2dr aInsideTrianglePoint = aPixInsideTriangle.GetCartesianCoordinates(); - const cPt2di aEastTranslatedPoint = cPt2di(aInsideTrianglePoint.x(), aInsideTrianglePoint.y()) + cPt2di(1, 0); - const cPt2di aSouthTranslatedPoint = cPt2di(aInsideTrianglePoint.x(), aInsideTrianglePoint.y()) + cPt2di(0, 1); + const tPt2dr aInsideTrianglePoint = aPixInsideTriangle.GetCartesianCoordinates(); + const tPt2di aEastTranslatedPoint = tPt2di(aInsideTrianglePoint.x(), aInsideTrianglePoint.y()) + tPt2di(1, 0); + const tPt2di aSouthTranslatedPoint = tPt2di(aInsideTrianglePoint.x(), aInsideTrianglePoint.y()) + tPt2di(0, 1); - if (aCurPostDIm->InsideBL(cPt2dr(aEastTranslatedPoint.x(), aEastTranslatedPoint.y()))) // avoid errors + if (aCurPostDIm->InsideBL(tPt2dr(aEastTranslatedPoint.x(), aEastTranslatedPoint.y()))) // avoid errors { - if (aCurPostDIm->InsideBL(cPt2dr(aSouthTranslatedPoint.x(), aSouthTranslatedPoint.y()))) // avoid errors + if (aCurPostDIm->InsideBL(tPt2dr(aSouthTranslatedPoint.x(), aSouthTranslatedPoint.y()))) // avoid errors { // prepare for application of bilinear formula - FormalBilinTri_SetObs(aVObs, TriangleDisplacement_NbObs, aInsideTrianglePoint, *aCurPostDIm); + FormalBilinTri_SetObs(aVObsRad, TriangleDisplacement_NbObs, aInsideTrianglePoint, *aCurPostDIm); // Now add observation - mSys->CalcAndAddObs(mEqRadiometryTri, aVecInd, aVObs); + mSysRadiometry->CalcAndAddObs(mEqRadiometryTri, aVecInd, aVObsRad); // compute indicators - const tREAL8 aRadiomValueImPre = aRadiometryScaling * aVObs[5] + aRadiometryTranslation; + const tREAL8 aRadiomValueImPre = aRadiometryScaling * aVObsRad[5] + aRadiometryTranslation; const tREAL8 aDif = aRadiomValueImPre - aCurPostDIm->GetVBL(aInsideTrianglePoint); // residual aSomDif += std::abs(aDif); } @@ -254,60 +244,22 @@ namespace MMVII } // Update all parameter taking into account previous observation - mSys->SolveUpdateReset(); + mSysRadiometry->SolveUpdateReset(); if (mShow) StdOut() << aIterNumber + 1 << ", " << aSomDif / aTotalNumberOfInsidePixels << ", " << aNbOut << std::endl; } - void cAppli_cTriangleDeformationRadiometry::FillOutputImage(const cPtInsideTriangles &aLastPixInsideTriangle, - const tREAL8 aLastRadiometryTranslation, - const tREAL8 aLastRadiometryScaling) - { - const tREAL8 aLastXCoordinate = aLastPixInsideTriangle.GetCartesianCoordinates().x(); - const tREAL8 aLastYCoordinate = aLastPixInsideTriangle.GetCartesianCoordinates().y(); - - const cPt2di aLastCoordinate = cPt2di(aLastXCoordinate, aLastYCoordinate); - - const tREAL8 aLastRadiometryValue = aLastRadiometryScaling * aLastPixInsideTriangle.GetPixelValue() + - aLastRadiometryTranslation; - - // Build image with radiometric intensities - mDImOut->SetV(aLastCoordinate, aLastRadiometryValue); - } - - tREAL8 cAppli_cTriangleDeformationRadiometry::ApplyLastBarycenterInterpolationFormulaRadiometryTranslation(const tREAL8 aLastRadTranslationPointA, - const tREAL8 aLastRadTranslationPointB, - const tREAL8 aLastRadTranslationPointC, - const cPtInsideTriangles &aLastPixInsideTriangle) - { - const cPt3dr BarycenterCoordinateOfPoint = aLastPixInsideTriangle.GetBarycenterCoordinates(); - const tREAL8 aCurentRadTranslation = BarycenterCoordinateOfPoint.x() * aLastRadTranslationPointA + BarycenterCoordinateOfPoint.y() * aLastRadTranslationPointB + - BarycenterCoordinateOfPoint.z() * aLastRadTranslationPointC; - return aCurentRadTranslation; - } - - tREAL8 cAppli_cTriangleDeformationRadiometry::ApplyLastBarycenterInterpolationFormulaRadiometryScaling(const tREAL8 aLastRadScalingPointA, - const tREAL8 aLastRadScalingPointB, - const tREAL8 aLastRadScalingPointC, - const cPtInsideTriangles &aLastPixInsideTriangle) - { - const cPt3dr BarycenterCoordinateOfPoint = aLastPixInsideTriangle.GetBarycenterCoordinates(); - const tREAL8 aCurrentRadScaling = BarycenterCoordinateOfPoint.x() * aLastRadScalingPointA + BarycenterCoordinateOfPoint.y() * aLastRadScalingPointB + - BarycenterCoordinateOfPoint.z() * aLastRadScalingPointC; - return aCurrentRadScaling; - } - - void cAppli_cTriangleDeformationRadiometry::GenerateOutputImageAndDisplayLastRadiometryValues(const tDenseVect &aVFinalSol, const int aIterNumber) + void cAppli_TriangleDeformationRadiometry::GenerateOutputImageAndDisplayLastRadiometryValues(const tDenseVect &aVFinalSol, const int aIterNumber) { mImOut = tIm(mSzImPre); mDImOut = &mImOut.DIm(); - mSzImOut = cPt2di(mDImOut->Sz().x(), mDImOut->Sz().y()); + mSzImOut = mDImOut->Sz(); tIm aLastPreIm = tIm(mSzImPre); tDIm *aLastPreDIm = nullptr; - cAppli_cTriangleDeformation::LoadImageAndData(aLastPreIm, aLastPreDIm, "pre", mImPre, mImPost); + LoadPrePostImageAndData(aLastPreIm, aLastPreDIm, "pre", mImPre, mImPost); if (mUseMultiScaleApproach && !mIsLastIters) { @@ -315,98 +267,85 @@ namespace MMVII aLastPreDIm = &aLastPreIm.DIm(); } - for (const cPt2di &aOutPix : *mDImOut) // Initialise output image + for (const tPt2di &aOutPix : *mDImOut) // Initialise output image mDImOut->SetV(aOutPix, aLastPreDIm->GetV(aOutPix)); for (size_t aLTr = 0; aLTr < mDelTri.NbFace(); aLTr++) { - const tTri2dr aLastTri = mDelTri.KthTri(aLTr); - const cPt3di aLastIndicesOfTriKnots = mDelTri.KthFace(aLTr); + const tTri2dr aLastTriRad = mDelTri.KthTri(aLTr); + const cPt3di aLastIndicesOfTriKnotsTr = mDelTri.KthFace(aLTr); - const cTriangle2DCompiled aLastCompTri(aLastTri); + const cTriangle2DCompiled aLastCompTri(aLastTriRad); - std::vector aLastVectorToFillWithInsidePixels; + std::vector aLastVectorToFillWithInsidePixels; aLastCompTri.PixelsInside(aLastVectorToFillWithInsidePixels); - const tIntVect aLastVecInd = {2 * aLastIndicesOfTriKnots.x(), 2 * aLastIndicesOfTriKnots.x() + 1, - 2 * aLastIndicesOfTriKnots.y(), 2 * aLastIndicesOfTriKnots.y() + 1, - 2 * aLastIndicesOfTriKnots.z(), 2 * aLastIndicesOfTriKnots.z() + 1}; + const tIntVect aLastVecInd = {2 * aLastIndicesOfTriKnotsTr.x(), 2 * aLastIndicesOfTriKnotsTr.x() + 1, + 2 * aLastIndicesOfTriKnotsTr.y(), 2 * aLastIndicesOfTriKnotsTr.y() + 1, + 2 * aLastIndicesOfTriKnotsTr.z(), 2 * aLastIndicesOfTriKnotsTr.z() + 1}; - const tREAL8 aLastRadTrPointA = aVFinalSol(aLastVecInd.at(0)); // last translation on radiometry 1st point of triangle - const tREAL8 aLastRadScPointA = aVFinalSol(aLastVecInd.at(1)); // last scale on radiometry 1st point of triangle - const tREAL8 aLastRadTrPointB = aVFinalSol(aLastVecInd.at(2)); // last translation on radiometry 2nd point of triangle - const tREAL8 aLastRadScPointB = aVFinalSol(aLastVecInd.at(3)); // last scale on radiometry 2nd point of triangle - const tREAL8 aLastRadTrPointC = aVFinalSol(aLastVecInd.at(4)); // last translation on radiometry 3rd point of triangle - const tREAL8 aLastRadScPointC = aVFinalSol(aLastVecInd.at(5)); // last scale on radiometry 3rd point of triangle + const cNodeOfTriangles aLastFirstPointOfTri = cNodeOfTriangles(aVFinalSol, aLastVecInd, 0, 1, 0, 1, aLastTriRad, 0); + const cNodeOfTriangles aLastSecondPointOfTri = cNodeOfTriangles(aVFinalSol, aLastVecInd, 2, 3, 2, 3, aLastTriRad, 1); + const cNodeOfTriangles aLastThirdPointOfTri = cNodeOfTriangles(aVFinalSol, aLastVecInd, 4, 5, 4, 5, aLastTriRad, 2); + + const tREAL8 aLastRadTrPointA = aLastFirstPointOfTri.GetCurrentRadiometryTranslation(); + const tREAL8 aLastRadScPointA = aLastFirstPointOfTri.GetCurrentRadiometryScaling(); + const tREAL8 aLastRadTrPointB = aLastSecondPointOfTri.GetCurrentRadiometryTranslation(); + const tREAL8 aLastRadScPointB = aLastSecondPointOfTri.GetCurrentRadiometryScaling(); + const tREAL8 aLastRadTrPointC = aLastThirdPointOfTri.GetCurrentRadiometryTranslation(); + const tREAL8 aLastRadScPointC = aLastThirdPointOfTri.GetCurrentRadiometryScaling(); const size_t aLastNumberOfInsidePixels = aLastVectorToFillWithInsidePixels.size(); for (size_t aLastFilledPixel = 0; aLastFilledPixel < aLastNumberOfInsidePixels; aLastFilledPixel++) { const cPtInsideTriangles aLastPixInsideTriangle = cPtInsideTriangles(aLastCompTri, aLastVectorToFillWithInsidePixels, - aLastFilledPixel, *aLastPreDIm); + aLastFilledPixel, aLastPreDIm); // radiometry translation of pixel by current radiometry translation - const tREAL8 aLastRadiometryTranslation = cAppli_cTriangleDeformationRadiometry::ApplyLastBarycenterInterpolationFormulaRadiometryTranslation(aLastRadTrPointA, - aLastRadTrPointB, - aLastRadTrPointC, - aLastPixInsideTriangle); - - const tREAL8 aLastRadiometryScaling = cAppli_cTriangleDeformationRadiometry::ApplyLastBarycenterInterpolationFormulaRadiometryScaling(aLastRadScPointA, - aLastRadScPointB, - aLastRadScPointC, - aLastPixInsideTriangle); - - FillOutputImage(aLastPixInsideTriangle, aLastRadiometryTranslation, - aLastRadiometryScaling); + const tREAL8 aLastRadiometryTranslation = ApplyBarycenterTranslationFormulaForTranslationRadiometry(aLastRadTrPointA, + aLastRadTrPointB, + aLastRadTrPointC, + aLastPixInsideTriangle); + + const tREAL8 aLastRadiometryScaling = ApplyBarycenterTranslationFormulaForScalingRadiometry(aLastRadScPointA, + aLastRadScPointB, + aLastRadScPointC, + aLastPixInsideTriangle); + + FillOutputImageRadiometry(aLastPixInsideTriangle, aLastRadiometryTranslation, + aLastRadiometryScaling, mDImOut); } } // save output image with calculated radiometries to image file - mDImOut->ToFile("OutputImage_" + std::to_string(mNumberOfScales) + "_" + std::to_string(mNumberPointsToGenerate) + ".tif"); - - if (mDisplayLastRadiometryValues) - { - for (int aFinalUnk = 0; aFinalUnk < aVFinalSol.DIm().Sz(); aFinalUnk++) - { - StdOut() << aVFinalSol(aFinalUnk) << " "; - if (aFinalUnk % 2 == 1 && aFinalUnk != 0) - StdOut() << std::endl; - } - } + mDImOut->ToFile("OutputImage_" + ToStr(mNumberPointsToGenerate) + "_" + ToStr(mNumberOfScales) + ".tif"); } - void cAppli_cTriangleDeformationRadiometry::DoOneIterationRadiometry(const int aIterNumber) + void cAppli_TriangleDeformationRadiometry::DoOneIterationRadiometry(const int aIterNumber, const int aTotalNumberOfIterations, + const tDenseVect &aVInitSol) { LoopOverTrianglesAndUpdateParametersRadiometry(aIterNumber); // Iterate over triangles and solve system - tDenseVect aVFinalSol = mSys->CurGlobSol(); + tDenseVect aVFinalSol = mSysRadiometry->CurGlobSol(); + // Show final translation results and produce displacement maps - if (mUseMultiScaleApproach) - { - if (aIterNumber == (mNumberOfScales + mNumberOfEndIterations - 1)) - GenerateOutputImageAndDisplayLastRadiometryValues(aVFinalSol, aIterNumber); - } - else + if (aIterNumber == (aTotalNumberOfIterations - 1)) { - if (aIterNumber == (mNumberOfScales - 1)) - GenerateOutputImageAndDisplayLastRadiometryValues(aVFinalSol, aIterNumber); + GenerateOutputImageAndDisplayLastRadiometryValues(aVFinalSol, aIterNumber); + // Display last computed values of radiometry unknowns + if (mDisplayLastRadiometryValues) + DisplayLastUnknownValuesAndComputeStatistics(aVFinalSol, aVInitSol); } } //----------------------------------------- - int cAppli_cTriangleDeformationRadiometry::Exe() + int cAppli_TriangleDeformationRadiometry::Exe() { // read pre and post images and their sizes - mImPre = tIm::FromFile(mNamePreImage); - mImPost = tIm::FromFile(mNamePostImage); - - mDImPre = &mImPre.DIm(); - mSzImPre = mDImPre->Sz(); - - mDImPost = &mImPost.DIm(); - mSzImPost = mDImPost->Sz(); + ReadFileNameLoadData(mNamePreImage, mImPre, mDImPre, mSzImPre); + ReadFileNameLoadData(mNamePostImage, mImPost, mDImPost, mSzImPost); if (mUseMultiScaleApproach) mSigmaGaussFilter = mNumberOfScales * mSigmaGaussFilterStep; @@ -416,21 +355,19 @@ namespace MMVII << "Diff, " << "NbOut" << std::endl; - cAppli_cTriangleDeformation::GeneratePointsForDelaunay(mVectorPts, mNumberPointsToGenerate, mRandomUniformLawUpperBoundLines, - mRandomUniformLawUpperBoundCols, mDelTri, mSzImPre); + DefineValueLimitsForPointGenerationAndBuildGrid(mNumberPointsToGenerate, mNumberOfLines, + mNumberOfCols, mDelTri, mSzImPre, mBuildRandomUniformGrid); - cAppli_cTriangleDeformationRadiometry::InitialisationAfterExeRadiometry(mDelTri, mSys); + InitialisationAfterExeRadiometry(mDelTri, mSysRadiometry, mInitialiseWithUserValues, + mInitialiseRadTrValue, mInitialiseRadScValue); - if (mUseMultiScaleApproach) - { - for (int aIterNumber = 0; aIterNumber < mNumberOfScales + mNumberOfEndIterations; aIterNumber++) - DoOneIterationRadiometry(aIterNumber); - } - else - { - for (int aIterNumber = 0; aIterNumber < mNumberOfScales; aIterNumber++) - DoOneIterationRadiometry(aIterNumber); - } + const tDenseVect aVInitSolRad = mSysRadiometry->CurGlobSol().Dup(); // Duplicate initial solution + + int aTotalNumberOfIterations = 0; + (mUseMultiScaleApproach) ? aTotalNumberOfIterations = mNumberOfScales + mNumberOfEndIterations : aTotalNumberOfIterations = mNumberOfScales; + + for (int aIterNumber = 0; aIterNumber < aTotalNumberOfIterations; aIterNumber++) + DoOneIterationRadiometry(aIterNumber, aTotalNumberOfIterations, aVInitSolRad); return EXIT_SUCCESS; } @@ -439,19 +376,19 @@ namespace MMVII // ::MMVII // /********************************************/ - tMMVII_UnikPApli Alloc_cTriangleDeformationRadiometry(const std::vector &aVArgs, - const cSpecMMVII_Appli &aSpec) + tMMVII_UnikPApli Alloc_cAppli_TriangleDeformationRadiometry(const std::vector &aVArgs, + const cSpecMMVII_Appli &aSpec) { - return tMMVII_UnikPApli(new cAppli_cTriangleDeformationRadiometry(aVArgs, aSpec)); + return tMMVII_UnikPApli(new cAppli_TriangleDeformationRadiometry(aVArgs, aSpec)); } cSpecMMVII_Appli TheSpec_ComputeTriangleDeformationRadiometry( "ComputeTriangleDeformationRadiometry", - Alloc_cTriangleDeformationRadiometry, + Alloc_cAppli_TriangleDeformationRadiometry, "Compute radiometric deformation between images using triangles", {eApF::ImProc}, // category {eApDT::Image}, // input {eApDT::Image}, // output __FILE__); -}; // namespace MMVII \ No newline at end of file +}; // namespace MMVII diff --git a/MMVII/src/MeshDisplacement/TriangleDeformationRadiometry.h b/MMVII/src/MeshDisplacement/TriangleDeformationRadiometry.h index 6af4d4f3a9..db05cbb33b 100644 --- a/MMVII/src/MeshDisplacement/TriangleDeformationRadiometry.h +++ b/MMVII/src/MeshDisplacement/TriangleDeformationRadiometry.h @@ -3,61 +3,46 @@ #include "MMVII_Geom2D.h" #include "MMVII_PhgrDist.h" +#include "MMVII_TplSymbTriangle.h" #include "TriangleDeformation.h" + using namespace NS_SymbolicDerivative; namespace MMVII { - /**************************************************/ - /* */ - /* cAppli_cTriangleDeformationRadiometry */ - /* */ - /**************************************************/ + /*************************************************/ + /* */ + /* cAppli_TriangleDeformationRadiometry */ + /* */ + /*************************************************/ - class cAppli_cTriangleDeformationRadiometry : public cAppli_cTriangleDeformation + class cAppli_TriangleDeformationRadiometry : public cAppli_TriangleDeformation { public: typedef cIm2D tIm; typedef cDataIm2D tDIm; typedef cTriangle tTri2dr; - typedef cDenseVect tDenseVect; + typedef cDenseVect tDenseVect; typedef std::vector tIntVect; - typedef std::vector tDoubleVect; + typedef std::vector tDoubleVect; - cAppli_cTriangleDeformationRadiometry(const std::vector &aVArgs, - const cSpecMMVII_Appli &aSpec); - ~cAppli_cTriangleDeformationRadiometry(); + cAppli_TriangleDeformationRadiometry(const std::vector &aVArgs, + const cSpecMMVII_Appli &aSpec); + ~cAppli_TriangleDeformationRadiometry(); int Exe() override; cCollecSpecArg2007 &ArgObl(cCollecSpecArg2007 &anArgObl) override; cCollecSpecArg2007 &ArgOpt(cCollecSpecArg2007 &anArgOpt) override; // Iterate of triangles and inside pixels - virtual void DoOneIterationRadiometry(const int aIterNumber); + void DoOneIterationRadiometry(const int aIterNumber, const int aTotalNumberOfIterations, + const tDenseVect &aVinitSol); // Loops over all triangles and solves system to update parameters at end of iteration - virtual void LoopOverTrianglesAndUpdateParametersRadiometry(const int aIterNumber); + void LoopOverTrianglesAndUpdateParametersRadiometry(const int aIterNumber); // Generate displacement maps of last solution - virtual void GenerateOutputImageAndDisplayLastRadiometryValues(const tDenseVect &aVFinalSol, const int aIterNumber); - // Initialise problem after user has input information - void InitialisationAfterExeRadiometry(cTriangulation2D &aDelaunayTri, - cResolSysNonLinear *&aSys); - // Fill displacement maps and output image - void FillOutputImage(const cPtInsideTriangles &aLastPixInsideTriangle, - const tREAL8 aLastRadiometryTranslation, - const tREAL8 aLastRadiometryScaling); - - // Apply barycentric translation formula to last radiometric translation values - tREAL8 ApplyLastBarycenterInterpolationFormulaRadiometryTranslation(const tREAL8 aLastRadTranslationPointA, - const tREAL8 aLastRadTranslationPointB, - const tREAL8 aLastRadTranslationPointC, - const cPtInsideTriangles &aLastPixInsideTriangle); - // Apply barycentric translation formula to last radiometric scaling values - tREAL8 ApplyLastBarycenterInterpolationFormulaRadiometryScaling(const tREAL8 aLastRadScalingPointA, - const tREAL8 aLastRadScalingPointB, - const tREAL8 aLastRadScalingPointC, - const cPtInsideTriangles &aLastPixInsideTriangle); + void GenerateOutputImageAndDisplayLastRadiometryValues(const tDenseVect &aVFinalSol, const int aIterNumber); private: // == Mandatory args ==== @@ -69,17 +54,21 @@ namespace MMVII // == Optionnal args ==== - int mRandomUniformLawUpperBoundLines; // Uniform law generates random coordinates in interval [0, mRandomUniformLawUpperBoundLines [ - int mRandomUniformLawUpperBoundCols; // Uniform law generates random coordinates in interval [0, mRandomUniformLawUpperBoundCols [ - bool mShow; // Print result, export image ... - bool mGenerateOutputImage; // Generate image with displaced pixels - bool mUseMultiScaleApproach; // Apply multi-scale approach or not - tREAL8 mWeightRadTranslation; // Weight given to radiometry translation if soft freezing is applied (default : negative => not applied) - tREAL8 mWeightRadScale; // Weight given to radiometry scaling if soft freezing is applied (default : negative => not applied) - bool mDisplayLastRadiometryValues; // Display final values of radiometry unknowns at last iteration of optimisation process - int mSigmaGaussFilterStep; // Decreasing step of sigma value during iterations - int mNumberOfIterGaussFilter; // Number of iterations to be done in Gauss filter algorithm - int mNumberOfEndIterations; // Number of iterations to do while using original image in multi-scale approach + int mNumberOfLines; // Uniform law generates random coordinates in interval [0, mNumberOfLines [ + int mNumberOfCols; // Uniform law generates random coordinates in interval [0, mNumberOfCols [ + bool mShow; // Print result, export image ... + bool mGenerateOutputImage; // Generate image with computed radiometric pixels + bool mBuildRandomUniformGrid; // Whether to triangulate grid made of points whose coordinates follow a uniform law or have coordinates that form rectangles + bool mInitialiseWithUserValues; // Initalise or not with values given by user + tREAL8 mInitialiseRadTrValue; // Value given by user to initialise radiometry transltion unknowns + tREAL8 mInitialiseRadScValue; // Value given by user to initialise radiometry scaling unknowns + bool mUseMultiScaleApproach; // Apply multi-scale approach or not + tREAL8 mWeightRadTranslation; // Weight given to radiometry translation if soft freezing is applied (default : negative => not applied) + tREAL8 mWeightRadScale; // Weight given to radiometry scaling if soft freezing is applied (default : negative => not applied) + bool mDisplayLastRadiometryValues; // Display final values of radiometry unknowns at last iteration of optimisation process + int mSigmaGaussFilterStep; // Decreasing step of sigma value during iterations + int mNumberOfIterGaussFilter; // Number of iterations to be done in Gauss filter algorithm + int mNumberOfEndIterations; // Number of iterations to do while using original image in multi-scale approach // == Internal variables ==== @@ -98,11 +87,10 @@ namespace MMVII tREAL8 mSigmaGaussFilter; // Value of sigma in gauss filter bool mIsLastIters; // Determines whether optimisation process is at last iters to optimise on original image - std::vector mVectorPts; // A vector containing a set of points cTriangulation2D mDelTri; // A Delaunay triangle - cResolSysNonLinear *mSys; // Non Linear Sys for solving problem - cCalculator *mEqRadiometryTri; // calculator giving access to values and derivatives + cResolSysNonLinear *mSysRadiometry; // Non Linear Sys for solving problem + cCalculator *mEqRadiometryTri; // calculator giving access to values and derivatives }; } diff --git a/MMVII/src/MeshDisplacement/TriangleDeformationTrRad.cpp b/MMVII/src/MeshDisplacement/TriangleDeformationTrRad.cpp deleted file mode 100644 index acec5284f8..0000000000 --- a/MMVII/src/MeshDisplacement/TriangleDeformationTrRad.cpp +++ /dev/null @@ -1,583 +0,0 @@ -#include "cMMVII_Appli.h" - -#include "MMVII_TplSymbTriangle.h" - -#include "TriangleDeformationTrRad.h" - -/** - \file TriangleDeformationTrRad.cpp - - \brief file for computing 2D deformations (translation and radiometry) - between 2 images thanks to triangles. -**/ - -namespace MMVII -{ - /******************************************/ - /* */ - /* cAppli_cTriangleDeformationTrRad */ - /* */ - /******************************************/ - - cAppli_cTriangleDeformationTrRad::cAppli_cTriangleDeformationTrRad(const std::vector &aVArgs, - const cSpecMMVII_Appli &aSpec) : cAppli_cTriangleDeformation(aVArgs, aSpec), - mRandomUniformLawUpperBoundLines(1), - mRandomUniformLawUpperBoundCols(1), - mShow(true), - mUseMultiScaleApproach(true), - mSigmaGaussFilterStep(1), - mGenerateDisplacementImage(true), - mFreezeTranslationX(false), - mFreezeTranslationY(false), - mFreezeRadTranslation(false), - mFreezeRadScale(false), - mWeightRadTranslation(-1), - mWeightRadScale(-1), - mNumberOfIterGaussFilter(3), - mNumberOfEndIterations(2), - mDisplayLastTranslationValues(false), - mDisplayLastRadiometryValues(false), - mSzImPre(cPt2di(1, 1)), - mImPre(mSzImPre), - mDImPre(nullptr), - mSzImPost(cPt2di(1, 1)), - mImPost(mSzImPost), - mDImPost(nullptr), - mSzImOut(cPt2di(1, 1)), - mImOut(mSzImOut), - mDImOut(nullptr), - mSzImDepX(cPt2di(1, 1)), - mImDepX(mSzImDepX), - mDImDepX(nullptr), - mSzImDepY(cPt2di(1, 1)), - mImDepY(mSzImDepY), - mDImDepY(nullptr), - mVectorPts({cPt2dr(0, 0)}), - mDelTri(mVectorPts), - mSys(nullptr), - mEqTriDeformTrRad(nullptr) - { - mEqTriDeformTrRad = EqDeformTriTrRad(true, 1); // true means with derivative, 1 is size of buffer - } - - cAppli_cTriangleDeformationTrRad::~cAppli_cTriangleDeformationTrRad() - { - delete mSys; - delete mEqTriDeformTrRad; - } - - cCollecSpecArg2007 &cAppli_cTriangleDeformationTrRad::ArgObl(cCollecSpecArg2007 &anArgObl) - { - return anArgObl - << Arg2007(mNamePreImage, "Name of pre-image file.", {{eTA2007::FileImage}, {eTA2007::FileDirProj}}) - << Arg2007(mNamePostImage, "Name of post-image file.", {eTA2007::FileImage}) - << Arg2007(mNumberPointsToGenerate, "Number of points you want to generate for triangulation.") - << Arg2007(mNumberOfScales, "Total number of scales to run in multi-scale approach optimisation process."); - } - - cCollecSpecArg2007 &cAppli_cTriangleDeformationTrRad::ArgOpt(cCollecSpecArg2007 &anArgOpt) - { - return anArgOpt - << AOpt2007(mRandomUniformLawUpperBoundCols, "RandomUniformLawUpperBoundXAxis", - "Maximum value that the uniform law can draw from on the x-axis.", {eTA2007::HDV}) - << AOpt2007(mRandomUniformLawUpperBoundLines, "RandomUniformLawUpperBoundYAxis", - "Maximum value that the uniform law can draw from for on the y-axis.", {eTA2007::HDV}) - << AOpt2007(mShow, "Show", "Whether to print minimisation results.", {eTA2007::HDV}) - << AOpt2007(mUseMultiScaleApproach, "UseMultiScaleApproach", "Whether to use multi-scale approach or not.", {eTA2007::HDV}) - << AOpt2007(mSigmaGaussFilterStep, "SigmaGaussFilterStep", "Sigma value to use for Gauss filter in multi-stage approach.", {eTA2007::HDV}) - << AOpt2007(mGenerateDisplacementImage, "GenerateDisplacementImage", - "Whether to generate and save an image having been translated.", {eTA2007::HDV}) - << AOpt2007(mFreezeTranslationX, "FreezeXTranslation", - "Whether to freeze or not x-translation to certain value during computation.", {eTA2007::HDV}) - << AOpt2007(mFreezeTranslationY, "FreezeYTranslation", - "Whether to freeze or not y-translation to certain value during computation.", {eTA2007::HDV}) - << AOpt2007(mFreezeRadTranslation, "FreezeRadTranslation", - "Whether to freeze radiometry translation factor in computation or not.", {eTA2007::HDV}) - << AOpt2007(mFreezeRadScale, "FreezeRadScaling", - "Whether to freeze radiometry scaling factor in computation or not.", {eTA2007::HDV}) - << AOpt2007(mWeightRadTranslation, "WeightRadiometryTranslation", - "A value to weight radiometry translation for soft freezing of coefficient.", {eTA2007::HDV}) - << AOpt2007(mWeightRadScale, "WeightRadiometryScaling", - "A value to weight radiometry scaling for soft freezing of coefficient.", {eTA2007::HDV}) - << AOpt2007(mNumberOfIterGaussFilter, "NumberOfIterationsGaussFilter", - "Number of iterations to run in Gauss filter algorithm.", {eTA2007::HDV}) - << AOpt2007(mNumberOfEndIterations, "NumberOfEndIterations", - "Number of iterations to run on original images in multi-scale approach.", {eTA2007::HDV}) - << AOpt2007(mDisplayLastTranslationValues, "DisplayLastTranslationsValues", - "Whether to display the final values of unknowns linked to point translation.", {eTA2007::HDV}) - << AOpt2007(mDisplayLastRadiometryValues, "DisplayLastRadiometryValues", - "Whether to display or not the last values of radiometry unknowns after optimisation process.", {eTA2007::HDV}); - } - - void cAppli_cTriangleDeformationTrRad::LoopOverTrianglesAndUpdateParameters(const int aIterNumber) - { - //----------- allocate vec of obs : - tDoubleVect aVObs(12, 0.0); // 6 for ImagePre and 6 for ImagePost - - //----------- extract current parameters - tDenseVect aVCur = mSys->CurGlobSol(); // Get current solution. - - tIm aCurPreIm = tIm(mSzImPre); - tDIm *aCurPreDIm = nullptr; - tIm aCurPostIm = tIm(mSzImPost); - tDIm *aCurPostDIm = nullptr; - - mIsLastIters = false; - - if (mUseMultiScaleApproach) - mIsLastIters = cAppli_cTriangleDeformation::ManageDifferentCasesOfEndIterations(aIterNumber, mNumberOfScales, mNumberOfEndIterations, - mIsLastIters, mImPre, mImPost, aCurPreIm, aCurPreDIm, - aCurPostIm, aCurPostDIm); - else - { - cAppli_cTriangleDeformation::LoadImageAndData(aCurPreIm, aCurPreDIm, "pre", mImPre, mImPost); - cAppli_cTriangleDeformation::LoadImageAndData(aCurPostIm, aCurPostDIm, "post", mImPre, mImPost); - } - - if (mUseMultiScaleApproach && !mIsLastIters) - { - aCurPreIm = mImPre.GaussFilter(mSigmaGaussFilter, mNumberOfIterGaussFilter); - aCurPostIm = mImPost.GaussFilter(mSigmaGaussFilter, mNumberOfIterGaussFilter); - - aCurPreDIm = &aCurPreIm.DIm(); - aCurPostDIm = &aCurPostIm.DIm(); - - mSigmaGaussFilter -= 1; - - const bool aSaveGaussImage = false; - if (aSaveGaussImage) - aCurPreDIm->ToFile("GaussFilteredImPre_iter_" + std::to_string(aIterNumber) + ".tif"); - } - else if (mUseMultiScaleApproach && mIsLastIters) - { - cAppli_cTriangleDeformation::LoadImageAndData(aCurPreIm, aCurPreDIm, "pre", mImPre, mImPost); - cAppli_cTriangleDeformation::LoadImageAndData(aCurPostIm, aCurPostDIm, "post", mImPre, mImPost); - } - - //----------- declaration of indicator of convergence - tREAL8 aSomDif = 0; // sum of difference between untranslated pixel and translated one. - size_t aNbOut = 0; // number of translated pixels out of image - - // Count number of pixels inside triangles for normalisation - size_t aTotalNumberOfInsidePixels = 0; - - // hard constraint : freeze radiometric coefficients - if (mFreezeRadTranslation || mFreezeRadScale || - mFreezeTranslationX || mFreezeTranslationY) - { - for (size_t aTr = 0; aTr < mDelTri.NbFace(); aTr++) - { - const cPt3di aIndicesOfTriKnots = mDelTri.KthFace(aTr); - - const tIntVect aVecInd = {4 * aIndicesOfTriKnots.x(), 4 * aIndicesOfTriKnots.x() + 1, - 4 * aIndicesOfTriKnots.x() + 2, 4 * aIndicesOfTriKnots.x() + 3, - 4 * aIndicesOfTriKnots.y(), 4 * aIndicesOfTriKnots.y() + 1, - 4 * aIndicesOfTriKnots.y() + 2, 4 * aIndicesOfTriKnots.y() + 3, - 4 * aIndicesOfTriKnots.z(), 4 * aIndicesOfTriKnots.z() + 1, - 4 * aIndicesOfTriKnots.z() + 2, 4 * aIndicesOfTriKnots.z() + 3}; - - if (mFreezeTranslationX) - { - mSys->SetFrozenVar(aVecInd.at(2), aVCur(0)); - mSys->SetFrozenVar(aVecInd.at(6), aVCur(4)); - mSys->SetFrozenVar(aVecInd.at(10), aVCur(8)); - } - if (mFreezeTranslationY) - { - mSys->SetFrozenVar(aVecInd.at(2), aVCur(1)); - mSys->SetFrozenVar(aVecInd.at(6), aVCur(5)); - mSys->SetFrozenVar(aVecInd.at(10), aVCur(9)); - } - if (mFreezeRadTranslation) - { - mSys->SetFrozenVar(aVecInd.at(2), aVCur(2)); - mSys->SetFrozenVar(aVecInd.at(6), aVCur(6)); - mSys->SetFrozenVar(aVecInd.at(10), aVCur(10)); - } - if (mFreezeRadScale) - { - mSys->SetFrozenVar(aVecInd.at(3), aVCur(3)); - mSys->SetFrozenVar(aVecInd.at(7), aVCur(7)); - mSys->SetFrozenVar(aVecInd.at(11), aVCur(11)); - } - } - } - - // Loop over all triangles to add the observations on each point - for (size_t aTr = 0; aTr < mDelTri.NbFace(); aTr++) - { - const tTri2dr aTri = mDelTri.KthTri(aTr); - const cPt3di aIndicesOfTriKnots = mDelTri.KthFace(aTr); - - const cTriangle2DCompiled aCompTri(aTri); - - std::vector aVectorToFillWithInsidePixels; - aCompTri.PixelsInside(aVectorToFillWithInsidePixels); // get pixels inside triangle - - //----------- index of unknown, finds the associated pixels of current triangle - const tIntVect aVecInd = {4 * aIndicesOfTriKnots.x(), 4 * aIndicesOfTriKnots.x() + 1, - 4 * aIndicesOfTriKnots.x() + 2, 4 * aIndicesOfTriKnots.x() + 3, - 4 * aIndicesOfTriKnots.y(), 4 * aIndicesOfTriKnots.y() + 1, - 4 * aIndicesOfTriKnots.y() + 2, 4 * aIndicesOfTriKnots.y() + 3, - 4 * aIndicesOfTriKnots.z(), 4 * aIndicesOfTriKnots.z() + 1, - 4 * aIndicesOfTriKnots.z() + 2, 4 * aIndicesOfTriKnots.z() + 3}; - - const cPt2dr aCurTrPointA = cPt2dr(aVCur(aVecInd.at(0)), - aVCur(aVecInd.at(1))); // current translation 1st point of triangle - const cPt2dr aCurTrPointB = cPt2dr(aVCur(aVecInd.at(4)), - aVCur(aVecInd.at(5))); // current translation 2nd point of triangle - const cPt2dr aCurTrPointC = cPt2dr(aVCur(aVecInd.at(8)), - aVCur(aVecInd.at(9))); // current translation 3rd point of triangle - - const tREAL8 aCurRadTrPointA = aVCur(aVecInd.at(2)); // current translation on radiometry 1st point of triangle - const tREAL8 aCurRadScPointA = aVCur(aVecInd.at(3)); // current scale on radiometry 3rd point of triangle - const tREAL8 aCurRadTrPointB = aVCur(aVecInd.at(6)); // current translation on radiometry 2nd point of triangle - const tREAL8 aCurRadScPointB = aVCur(aVecInd.at(7)); // current scale on radiometry 3rd point of triangle - const tREAL8 aCurRadTrPointC = aVCur(aVecInd.at(10)); // current translation on radiometry 3rd point of triangle - const tREAL8 aCurRadScPointC = aVCur(aVecInd.at(11)); // current scale on radiometry 3rd point of triangle - - // soft constraint radiometric translation - if (!mFreezeRadTranslation) - { - if (mWeightRadTranslation >= 0) - { - const int aSolStep = 4; // adapt step to solution vector configuration - const int aSolStart = 2; - for (size_t aIndCurSol = aSolStart; aIndCurSol < aVecInd.size() - 1; aIndCurSol += aSolStep) - { - const int aIndices = aVecInd.at(aIndCurSol); - mSys->AddEqFixVar(aIndices, aVCur(aIndices), mWeightRadTranslation); - } - } - } - - // soft constraint radiometric scaling - if (!mFreezeRadScale) - { - if (mWeightRadScale >= 0) - { - const int aSolStep = 4; // adapt step to solution vector configuration - const int aSolStart = 3; - for (size_t aIndCurSol = aSolStart; aIndCurSol < aVecInd.size(); aIndCurSol += aSolStep) - { - const int aIndices = aVecInd.at(aIndCurSol); - mSys->AddEqFixVar(aIndices, aVCur(aIndices), mWeightRadScale); - } - } - } - - const size_t aNumberOfInsidePixels = aVectorToFillWithInsidePixels.size(); - - // Loop over all pixels inside triangle - // size_t is necessary as there can be a lot of pixels in triangles - for (size_t aFilledPixel = 0; aFilledPixel < aNumberOfInsidePixels; aFilledPixel++) - { - const cPtInsideTriangles aPixInsideTriangle = cPtInsideTriangles(aCompTri, aVectorToFillWithInsidePixels, - aFilledPixel, *aCurPreDIm); - // prepare for barycenter translation formula by filling aVObs with different coordinates - FormalInterpBarycenter_SetObs(aVObs, 0, aPixInsideTriangle); - - // image of a point in triangle by current translation - const cPt2dr aTranslatedFilledPoint = cAppli_cTriangleDeformation::ApplyBarycenterTranslationFormulaToFilledPixel(aCurTrPointA, aCurTrPointB, - aCurTrPointC, aVObs); - // radiometry translation of pixel by current radiometry translation of triangle knots - const tREAL8 aRadiometryTranslation = cAppli_cTriangleDeformation::ApplyBarycenterTranslationFormulaForTranslationRadiometry(aCurRadTrPointA, - aCurRadTrPointB, - aCurRadTrPointC, - aVObs); - // radiometry translation of pixel by current radiometry scaling of triangle knots - const tREAL8 aRadiometryScaling = cAppli_cTriangleDeformation::ApplyBarycenterTranslationFormulaForScalingRadiometry(aCurRadScPointA, - aCurRadScPointB, - aCurRadScPointC, - aVObs); - - if (aCurPostDIm->InsideBL(aTranslatedFilledPoint)) // avoid errors - { - // prepare for application of bilinear formula - FormalBilinTri_SetObs(aVObs, TriangleDisplacement_NbObs, aTranslatedFilledPoint, *aCurPostDIm); - - // Now add observation - mSys->CalcAndAddObs(mEqTriDeformTrRad, aVecInd, aVObs); - - // compute indicators - const tREAL8 aBilinearRadiomValue = aRadiometryScaling * aCurPostDIm->GetVBL(aTranslatedFilledPoint) + aRadiometryTranslation; - const tREAL8 aDif = aVObs[5] - aBilinearRadiomValue; // residual : aValueImPre - aBilinearRadiomValue - aSomDif += std::abs(aDif); - } - else - aNbOut++; // Count number of pixels translated outside post image - - aTotalNumberOfInsidePixels += aNumberOfInsidePixels; - } - } - - if (mUseMultiScaleApproach && !mIsLastIters && aIterNumber != 0) - { - const bool aGenerateIntermediateMaps = false; - if (aGenerateIntermediateMaps) - GenerateDisplacementMapsAndOutputImages(aVCur, aIterNumber); - } - - // Update all parameter taking into account previous observation - mSys->SolveUpdateReset(); - - if (mShow) - StdOut() << aIterNumber + 1 << ", " << aSomDif / aTotalNumberOfInsidePixels - << ", " << aNbOut << std::endl; - } - - void cAppli_cTriangleDeformationTrRad::FillDisplacementMapsAndOutputImage(const cPtInsideTriangles &aLastPixInsideTriangle, - const cPt2dr &aLastTranslatedFilledPoint, - const tREAL8 aLastRadiometryTranslation, - const tREAL8 aLastRadiometryScaling) - { - const tREAL8 aLastXCoordinate = aLastPixInsideTriangle.GetCartesianCoordinates().x(); - const tREAL8 aLastYCoordinate = aLastPixInsideTriangle.GetCartesianCoordinates().y(); - - const cPt2di aLastCoordinate = cPt2di(aLastXCoordinate, aLastYCoordinate); - mDImDepX->SetV(aLastCoordinate, - aLastTranslatedFilledPoint.x() - aLastXCoordinate); - mDImDepY->SetV(aLastCoordinate, - aLastTranslatedFilledPoint.y() - aLastYCoordinate); - const tREAL8 aLastXTranslatedCoord = aLastXCoordinate + mDImDepX->GetV(aLastCoordinate); - const tREAL8 aLastYTranslatedCoord = aLastYCoordinate + mDImDepY->GetV(aLastCoordinate); - - const tREAL8 aLastRadiometryValue = aLastRadiometryScaling * aLastPixInsideTriangle.GetPixelValue() + - aLastRadiometryTranslation; - - // Build image with intensities displaced - // deal with different cases of pixel being translated out of image - if (aLastXTranslatedCoord < 0 && aLastYTranslatedCoord < 0) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(0, 0))); - else if (aLastXTranslatedCoord >= mSzImOut.x() && aLastYTranslatedCoord >= mSzImOut.y()) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(mSzImOut.x() - 1, mSzImOut.y() - 1))); - else if (aLastXTranslatedCoord < 0 && aLastYTranslatedCoord >= mSzImOut.y()) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(0, mSzImOut.y() - 1))); - else if (aLastXTranslatedCoord >= mSzImOut.x() && aLastYTranslatedCoord < 0) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(mSzImOut.x() - 1, 0))); - else if (aLastXTranslatedCoord >= 0 && aLastXTranslatedCoord < mSzImOut.x() && - aLastYTranslatedCoord < 0) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(aLastXTranslatedCoord, 0))); - else if (aLastXTranslatedCoord >= 0 && aLastXTranslatedCoord < mSzImOut.x() && - aLastYTranslatedCoord > mSzImOut.y()) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(aLastXTranslatedCoord, mSzImOut.y() - 1))); - else if (aLastYTranslatedCoord >= 0 && aLastYTranslatedCoord < mSzImOut.y() && - aLastXTranslatedCoord < 0) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(0, aLastYTranslatedCoord))); - else if (aLastYTranslatedCoord >= 0 && aLastYTranslatedCoord < mSzImOut.y() && - aLastXTranslatedCoord > mSzImOut.x()) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(mSzImOut.x() - 1, aLastYTranslatedCoord))); - else - // at the translated pixel the untranslated pixel value is given computed with the right radiometry values - mDImOut->SetV(cPt2di(aLastXTranslatedCoord, aLastYTranslatedCoord), aLastRadiometryValue); - } - - void cAppli_cTriangleDeformationTrRad::GenerateDisplacementMapsAndOutputImages(const tDenseVect &aVFinalSol, const int aIterNumber) - { - mImOut = tIm(mSzImPre); - mDImOut = &mImOut.DIm(); - mSzImOut = cPt2di(mDImOut->Sz().x(), mDImOut->Sz().y()); - - mImDepX = tIm(mSzImPre, 0, eModeInitImage::eMIA_Null); - mDImDepX = &mImDepX.DIm(); - - mImDepY = tIm(mSzImPre, 0, eModeInitImage::eMIA_Null); - mDImDepY = &mImDepY.DIm(); - - tIm aLastPostIm = tIm(mSzImPost); - tDIm *aLastPostDIm = nullptr; - cAppli_cTriangleDeformation::LoadImageAndData(aLastPostIm, aLastPostDIm, "post", mImPre, mImPost); - - if (mUseMultiScaleApproach && !mIsLastIters) - { - aLastPostIm = mImPre.GaussFilter(mSigmaGaussFilter, mNumberOfIterGaussFilter); - aLastPostDIm = &aLastPostIm.DIm(); - } - - tDoubleVect aLastVObs(12, 0.0); - - for (const cPt2di &aOutPix : *mDImOut) // Initialise output image - mDImOut->SetV(aOutPix, aLastPostDIm->GetV(aOutPix)); - - for (size_t aLTr = 0; aLTr < mDelTri.NbFace(); aLTr++) - { - const tTri2dr aLastTri = mDelTri.KthTri(aLTr); - const cPt3di aLastIndicesOfTriKnots = mDelTri.KthFace(aLTr); - - const cTriangle2DCompiled aLastCompTri(aLastTri); - - std::vector aLastVectorToFillWithInsidePixels; - aLastCompTri.PixelsInside(aLastVectorToFillWithInsidePixels); - - const tIntVect aLastVecInd = { - 4 * aLastIndicesOfTriKnots.x(), - 4 * aLastIndicesOfTriKnots.x() + 1, - 4 * aLastIndicesOfTriKnots.x() + 2, - 4 * aLastIndicesOfTriKnots.x() + 3, - 4 * aLastIndicesOfTriKnots.y(), - 4 * aLastIndicesOfTriKnots.y() + 1, - 4 * aLastIndicesOfTriKnots.y() + 2, - 4 * aLastIndicesOfTriKnots.y() + 3, - 4 * aLastIndicesOfTriKnots.z(), - 4 * aLastIndicesOfTriKnots.z() + 1, - 4 * aLastIndicesOfTriKnots.z() + 2, - 4 * aLastIndicesOfTriKnots.z() + 3, - }; - - const cPt2dr aLastTrPointA = cPt2dr(aVFinalSol(aLastVecInd.at(0)), - aVFinalSol(aLastVecInd.at(1))); // last translation 1st point of triangle - const cPt2dr aLastTrPointB = cPt2dr(aVFinalSol(aLastVecInd.at(4)), - aVFinalSol(aLastVecInd.at(5))); // last translation 2nd point of triangle - const cPt2dr aLastTrPointC = cPt2dr(aVFinalSol(aLastVecInd.at(8)), - aVFinalSol(aLastVecInd.at(9))); // last translation 3rd point of triangle - - const tREAL8 aLastRadTrPointA = aVFinalSol(aLastVecInd.at(2)); // last translation on radiometry 1st point of triangle - const tREAL8 aLastRadScPointA = aVFinalSol(aLastVecInd.at(3)); // last scale on radiometry 3rd point of triangle - const tREAL8 aLastRadTrPointB = aVFinalSol(aLastVecInd.at(6)); // last translation on radiometry 2nd point of triangle - const tREAL8 aLastRadScPointB = aVFinalSol(aLastVecInd.at(7)); // last scale on radiometry 3rd point of triangle - const tREAL8 aLastRadTrPointC = aVFinalSol(aLastVecInd.at(10)); // last translation on radiometry 3rd point of triangle - const tREAL8 aLastRadScPointC = aVFinalSol(aLastVecInd.at(11)); // last scale on radiometry 3rd point of triangle - - const size_t aLastNumberOfInsidePixels = aLastVectorToFillWithInsidePixels.size(); - - for (size_t aLastFilledPixel = 0; aLastFilledPixel < aLastNumberOfInsidePixels; aLastFilledPixel++) - { - const cPtInsideTriangles aLastPixInsideTriangle = cPtInsideTriangles(aLastCompTri, aLastVectorToFillWithInsidePixels, - aLastFilledPixel, *aLastPostDIm); - // prepare for barycenter translation formula by filling aVObs with different coordinates - FormalInterpBarycenter_SetObs(aLastVObs, 0, aLastPixInsideTriangle); - - // image of a point in triangle by current translation - const cPt2dr aLastTranslatedFilledPoint = cAppli_cTriangleDeformation::ApplyBarycenterTranslationFormulaToFilledPixel(aLastTrPointA, aLastTrPointB, - aLastTrPointC, aLastVObs); - - const tREAL8 aLastRadiometryTranslation = cAppli_cTriangleDeformation::ApplyBarycenterTranslationFormulaForTranslationRadiometry(aLastRadTrPointA, - aLastRadTrPointB, - aLastRadTrPointC, - aLastVObs); - - const tREAL8 aLastRadiometryScaling = cAppli_cTriangleDeformation::ApplyBarycenterTranslationFormulaForScalingRadiometry(aLastRadScPointA, - aLastRadScPointB, - aLastRadScPointC, - aLastVObs); - - FillDisplacementMapsAndOutputImage(aLastPixInsideTriangle, aLastTranslatedFilledPoint, aLastRadiometryTranslation, - aLastRadiometryScaling); - } - } - - // save displacement maps in x and y to image files - if (mUseMultiScaleApproach) - { - mDImDepX->ToFile("DisplacedPixelsX_iter_" + std::to_string(aIterNumber) + "_" + - std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales + mNumberOfEndIterations) + ".tif"); - mDImDepY->ToFile("DisplacedPixelsY_iter_" + std::to_string(aIterNumber) + "_" + - std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales + mNumberOfEndIterations) + ".tif"); - if (aIterNumber == mNumberOfScales + mNumberOfEndIterations - 1) - mDImOut->ToFile("DisplacedPixels.tif"); - } - else - { - mDImDepX->ToFile("DisplacedPixelsX_" + std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales) + ".tif"); - mDImDepY->ToFile("DisplacedPixelsY_" + std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales) + ".tif"); - mDImOut->ToFile("DisplacedPixels.tif"); - } - } - - void cAppli_cTriangleDeformationTrRad::GenerateDisplacementMapsAndDisplayLastValuesUnknowns(const int aIterNumber, const bool aDisplayLastRadiometryValues, - const bool aDisplayLastTranslationValues) - { - tDenseVect aVFinalSol = mSys->CurGlobSol(); - - if (mGenerateDisplacementImage) - GenerateDisplacementMapsAndOutputImages(aVFinalSol, aIterNumber); - - if (aDisplayLastRadiometryValues || aDisplayLastTranslationValues) - cAppli_cTriangleDeformation::DisplayLastUnknownValues(aVFinalSol, aDisplayLastRadiometryValues, - aDisplayLastTranslationValues); - } - - void cAppli_cTriangleDeformationTrRad::DoOneIteration(const int aIterNumber) - { - LoopOverTrianglesAndUpdateParameters(aIterNumber); // Iterate over triangles and solve system - - // Show final translation results and produce displacement maps - if (mUseMultiScaleApproach) - { - if (aIterNumber == (mNumberOfScales + mNumberOfEndIterations - 1)) - GenerateDisplacementMapsAndDisplayLastValuesUnknowns(aIterNumber, mDisplayLastRadiometryValues, - mDisplayLastTranslationValues); - } - else - { - if (aIterNumber == (mNumberOfScales - 1)) - GenerateDisplacementMapsAndDisplayLastValuesUnknowns(aIterNumber, mDisplayLastRadiometryValues, - mDisplayLastTranslationValues); - } - } - - //----------------------------------------- - - int cAppli_cTriangleDeformationTrRad::Exe() - { - // read pre and post images and their sizes - mImPre = tIm::FromFile(mNamePreImage); - mImPost = tIm::FromFile(mNamePostImage); - - mDImPre = &mImPre.DIm(); - mSzImPre = mDImPre->Sz(); - - mDImPost = &mImPost.DIm(); - mSzImPost = mDImPost->Sz(); - - if (mUseMultiScaleApproach) - mSigmaGaussFilter = mNumberOfScales * mSigmaGaussFilterStep; - - if (mShow) - StdOut() << "Iter, " - << "Diff, " - << "NbOut" << std::endl; - - cAppli_cTriangleDeformation::GeneratePointsForDelaunay(mVectorPts, mNumberPointsToGenerate, mRandomUniformLawUpperBoundLines, - mRandomUniformLawUpperBoundCols, mDelTri, mSzImPre); - - cAppli_cTriangleDeformation::InitialisationAfterExe(mDelTri, mSys); - - if (mUseMultiScaleApproach) - { - for (int aIterNumber = 0; aIterNumber < mNumberOfScales + mNumberOfEndIterations; aIterNumber++) - DoOneIteration(aIterNumber); - } - else - { - for (int aIterNumber = 0; aIterNumber < mNumberOfScales; aIterNumber++) - DoOneIteration(aIterNumber); - } - - return EXIT_SUCCESS; - } - - /********************************************/ - // ::MMVII // - /********************************************/ - - tMMVII_UnikPApli Alloc_cTriangleDeformationTrRad(const std::vector &aVArgs, - const cSpecMMVII_Appli &aSpec) - { - return tMMVII_UnikPApli(new cAppli_cTriangleDeformationTrRad(aVArgs, aSpec)); - } - - cSpecMMVII_Appli TheSpec_ComputeTriangleDeformationTrRad( - "ComputeTriangleDeformationTrRad", - Alloc_cTriangleDeformationTrRad, - "Compute 2D deformation of triangles between images using triangles and alternative formula", - {eApF::ImProc}, // category - {eApDT::Image}, // input - {eApDT::Image}, // output - __FILE__); - -}; // namespace MMVII \ No newline at end of file diff --git a/MMVII/src/MeshDisplacement/TriangleDeformationTrRad.h b/MMVII/src/MeshDisplacement/TriangleDeformationTrRad.h deleted file mode 100644 index 5af78c8007..0000000000 --- a/MMVII/src/MeshDisplacement/TriangleDeformationTrRad.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef _TRIANGLEDEFORMATIONTRAD_H_ -#define _TRIANGLEDEFORMATIONTRAD_H_ - -#include "MMVII_Geom2D.h" -#include "MMVII_PhgrDist.h" -#include "TriangleDeformation.h" - -using namespace NS_SymbolicDerivative; - -namespace MMVII -{ - - /******************************************/ - /* */ - /* cTriangleDeformation */ - /* */ - /******************************************/ - - class cAppli_cTriangleDeformationTrRad : public cAppli_cTriangleDeformation - { - public: - typedef cIm2D tIm; - typedef cDataIm2D tDIm; - typedef cTriangle tTri2dr; - typedef cDenseVect tDenseVect; - typedef std::vector tIntVect; - typedef std::vector tDoubleVect; - - cAppli_cTriangleDeformationTrRad(const std::vector &aVArgs, - const cSpecMMVII_Appli &aSpec); - ~cAppli_cTriangleDeformationTrRad(); - - int Exe() override; - cCollecSpecArg2007 &ArgObl(cCollecSpecArg2007 &anArgObl) override; - cCollecSpecArg2007 &ArgOpt(cCollecSpecArg2007 &anArgOpt) override; - - // Iterate of triangles and inside pixels - virtual void DoOneIteration(const int aIterNumber); - // Loops over all triangles and solves system to update parameters at end of iteration - virtual void LoopOverTrianglesAndUpdateParameters(const int aIterNumber); - // Generate displacement maps of last solution - virtual void GenerateDisplacementMapsAndOutputImages(const tDenseVect &aVFinalSol, const int aIterNumber); - // Generates Displacement maps and coordinates of points in triangulation at last iteration - virtual void GenerateDisplacementMapsAndDisplayLastValuesUnknowns(const int aIterNumber, const bool aDisplayLastRadiometryValues, - const bool aDisplayLastTranslationValues); - // Fill displacement maps and output image - virtual void FillDisplacementMapsAndOutputImage(const cPtInsideTriangles &aLastPixInsideTriangle, - const cPt2dr &aLastTranslatedFilledPoint, - const tREAL8 aLastRadiometryTranslation, - const tREAL8 aLastRadiometryScaling); - - private: - // == Mandatory args ==== - - std::string mNamePreImage; // Name of given pre-image - std::string mNamePostImage; // Name of given post-image - int mNumberPointsToGenerate; // number of generated points - int mNumberOfScales; // number of iterations in optimisation process - - // == Optionnal args ==== - - int mRandomUniformLawUpperBoundLines; // Uniform law generates random coordinates in interval [0, mRandomUniformLawUpperBoundLines [ - int mRandomUniformLawUpperBoundCols; // Uniform law generates random coordinates in interval [0, mRandomUniformLawUpperBoundCols [ - bool mShow; // Print result, export image ... - bool mComputeAvgMax; // Compute average and maximum pixel value of difference image between pre and post images - bool mUseMultiScaleApproach; // Apply multi-scale approach or not - int mSigmaGaussFilterStep; // Decreasing step of sigma value during iterations - bool mGenerateDisplacementImage; // Generate image with displaced pixels - bool mFreezeTranslationX; // Freeze x-translation or not during optimisation - bool mFreezeTranslationY; // Freeze y-translation or not during optimisation - bool mFreezeRadTranslation; // Freeze radiometry translation in computation - bool mFreezeRadScale; // Freeze radiometry scaling in computation - double mWeightRadTranslation; // Weight given to radiometry translation if soft freezing is applied (default : negative => not applied) - double mWeightRadScale; // Weight given to radiometry scaling if soft freezing is applied (default : negative => not applied) - int mNumberOfIterGaussFilter; // Number of iterations to be done in Gauss filter algorithm - int mNumberOfEndIterations; // Number of iterations to do while using original image in multi-scale approach - bool mDisplayLastTranslationValues; // Whether to display the final coordinates of the translated points - bool mDisplayLastRadiometryValues; // Display final values of radiometry unknowns at last iteration of optimisation process - - // == Internal variables ==== - - cPt2di mSzImPre; // size of image - tIm mImPre; // memory representation of the image - tDIm *mDImPre; // memory representation of the image - - cPt2di mSzImPost; // size of image - tIm mImPost; // memory representation of the image - tDIm *mDImPost; // memory representation of the image - - cPt2di mSzImOut; // size of image - tIm mImOut; // memory representation of the image - tDIm *mDImOut; // memory representation of the image - - cPt2di mSzImDepX; // size of image - tIm mImDepX; // memory representation of the image - tDIm *mDImDepX; // memory representation of the image - - cPt2di mSzImDepY; // size of image - tIm mImDepY; // memory representation of the image - tDIm *mDImDepY; // memory representation of the image - - std::vector mVectorPts; // A vector containing a set of points - cTriangulation2D mDelTri; // A Delaunay triangle - - double mSigmaGaussFilter; // Value of sigma in gauss filter - bool mIsLastIters; // Determines whether optimisation process is at last iters to optimise on original image - - cResolSysNonLinear *mSys; // Non Linear Sys for solving problem - cCalculator *mEqTriDeformTrRad; // calculator giving access to values and derivatives - }; -} - -#endif // _TRIANGLEDEFORMATIONTRAD_H_ diff --git a/MMVII/src/MeshDisplacement/TriangleDeformationTranslation.cpp b/MMVII/src/MeshDisplacement/TriangleDeformationTranslation.cpp index c3da45f140..60fab89d97 100644 --- a/MMVII/src/MeshDisplacement/TriangleDeformationTranslation.cpp +++ b/MMVII/src/MeshDisplacement/TriangleDeformationTranslation.cpp @@ -1,7 +1,3 @@ -#include "cMMVII_Appli.h" - -#include "MMVII_TplSymbTriangle.h" - #include "TriangleDeformationTranslation.h" /** @@ -13,97 +9,143 @@ namespace MMVII { - - /******************************************/ - /* */ - /* cTriangleDeformationTranslation */ - /* */ - /******************************************/ - - cAppli_cTriangleDeformationTranslation::cAppli_cTriangleDeformationTranslation(const std::vector &aVArgs, - const cSpecMMVII_Appli &aSpec) : cAppli_cTriangleDeformation(aVArgs, aSpec), - mRandomUniformLawUpperBoundLines(1), - mRandomUniformLawUpperBoundCols(1), - mShow(true), - mUseMultiScaleApproach(true), - mSigmaGaussFilterStep(1), - mGenerateDisplacementImage(true), - mNumberOfIterGaussFilter(3), - mNumberOfEndIterations(2), - mDisplayLastTranslatedPointsCoordinates(false), - mSzImPre(cPt2di(1, 1)), - mImPre(mSzImPre), - mDImPre(nullptr), - mSzImPost(cPt2di(1, 1)), - mImPost(mSzImPost), - mDImPost(nullptr), - mSzImOut(cPt2di(1, 1)), - mImOut(mSzImOut), - mDImOut(nullptr), - mSzImDepX(cPt2di(1, 1)), - mImDepX(mSzImDepX), - mDImDepX(nullptr), - mSzImDepY(cPt2di(1, 1)), - mImDepY(mSzImDepY), - mDImDepY(nullptr), - mVectorPts({cPt2dr(0, 0)}), - mDelTri(mVectorPts), - mSys(nullptr), - mEqTranslationTri(nullptr) + /************************************************/ + /* */ + /* cAppli_TriangleDeformationTranslation */ + /* */ + /************************************************/ + + cAppli_TriangleDeformationTranslation::cAppli_TriangleDeformationTranslation(const std::vector &aVArgs, + const cSpecMMVII_Appli &aSpec) : cAppli_TriangleDeformation(aVArgs, aSpec), + mNumberOfLines(1), + mNumberOfCols(1), + mShow(true), + mUseMultiScaleApproach(false), + mBuildRandomUniformGrid(false), + mInitialiseTranslationWithPreviousExecution(false), + mInitialiseWithUserValues(true), + mInitialiseXTranslationValue(0), + mInitialiseYTranslationValue(0), + mInitialiseWithMMVI(false), + mNameInitialDepX("InitialDispXMap.tif"), + mNameInitialDepY("InitialDispYMap.tif"), + mNameIntermediateDepX("IntermediateDispXMap.tif"), + mNameIntermediateDepY("IntermediateDispYMap.tif"), + mNameCorrelationMaskMMVI("CorrelationMask.tif"), + mIsFirstExecution(false), + mSigmaGaussFilterStep(1), + mGenerateDisplacementImage(true), + mFreezeTranslationX(false), + mFreezeTranslationY(false), + mWeightTranslationX(-1), + mWeightTranslationY(-1), + mNumberOfIterGaussFilter(3), + mNumberOfEndIterations(2), + mDisplayLastTranslationValues(false), + mSzImPre(tPt2di(1, 1)), + mImPre(mSzImPre), + mDImPre(nullptr), + mSzImPost(tPt2di(1, 1)), + mImPost(mSzImPost), + mDImPost(nullptr), + mSzImOut(tPt2di(1, 1)), + mImOut(mSzImOut), + mDImOut(nullptr), + mSzImDepX(tPt2di(1, 1)), + mImDepX(mSzImDepX), + mDImDepX(nullptr), + mSzImDepY(tPt2di(1, 1)), + mImDepY(mSzImDepY), + mDImDepY(nullptr), + mSzImIntermediateDepX(tPt2di(1, 1)), + mImIntermediateDepX(mSzImIntermediateDepX), + mDImIntermediateDepX(nullptr), + mSzImIntermediateDepY(tPt2di(1, 1)), + mImIntermediateDepY(mSzImIntermediateDepY), + mDImIntermediateDepY(nullptr), + mSzCorrelationMask(tPt2di(1, 1)), + mImCorrelationMask(mSzImIntermediateDepY), + mDImCorrelationMask(nullptr), + mDelTri({tPt2dr(0, 0)}), + mSysTranslation(nullptr), + mEqTranslationTri(nullptr) { mEqTranslationTri = EqDeformTriTranslation(true, 1); // true means with derivative, 1 is size of buffer - // mEqTranslationTri->SetDebugEnabled(true); } - cAppli_cTriangleDeformationTranslation::~cAppli_cTriangleDeformationTranslation() + cAppli_TriangleDeformationTranslation::~cAppli_TriangleDeformationTranslation() { - delete mSys; + delete mSysTranslation; delete mEqTranslationTri; } - cCollecSpecArg2007 &cAppli_cTriangleDeformationTranslation::ArgObl(cCollecSpecArg2007 &anArgObl) + cCollecSpecArg2007 &cAppli_TriangleDeformationTranslation::ArgObl(cCollecSpecArg2007 &anArgObl) { return anArgObl - << Arg2007(mNamePreImage, "Name of pre-image file.", {{eTA2007::FileImage}, {eTA2007::FileDirProj}}) + << Arg2007(mNamePreImage, "Name of pre-image file.", {eTA2007::FileImage, eTA2007::FileDirProj}) << Arg2007(mNamePostImage, "Name of post-image file.", {eTA2007::FileImage}) << Arg2007(mNumberPointsToGenerate, "Number of points you want to generate for triangulation.") << Arg2007(mNumberOfScales, "Total number of scales to run in multi-scale approach optimisation process."); } - cCollecSpecArg2007 &cAppli_cTriangleDeformationTranslation::ArgOpt(cCollecSpecArg2007 &anArgOpt) + cCollecSpecArg2007 &cAppli_TriangleDeformationTranslation::ArgOpt(cCollecSpecArg2007 &anArgOpt) { return anArgOpt - << AOpt2007(mRandomUniformLawUpperBoundCols, "RandomUniformLawUpperBoundXAxis", - "Maximum value that the uniform law can draw from on the x-axis.", {eTA2007::HDV}) - << AOpt2007(mRandomUniformLawUpperBoundLines, "RandomUniformLawUpperBoundYAxis", - "Maximum value that the uniform law can draw from for on the y-axis.", {eTA2007::HDV}) - << AOpt2007(mShow, "Show", "Whether to print minimisation results.", {eTA2007::HDV}) + << AOpt2007(mNumberOfCols, "MaximumValueNumberOfCols", + "Maximum value that the uniform law can draw from on the x-axis.", {eTA2007::HDV, eTA2007::Tuning}) + << AOpt2007(mNumberOfLines, "MaximumValueNumberOfLines", + "Maximum value that the uniform law can draw from for on the y-axis.", {eTA2007::HDV, eTA2007::Tuning}) + << AOpt2007(mShow, "Show", "Whether to print minimisation results.", {eTA2007::HDV, eTA2007::Tuning}) << AOpt2007(mUseMultiScaleApproach, "UseMultiScaleApproach", "Whether to use multi-scale approach or not.", {eTA2007::HDV}) - << AOpt2007(mSigmaGaussFilterStep, "SigmaGaussFilterStep", "Sigma value to use for Gauss filter in multi-stage approach.", {eTA2007::HDV}) + << AOpt2007(mBuildRandomUniformGrid, "GenerateRandomUniformGrid", + "Whether to build a grid to be triangulated thanks to points generated randomly with a uniform law or build a grid made of rectangles.", {eTA2007::HDV}) + << AOpt2007(mInitialiseTranslationWithPreviousExecution, "InitialiseTranslationWithPreviousExecution", + "Whether to initialise or not with unknown values obtained at previous algorithm execution.", {eTA2007::HDV}) + << AOpt2007(mInitialiseWithUserValues, "InitialiseWithUserValues", + "Whether the user wishes or not to initialise unknowns with personalised values.", {eTA2007::HDV}) + << AOpt2007(mInitialiseXTranslationValue, "InitialXTranslationValue", + "Value to use for initialising x-translation unknowns.", {eTA2007::HDV}) + << AOpt2007(mInitialiseYTranslationValue, "InitialYTranslationValue", + "Value to use for initialising y-translation unknowns.", {eTA2007::HDV}) + << AOpt2007(mInitialiseWithMMVI, "InitialiseWithMMVI", + "Whether to initialise or not values of unknowns with pre-computed values from MicMacV1 at first execution.", {eTA2007::HDV}) + << AOpt2007(mNameInitialDepX, "NameOfInitialDispXMap", "Name of file of initial X-displacement map.", {eTA2007::HDV, eTA2007::FileImage}) + << AOpt2007(mNameInitialDepY, "NameOfInitialDispYMap", "Name of file of initial Y-displacement map.", {eTA2007::HDV, eTA2007::FileImage}) + << AOpt2007(mNameIntermediateDepX, "NameForIntermediateDispXMap", + "File name to use when saving intermediate x-displacement maps between executions.", {eTA2007::HDV, eTA2007::FileImage, eTA2007::Tuning}) + << AOpt2007(mNameIntermediateDepY, "NameForIntermediateDisYpMap", + "File name to use when saving intermediate y-displacement maps between executions.", {eTA2007::HDV, eTA2007::FileImage, eTA2007::Tuning}) + << AOpt2007(mNameCorrelationMaskMMVI, "NameOfCorrelationMask", + "File name of mask file from MMVI giving locations where correlation is computed.", {eTA2007::HDV, eTA2007::FileImage}) + << AOpt2007(mIsFirstExecution, "IsFirstExecution", + "Whether this is the first execution of optimisation algorithm or not", {eTA2007::HDV}) + << AOpt2007(mSigmaGaussFilterStep, "SigmaGaussFilterStep", "Sigma value to use for Gauss filter in multi-stage approach.", {eTA2007::HDV, eTA2007::Tuning}) << AOpt2007(mGenerateDisplacementImage, "GenerateDisplacementImage", "Whether to generate and save an image having been translated.", {eTA2007::HDV}) - << AOpt2007(mDisplayLastTranslatedPointsCoordinates, "DisplayLastTranslatedCoordinates", + << AOpt2007(mFreezeTranslationX, "FreezeXTranslation", + "Whether to freeze or not x-translation to certain value during computation.", {eTA2007::HDV}) + << AOpt2007(mFreezeTranslationY, "FreezeYTranslation", + "Whether to freeze or not y-translation to certain value during computation.", {eTA2007::HDV}) + << AOpt2007(mWeightTranslationX, "WeightTranslationX", + "A value to weight x-translation for soft freezing of coefficient.", {eTA2007::HDV}) + << AOpt2007(mWeightTranslationY, "WeightTranslationY", + "A value to weight y-translation for soft freezing of coefficient.", {eTA2007::HDV}) + << AOpt2007(mDisplayLastTranslationValues, "DisplayLastTranslationValues", "Whether to display the final coordinates of the trainslated points.", {eTA2007::HDV}) << AOpt2007(mNumberOfIterGaussFilter, "NumberOfIterationsGaussFilter", - "Number of iterations to run in Gauss filter algorithm.", {eTA2007::HDV}) + "Number of iterations to run in Gauss filter algorithm.", {eTA2007::HDV, eTA2007::Tuning}) << AOpt2007(mNumberOfEndIterations, "NumberOfEndIterations", - "Number of iterations to run on original images in multi-scale approach.", {eTA2007::HDV}); - } - - void cAppli_cTriangleDeformationTranslation::InitialisationAfterExeTranslation() - { - tDenseVect aVInit(2 * mDelTri.NbPts(), eModeInitImage::eMIA_Null); - - mSys = new cResolSysNonLinear(eModeSSR::eSSR_LsqDense, aVInit); + "Number of iterations to run on original images in multi-scale approach.", {eTA2007::HDV, eTA2007::Tuning}); } - void cAppli_cTriangleDeformationTranslation::LoopOverTrianglesAndUpdateParametersTranslation(const int aIterNumber) + void cAppli_TriangleDeformationTranslation::LoopOverTrianglesAndUpdateParametersTranslation(const int aIterNumber, + const int aTotalNumberOfIterations) { //----------- allocate vec of obs : - tDoubleVect aVObs(12, 0.0); // 6 for ImagePre and 6 for ImagePost + tDoubleVect aVObsTr(12, 0.0); // 6 for ImagePre and 6 for ImagePost //----------- extract current parameters - tDenseVect aVCur = mSys->CurGlobSol(); // Get current solution. + tDenseVect aVCurSolTr = mSysTranslation->CurGlobSol(); // Get current solution. tIm aCurPreIm = tIm(mSzImPre); tDIm *aCurPreDIm = nullptr; @@ -113,13 +155,13 @@ namespace MMVII mIsLastIters = false; if (mUseMultiScaleApproach) - mIsLastIters = cAppli_cTriangleDeformation::ManageDifferentCasesOfEndIterations(aIterNumber, mNumberOfScales, mNumberOfEndIterations, - mIsLastIters, mImPre, mImPost, aCurPreIm, aCurPreDIm, - aCurPostIm, aCurPostDIm); + mIsLastIters = ManageDifferentCasesOfEndIterations(aIterNumber, mNumberOfScales, mNumberOfEndIterations, + mIsLastIters, mImPre, mImPost, aCurPreIm, aCurPreDIm, + aCurPostIm, aCurPostDIm); else { - cAppli_cTriangleDeformation::LoadImageAndData(aCurPreIm, aCurPreDIm, "pre", mImPre, mImPost); - cAppli_cTriangleDeformation::LoadImageAndData(aCurPostIm, aCurPostDIm, "post", mImPre, mImPost); + LoadPrePostImageAndData(aCurPreIm, aCurPreDIm, "pre", mImPre, mImPost); + LoadPrePostImageAndData(aCurPostIm, aCurPostDIm, "post", mImPre, mImPost); } if (mUseMultiScaleApproach && !mIsLastIters) @@ -134,12 +176,7 @@ namespace MMVII const bool aSaveGaussImage = false; if (aSaveGaussImage) - aCurPreDIm->ToFile("GaussFilteredImPre_iter_" + std::to_string(aIterNumber) + ".tif"); - } - else if (mUseMultiScaleApproach && mIsLastIters) - { - cAppli_cTriangleDeformation::LoadImageAndData(aCurPreIm, aCurPreDIm, "pre", mImPre, mImPost); - cAppli_cTriangleDeformation::LoadImageAndData(aCurPostIm, aCurPostDIm, "post", mImPre, mImPost); + aCurPreDIm->ToFile("GaussFilteredImPre_iter_" + ToStr(aIterNumber) + ".tif"); } //----------- declaration of indicator of convergence @@ -149,28 +186,84 @@ namespace MMVII // Count number of pixels inside triangles for normalisation size_t aTotalNumberOfInsidePixels = 0; + if (mFreezeTranslationX || mFreezeTranslationY) + { + for (size_t aTr = 0; aTr < mDelTri.NbFace(); aTr++) + { + const tPt3di aIndicesOfTriKnotsTr = mDelTri.KthFace(aTr); + + const tIntVect aVecIndTr = {2 * aIndicesOfTriKnotsTr.x(), 2 * aIndicesOfTriKnotsTr.x() + 1, + 2 * aIndicesOfTriKnotsTr.y(), 2 * aIndicesOfTriKnotsTr.y() + 1, + 2 * aIndicesOfTriKnotsTr.z(), 2 * aIndicesOfTriKnotsTr.z() + 1}; + + if (mFreezeTranslationX) + { + mSysTranslation->SetFrozenVar(aVecIndTr.at(0), aVCurSolTr(aVecIndTr.at(0))); + mSysTranslation->SetFrozenVar(aVecIndTr.at(2), aVCurSolTr(aVecIndTr.at(2))); + mSysTranslation->SetFrozenVar(aVecIndTr.at(4), aVCurSolTr(aVecIndTr.at(4))); + } + if (mFreezeTranslationY) + { + mSysTranslation->SetFrozenVar(aVecIndTr.at(1), aVCurSolTr(aVecIndTr.at(1))); + mSysTranslation->SetFrozenVar(aVecIndTr.at(3), aVCurSolTr(aVecIndTr.at(3))); + mSysTranslation->SetFrozenVar(aVecIndTr.at(5), aVCurSolTr(aVecIndTr.at(5))); + } + } + } + // Loop over all triangles to add the observations on each point for (size_t aTr = 0; aTr < mDelTri.NbFace(); aTr++) { - const tTri2dr aTri = mDelTri.KthTri(aTr); - const cPt3di aIndicesOfTriKnots = mDelTri.KthFace(aTr); + const tTri2dr aTriTr = mDelTri.KthTri(aTr); + const tPt3di aIndicesOfTriKnotsTr = mDelTri.KthFace(aTr); - const cTriangle2DCompiled aCompTri(aTri); + const cTriangle2DCompiled aCompTri(aTriTr); - std::vector aVectorToFillWithInsidePixels; + std::vector aVectorToFillWithInsidePixels; aCompTri.PixelsInside(aVectorToFillWithInsidePixels); // get pixels inside triangle //----------- index of unknown, finds the associated pixels of current triangle - const tIntVect aVecInd = {2 * aIndicesOfTriKnots.x(), 2 * aIndicesOfTriKnots.x() + 1, - 2 * aIndicesOfTriKnots.y(), 2 * aIndicesOfTriKnots.y() + 1, - 2 * aIndicesOfTriKnots.z(), 2 * aIndicesOfTriKnots.z() + 1}; + const tIntVect aVecIndTr = {2 * aIndicesOfTriKnotsTr.x(), 2 * aIndicesOfTriKnotsTr.x() + 1, + 2 * aIndicesOfTriKnotsTr.y(), 2 * aIndicesOfTriKnotsTr.y() + 1, + 2 * aIndicesOfTriKnotsTr.z(), 2 * aIndicesOfTriKnotsTr.z() + 1}; + + const cNodeOfTriangles aFirstPointOfTriTr = cNodeOfTriangles(aVCurSolTr, aVecIndTr, 0, 1, 0, 1, aTriTr, 0); + const cNodeOfTriangles aSecondPointOfTriTr = cNodeOfTriangles(aVCurSolTr, aVecIndTr, 2, 3, 2, 3, aTriTr, 1); + const cNodeOfTriangles aThirdPointOfTriTr = cNodeOfTriangles(aVCurSolTr, aVecIndTr, 4, 5, 4, 5, aTriTr, 2); + + const tPt2dr aCurTrPointA = aFirstPointOfTriTr.GetCurrentXYDisplacementValues(); // current translation 1st point of triangle + const tPt2dr aCurTrPointB = aSecondPointOfTriTr.GetCurrentXYDisplacementValues(); // current translation 2nd point of triangle + const tPt2dr aCurTrPointC = aThirdPointOfTriTr.GetCurrentXYDisplacementValues(); // current translation 3rd point of triangle + + // soft constraint x-translation + if (!mFreezeTranslationX) + { + if (mWeightTranslationX >= 0) + { + const int aSolStart = 0; + const int aSolStep = 2; // adapt step to solution vector configuration + for (size_t aIndCurSol = aSolStart; aIndCurSol < aVecIndTr.size() - 1; aIndCurSol += aSolStep) + { + const int aIndices = aVecIndTr.at(aIndCurSol); + mSysTranslation->AddEqFixCurVar(aIndices, mWeightTranslationX); + } + } + } - const cPt2dr aCurTrPointA = cPt2dr(aVCur(aVecInd.at(0)), - aVCur(aVecInd.at(1))); // current translation 1st point of triangle - const cPt2dr aCurTrPointB = cPt2dr(aVCur(aVecInd.at(2)), - aVCur(aVecInd.at(3))); // current translation 2nd point of triangle - const cPt2dr aCurTrPointC = cPt2dr(aVCur(aVecInd.at(4)), - aVCur(aVecInd.at(5))); // current translation 3rd point of triangle + // soft constraint y-translation + if (!mFreezeTranslationY) + { + if (mWeightTranslationY >= 0) + { + const int aSolStart = 1; + const int aSolStep = 2; // adapt step to solution vector configuration + for (size_t aIndCurSol = aSolStart; aIndCurSol < aVecIndTr.size(); aIndCurSol += aSolStep) + { + const int aIndices = aVecIndTr.at(aIndCurSol); + mSysTranslation->AddEqFixCurVar(aIndices, mWeightTranslationY); + } + } + } const size_t aNumberOfInsidePixels = aVectorToFillWithInsidePixels.size(); @@ -179,24 +272,24 @@ namespace MMVII for (size_t aFilledPixel = 0; aFilledPixel < aNumberOfInsidePixels; aFilledPixel++) { const cPtInsideTriangles aPixInsideTriangle = cPtInsideTriangles(aCompTri, aVectorToFillWithInsidePixels, - aFilledPixel, *aCurPreDIm); - // prepare for barycenter translation formula by filling aVObs with different coordinates - FormalInterpBarycenter_SetObs(aVObs, 0, aPixInsideTriangle); + aFilledPixel, aCurPreDIm); + // prepare for barycenter translation formula by filling aVObsTr with different coordinates + FormalInterpBarycenter_SetObs(aVObsTr, 0, aPixInsideTriangle); // image of a point in triangle by current translation - const cPt2dr aTranslatedFilledPoint = cAppli_cTriangleDeformation::ApplyBarycenterTranslationFormulaToFilledPixel(aCurTrPointA, aCurTrPointB, - aCurTrPointC, aVObs); + const tPt2dr aTranslatedFilledPoint = ApplyBarycenterTranslationFormulaToFilledPixel(aCurTrPointA, aCurTrPointB, + aCurTrPointC, aVObsTr); if (aCurPostDIm->InsideBL(aTranslatedFilledPoint)) // avoid errors { // prepare for application of bilinear formula - FormalBilinTri_SetObs(aVObs, TriangleDisplacement_NbObs, aTranslatedFilledPoint, *aCurPostDIm); + FormalBilinTri_SetObs(aVObsTr, TriangleDisplacement_NbObs, aTranslatedFilledPoint, *aCurPostDIm); // Now add observation - mSys->CalcAndAddObs(mEqTranslationTri, aVecInd, aVObs); + mSysTranslation->CalcAndAddObs(mEqTranslationTri, aVecIndTr, aVObsTr); // compute indicators - const tREAL8 aDif = aVObs[5] - aCurPostDIm->GetVBL(aTranslatedFilledPoint); // residual - aValueImPre - aCurPostDIm->GetVBL(aTranslatedFilledPoint) + const tREAL8 aDif = aVObsTr[5] - aCurPostDIm->GetVBL(aTranslatedFilledPoint); // residual - aValueImPre - aCurPostDIm->GetVBL(aTranslatedFilledPoint) aSomDif += std::abs(aDif); } else @@ -210,93 +303,31 @@ namespace MMVII { const bool aGenerateIntermediateMaps = false; if (aGenerateIntermediateMaps) - GenerateDisplacementMaps(aVCur, aIterNumber); + GenerateDisplacementMaps(aVCurSolTr, aIterNumber, aTotalNumberOfIterations); } // Update all parameter taking into account previous observation - mSys->SolveUpdateReset(); + mSysTranslation->SolveUpdateReset(); if (mShow) StdOut() << aIterNumber + 1 << ", " << aSomDif / aTotalNumberOfInsidePixels << ", " << aNbOut << std::endl; } - cPt2dr cAppli_cTriangleDeformationTranslation::ApplyLastBarycenterTranslationFormulaToInsidePixel(const cPt2dr &aLastTranslationPointA, - const cPt2dr &aLastTranslationPointB, - const cPt2dr &aLastTranslationPointC, - const cPtInsideTriangles &aLastPixInsideTriangle) - { - const cPt2dr aLastCartesianCoordinates = aLastPixInsideTriangle.GetCartesianCoordinates(); - const cPt3dr aLastBarycenterCoordinates = aLastPixInsideTriangle.GetBarycenterCoordinates(); - // apply current barycenter translation formula for x and y on current observations. - const tREAL8 aLastXTriCoord = aLastCartesianCoordinates.x() + aLastBarycenterCoordinates.x() * aLastTranslationPointA.x() + - aLastBarycenterCoordinates.y() * aLastTranslationPointB.x() + aLastBarycenterCoordinates.z() * aLastTranslationPointC.x(); - const tREAL8 aLastYTriCoord = aLastCartesianCoordinates.y() + aLastBarycenterCoordinates.x() * aLastTranslationPointA.y() + - aLastBarycenterCoordinates.y() * aLastTranslationPointB.y() + aLastBarycenterCoordinates.z() * aLastTranslationPointC.y(); - - const cPt2dr aLastTranslatedPixel = cPt2dr(aLastXTriCoord, aLastYTriCoord); - - return aLastTranslatedPixel; - } - - void cAppli_cTriangleDeformationTranslation::FillDisplacementMaps(const cPtInsideTriangles &aLastPixInsideTriangle, - const cPt2dr &aLastTranslatedFilledPoint) - { - const tREAL8 aLastXCoordinate = aLastPixInsideTriangle.GetCartesianCoordinates().x(); - const tREAL8 aLastYCoordinate = aLastPixInsideTriangle.GetCartesianCoordinates().y(); - const tREAL8 aLastPixelValue = aLastPixInsideTriangle.GetPixelValue(); - - const cPt2di aLastCoordinate = cPt2di(aLastXCoordinate, aLastYCoordinate); - - mDImDepX->SetV(aLastCoordinate, - aLastTranslatedFilledPoint.x() - aLastXCoordinate); - mDImDepY->SetV(aLastCoordinate, - aLastTranslatedFilledPoint.y() - aLastYCoordinate); - const tREAL8 aLastXTranslatedCoord = aLastXCoordinate + mDImDepX->GetV(aLastCoordinate); - const tREAL8 aLastYTranslatedCoord = aLastYCoordinate + mDImDepY->GetV(aLastCoordinate); - - // Build image with intensities displaced - // deal with different cases of pixel being translated out of image - if (aLastXTranslatedCoord < 0 && aLastYTranslatedCoord < 0) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(0, 0))); - else if (aLastXTranslatedCoord >= mSzImOut.x() && aLastYTranslatedCoord >= mSzImOut.y()) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(mSzImOut.x() - 1, mSzImOut.y() - 1))); - else if (aLastXTranslatedCoord < 0 && aLastYTranslatedCoord >= mSzImOut.y()) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(0, mSzImOut.y() - 1))); - else if (aLastXTranslatedCoord >= mSzImOut.x() && aLastYTranslatedCoord < 0) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(mSzImOut.x() - 1, 0))); - else if (aLastXTranslatedCoord >= 0 && aLastXTranslatedCoord < mSzImOut.x() && - aLastYTranslatedCoord < 0) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(aLastXTranslatedCoord, 0))); - else if (aLastXTranslatedCoord >= 0 && aLastXTranslatedCoord < mSzImOut.x() && - aLastYTranslatedCoord > mSzImOut.y()) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(aLastXTranslatedCoord, mSzImOut.y() - 1))); - else if (aLastYTranslatedCoord >= 0 && aLastYTranslatedCoord < mSzImOut.y() && - aLastXTranslatedCoord < 0) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(0, aLastYTranslatedCoord))); - else if (aLastYTranslatedCoord >= 0 && aLastYTranslatedCoord < mSzImOut.y() && - aLastXTranslatedCoord > mSzImOut.x()) - mDImOut->SetV(aLastCoordinate, mDImOut->GetV(cPt2di(mSzImOut.x() - 1, aLastYTranslatedCoord))); - else - // at the translated pixel the untranslated pixel value is given - mDImOut->SetV(cPt2di(aLastXTranslatedCoord, aLastYTranslatedCoord), aLastPixelValue); - } - - void cAppli_cTriangleDeformationTranslation::GenerateDisplacementMaps(const tDenseVect &aVFinalSol, const int aIterNumber) + void cAppli_TriangleDeformationTranslation::GenerateDisplacementMaps(const tDenseVect &aVFinalSol, const int aIterNumber, + const int aTotalNumberOfIterations) { + // Initialise output image, x and y displacement maps mImOut = tIm(mSzImPre); mDImOut = &mImOut.DIm(); - mSzImOut = cPt2di(mDImOut->Sz().x(), mDImOut->Sz().y()); + mSzImOut = mDImOut->Sz(); - mImDepX = tIm(mSzImPre, 0, eModeInitImage::eMIA_Null); - mDImDepX = &mImDepX.DIm(); - - mImDepY = tIm(mSzImPre, 0, eModeInitImage::eMIA_Null); - mDImDepY = &mImDepY.DIm(); + InitialiseDisplacementMaps(mSzImPre, mImDepX, mDImDepX, mSzImDepX); + InitialiseDisplacementMaps(mSzImPre, mImDepY, mDImDepY, mSzImDepY); tIm aLastPreIm = tIm(mSzImPre); tDIm *aLastPreDIm = nullptr; - cAppli_cTriangleDeformation::LoadImageAndData(aLastPreIm, aLastPreDIm, "pre", mImPre, mImPost); + LoadPrePostImageAndData(aLastPreIm, aLastPreDIm, "pre", mImPre, mImPost); if (mUseMultiScaleApproach && !mIsLastIters) { @@ -304,115 +335,108 @@ namespace MMVII aLastPreDIm = &aLastPreIm.DIm(); } - for (const cPt2di &aOutPix : *mDImOut) // Initialise output image + // prefill output image with ImPre pixels to not have null values + for (const tPt2di &aOutPix : *mDImOut) mDImOut->SetV(aOutPix, aLastPreDIm->GetV(aOutPix)); for (size_t aLTr = 0; aLTr < mDelTri.NbFace(); aLTr++) { const tTri2dr aLastTri = mDelTri.KthTri(aLTr); - const cPt3di aLastIndicesOfTriKnots = mDelTri.KthFace(aLTr); + const tPt3di aLastIndicesOfTriKnots = mDelTri.KthFace(aLTr); const cTriangle2DCompiled aLastCompTri(aLastTri); - std::vector aLastVectorToFillWithInsidePixels; + std::vector aLastVectorToFillWithInsidePixels; aLastCompTri.PixelsInside(aLastVectorToFillWithInsidePixels); const tIntVect aLastVecInd = {2 * aLastIndicesOfTriKnots.x(), 2 * aLastIndicesOfTriKnots.x() + 1, 2 * aLastIndicesOfTriKnots.y(), 2 * aLastIndicesOfTriKnots.y() + 1, 2 * aLastIndicesOfTriKnots.z(), 2 * aLastIndicesOfTriKnots.z() + 1}; - const cPt2dr aLastTrPointA = cPt2dr(aVFinalSol(aLastVecInd.at(0)), - aVFinalSol(aLastVecInd.at(1))); // last translation 1st point of triangle - const cPt2dr aLastTrPointB = cPt2dr(aVFinalSol(aLastVecInd.at(2)), - aVFinalSol(aLastVecInd.at(3))); // last translation 2nd point of triangle - const cPt2dr aLastTrPointC = cPt2dr(aVFinalSol(aLastVecInd.at(4)), - aVFinalSol(aLastVecInd.at(5))); // last translation 3rd point of triangle + const cNodeOfTriangles aLastFirstPointOfTri = cNodeOfTriangles(aVFinalSol, aLastVecInd, 0, 1, 0, 1, aLastTri, 0); + const cNodeOfTriangles aLastSecondPointOfTri = cNodeOfTriangles(aVFinalSol, aLastVecInd, 2, 3, 2, 3, aLastTri, 1); + const cNodeOfTriangles aLastThirdPointOfTri = cNodeOfTriangles(aVFinalSol, aLastVecInd, 4, 5, 4, 5, aLastTri, 2); + + const tPt2dr aLastTrPointA = aLastFirstPointOfTri.GetCurrentXYDisplacementValues(); // last translation 1st point of triangle + const tPt2dr aLastTrPointB = aLastSecondPointOfTri.GetCurrentXYDisplacementValues(); // last translation 2nd point of triangle + const tPt2dr aLastTrPointC = aLastThirdPointOfTri.GetCurrentXYDisplacementValues(); // last translation 3rd point of triangle const size_t aLastNumberOfInsidePixels = aLastVectorToFillWithInsidePixels.size(); for (size_t aLastFilledPixel = 0; aLastFilledPixel < aLastNumberOfInsidePixels; aLastFilledPixel++) { const cPtInsideTriangles aLastPixInsideTriangle = cPtInsideTriangles(aLastCompTri, aLastVectorToFillWithInsidePixels, - aLastFilledPixel, *aLastPreDIm); + aLastFilledPixel, aLastPreDIm); // image of a point in triangle by current translation - const cPt2dr aLastTranslatedFilledPoint = ApplyLastBarycenterTranslationFormulaToInsidePixel(aLastTrPointA, aLastTrPointB, - aLastTrPointC, aLastPixInsideTriangle); + const tPt2dr aLastTranslatedFilledPoint = ApplyBarycenterTranslationFormulaToFilledPixel(aLastTrPointA, aLastTrPointB, + aLastTrPointC, aLastPixInsideTriangle); - FillDisplacementMaps(aLastPixInsideTriangle, aLastTranslatedFilledPoint); + FillDisplacementMapsTranslation(aLastPixInsideTriangle, aLastTranslatedFilledPoint, + mSzImOut, mDImDepX, mDImDepY, mDImOut); } } // save displacement maps in x and y to image files if (mUseMultiScaleApproach) { - mDImDepX->ToFile("DisplacedPixelsX_iter_" + std::to_string(aIterNumber) + "_" + - std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales + mNumberOfEndIterations) + ".tif"); - mDImDepY->ToFile("DisplacedPixelsY_iter_" + std::to_string(aIterNumber) + "_" + - std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales + mNumberOfEndIterations) + ".tif"); - if (aIterNumber == mNumberOfScales + mNumberOfEndIterations - 1) - mDImOut->ToFile("DisplacedPixels.tif"); + mDImDepX->ToFile("DisplacedPixelsX_iter_" + ToStr(aIterNumber) + "_" + + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); + mDImDepY->ToFile("DisplacedPixelsY_iter_" + ToStr(aIterNumber) + "_" + + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); + if (aIterNumber == aTotalNumberOfIterations - 1) + mDImOut->ToFile("DisplacedPixels_iter_" + ToStr(aIterNumber) + "_" + + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); } - else + if (mInitialiseTranslationWithPreviousExecution) + { + mDImDepX->ToFile(mNameIntermediateDepX); + mDImDepY->ToFile(mNameIntermediateDepY); + } + if (!mUseMultiScaleApproach && (aIterNumber == aTotalNumberOfIterations - 1)) { - mDImDepX->ToFile("DisplacedPixelsX_" + std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales) + ".tif"); - mDImDepY->ToFile("DisplacedPixelsY_" + std::to_string(mNumberPointsToGenerate) + "_" + - std::to_string(mNumberOfScales) + ".tif"); - mDImOut->ToFile("DisplacedPixels.tif"); + mDImDepX->ToFile("DisplacedPixelsX_" + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); + mDImDepY->ToFile("DisplacedPixelsY_" + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); + mDImOut->ToFile("DisplacedPixels_" + ToStr(mNumberPointsToGenerate) + "_" + + ToStr(aTotalNumberOfIterations) + ".tif"); } } - void cAppli_cTriangleDeformationTranslation::GenerateDisplacementMapsAndLastTranslatedPoints(const int aIterNumber) + void cAppli_TriangleDeformationTranslation::GenerateDisplacementMapsAndDisplayLastTranslatedPoints(const int aIterNumber, + const int aTotalNumberOfIterations, + const tDenseVect &aVinitVecSol) { - tDenseVect aVFinalSol = mSys->CurGlobSol(); + tDenseVect aVFinalSol = mSysTranslation->CurGlobSol(); if (mGenerateDisplacementImage) - GenerateDisplacementMaps(aVFinalSol, aIterNumber); + GenerateDisplacementMaps(aVFinalSol, aIterNumber, aTotalNumberOfIterations); - if (mDisplayLastTranslatedPointsCoordinates) - { - for (int aFinalUnk = 0; aFinalUnk < aVFinalSol.DIm().Sz(); aFinalUnk++) - { - StdOut() << aVFinalSol(aFinalUnk) << " "; - if (aFinalUnk % 2 == 1 && aFinalUnk != 0) - StdOut() << std::endl; - } - } + if (mDisplayLastTranslationValues) + DisplayLastUnknownValuesAndComputeStatistics(aVFinalSol, aVinitVecSol); } - void cAppli_cTriangleDeformationTranslation::DoOneIterationTranslation(const int aIterNumber) + void cAppli_TriangleDeformationTranslation::DoOneIterationTranslation(const int aIterNumber, const int aTotalNumberOfIterations, + const tDenseVect &aVInitVecSol) { - LoopOverTrianglesAndUpdateParametersTranslation(aIterNumber); // Iterate over triangles and solve system + LoopOverTrianglesAndUpdateParametersTranslation(aIterNumber, aTotalNumberOfIterations); // Iterate over triangles and solve system // Show final translation results and produce displacement maps - if (mUseMultiScaleApproach) - { - if (aIterNumber == (mNumberOfScales + mNumberOfEndIterations - 1)) - GenerateDisplacementMapsAndLastTranslatedPoints(aIterNumber); - } - else - { - if (aIterNumber == (mNumberOfScales - 1)) - GenerateDisplacementMapsAndLastTranslatedPoints(aIterNumber); - } + if (aIterNumber == (aTotalNumberOfIterations - 1)) + GenerateDisplacementMapsAndDisplayLastTranslatedPoints(aIterNumber, aTotalNumberOfIterations, aVInitVecSol); } //----------------------------------------- - int cAppli_cTriangleDeformationTranslation::Exe() + int cAppli_TriangleDeformationTranslation::Exe() { - // read pre and post images and their sizes - mImPre = tIm::FromFile(mNamePreImage); - mImPost = tIm::FromFile(mNamePostImage); - - mDImPre = &mImPre.DIm(); - mSzImPre = mDImPre->Sz(); - - mDImPost = &mImPost.DIm(); - mSzImPost = mDImPost->Sz(); + // read pre and post images and update their sizes + ReadFileNameLoadData(mNamePreImage, mImPre, mDImPre, mSzImPre); + ReadFileNameLoadData(mNamePostImage, mImPost, mDImPost, mSzImPost); if (mUseMultiScaleApproach) mSigmaGaussFilter = mNumberOfScales * mSigmaGaussFilterStep; @@ -422,22 +446,41 @@ namespace MMVII << "Diff, " << "NbOut" << std::endl; - cAppli_cTriangleDeformation::GeneratePointsForDelaunay(mVectorPts, mNumberPointsToGenerate, mRandomUniformLawUpperBoundLines, - mRandomUniformLawUpperBoundCols, mDelTri, mSzImPre); - - InitialisationAfterExeTranslation(); + DefineValueLimitsForPointGenerationAndBuildGrid(mNumberPointsToGenerate, mNumberOfLines, + mNumberOfCols, mDelTri, mSzImPre, mBuildRandomUniformGrid); - if (mUseMultiScaleApproach) - { - for (int aIterNumber = 0; aIterNumber < mNumberOfScales + mNumberOfEndIterations; aIterNumber++) - DoOneIterationTranslation(aIterNumber); - } + if (!mInitialiseTranslationWithPreviousExecution || mInitialiseWithUserValues) + InitialisationAfterExeTranslation(mDelTri, mSysTranslation, mInitialiseWithUserValues, + mInitialiseXTranslationValue, mInitialiseYTranslationValue); else { - for (int aIterNumber = 0; aIterNumber < mNumberOfScales; aIterNumber++) - DoOneIterationTranslation(aIterNumber); + if (mIsFirstExecution && mInitialiseWithMMVI) + InitialiseWithPreviousExecutionValuesTranslation(mDelTri, mSysTranslation, + mNameInitialDepX, mImIntermediateDepX, + mDImIntermediateDepX, mSzImIntermediateDepX, + mNameInitialDepY, mImIntermediateDepY, + mDImIntermediateDepY, mSzImIntermediateDepY, + mNameCorrelationMaskMMVI, mImCorrelationMask, + mDImCorrelationMask, mSzCorrelationMask); + + else if (!mIsFirstExecution && mInitialiseWithMMVI) + InitialiseWithPreviousExecutionValuesTranslation(mDelTri, mSysTranslation, + mNameIntermediateDepX, mImIntermediateDepX, + mDImIntermediateDepX, mSzImIntermediateDepX, + mNameIntermediateDepY, mImIntermediateDepY, + mDImIntermediateDepY, mSzImIntermediateDepY, + mNameCorrelationMaskMMVI, mImCorrelationMask, + mDImCorrelationMask, mSzCorrelationMask); } + const tDenseVect aVInitSolTr = mSysTranslation->CurGlobSol().Dup(); // Duplicate initial solution + + int aTotalNumberOfIterations = 0; + (mUseMultiScaleApproach) ? aTotalNumberOfIterations = mNumberOfScales + mNumberOfEndIterations : aTotalNumberOfIterations = mNumberOfScales; + + for (int aIterNumber = 0; aIterNumber < aTotalNumberOfIterations; aIterNumber++) + DoOneIterationTranslation(aIterNumber, aTotalNumberOfIterations, aVInitSolTr); + return EXIT_SUCCESS; } @@ -445,19 +488,19 @@ namespace MMVII // ::MMVII // /********************************************/ - tMMVII_UnikPApli Alloc_cTriangleDeformationTranslation(const std::vector &aVArgs, - const cSpecMMVII_Appli &aSpec) + tMMVII_UnikPApli Alloc_cAppli_TriangleDeformationTranslation(const std::vector &aVArgs, + const cSpecMMVII_Appli &aSpec) { - return tMMVII_UnikPApli(new cAppli_cTriangleDeformationTranslation(aVArgs, aSpec)); + return tMMVII_UnikPApli(new cAppli_TriangleDeformationTranslation(aVArgs, aSpec)); } cSpecMMVII_Appli TheSpec_ComputeTriangleDeformationTranslation( "ComputeTriangleDeformationTranslation", - Alloc_cTriangleDeformationTranslation, - "Compute 2D translation deformations of triangles between images using triangles", + Alloc_cAppli_TriangleDeformationTranslation, + "Compute 2D translation deformations between images using triangles", {eApF::ImProc}, // category {eApDT::Image}, // input {eApDT::Image}, // output __FILE__); -}; // namespace MMVII \ No newline at end of file +}; // namespace MMVII diff --git a/MMVII/src/MeshDisplacement/TriangleDeformationTranslation.h b/MMVII/src/MeshDisplacement/TriangleDeformationTranslation.h index 170687e39c..ba4423d519 100644 --- a/MMVII/src/MeshDisplacement/TriangleDeformationTranslation.h +++ b/MMVII/src/MeshDisplacement/TriangleDeformationTranslation.h @@ -4,6 +4,7 @@ #include "MMVII_Geom2D.h" #include "MMVII_PhgrDist.h" +#include "MMVII_TplSymbTriangle.h" #include "TriangleDeformation.h" using namespace NS_SymbolicDerivative; @@ -11,48 +12,41 @@ using namespace NS_SymbolicDerivative; namespace MMVII { - /******************************************/ - /* */ - /* cTriangleDeformationTranslation */ - /* */ - /******************************************/ + /************************************************/ + /* */ + /* cAppli_TriangleDeformationTranslation */ + /* */ + /************************************************/ - class cAppli_cTriangleDeformationTranslation : public cAppli_cTriangleDeformation + class cAppli_TriangleDeformationTranslation : public cAppli_TriangleDeformation { public: typedef cIm2D tIm; typedef cDataIm2D tDIm; typedef cTriangle tTri2dr; - typedef cDenseVect tDenseVect; + typedef cDenseVect tDenseVect; typedef std::vector tIntVect; - typedef std::vector tDoubleVect; + typedef std::vector tDoubleVect; - cAppli_cTriangleDeformationTranslation(const std::vector &aVArgs, - const cSpecMMVII_Appli &aSpec); - ~cAppli_cTriangleDeformationTranslation(); + cAppli_TriangleDeformationTranslation(const std::vector &aVArgs, + const cSpecMMVII_Appli &aSpec); + ~cAppli_TriangleDeformationTranslation(); int Exe() override; cCollecSpecArg2007 &ArgObl(cCollecSpecArg2007 &anArgObl) override; cCollecSpecArg2007 &ArgOpt(cCollecSpecArg2007 &anArgOpt) override; // Iterate of triangles and inside pixels - void DoOneIterationTranslation(const int aIterNumber); + // void DoOneIterationTranslation(const int aIterNumber, const int aTotalNumberOfIterations); + void DoOneIterationTranslation(const int aIterNumber, const int aTotalNumberOfIterations, + const tDenseVect &aVInitVecSol); // Loops over all triangles and solves system to update parameters at end of iteration - void LoopOverTrianglesAndUpdateParametersTranslation(const int aIterNumber); + void LoopOverTrianglesAndUpdateParametersTranslation(const int aIterNumber, const int aTotalNumberOfIterations); // Generate displacement maps of last solution - void GenerateDisplacementMaps(const tDenseVect &aVFinalSol, const int aIterNumber); + void GenerateDisplacementMaps(const tDenseVect &aVFinalSol, const int aIterNumber, const int aTotalNumberOfIterations); // Generates Displacement maps and coordinates of points in triangulation at last iteration - void GenerateDisplacementMapsAndLastTranslatedPoints(const int aIterNumber); - // Initialise problem after user has input information - void InitialisationAfterExeTranslation(); - // Fill displacement maps and output image - void FillDisplacementMaps(const cPtInsideTriangles &aLastPixInsideTriangle, - const cPt2dr &aLastTranslatedFilledPoint); - // Apply barycentration translation formula to last translation values in optimisation process - cPt2dr ApplyLastBarycenterTranslationFormulaToInsidePixel(const cPt2dr &aLastTranslationPointA, - const cPt2dr &aLastTranslationPointB, - const cPt2dr &aLastTranslationPointC, - const cPtInsideTriangles &aLastPixInsideTriangle); + void GenerateDisplacementMapsAndDisplayLastTranslatedPoints(const int aIterNumber, const int aTotalNumberOfIterations, + const tDenseVect &aVinitVecSol); private: // == Mandatory args ==== @@ -60,51 +54,77 @@ namespace MMVII std::string mNamePreImage; // Name of given pre-image std::string mNamePostImage; // Name of given post-image int mNumberPointsToGenerate; // number of generated points - int mNumberOfScales; // number of iterations in optimisation process + int mNumberOfScales; // number of iterations in optimisation process or scales is use of multi-scale approach // == Optionnal args ==== - int mRandomUniformLawUpperBoundLines; // Uniform law generates random coordinates in interval [0, mRandomUniformLawUpperBoundLines [ - int mRandomUniformLawUpperBoundCols; // Uniform law generates random coordinates in interval [0, mRandomUniformLawUpperBoundCols [ - bool mShow; // Print result, export image ... - bool mComputeAvgMax; // Compute average and maximum pixel value of difference image between pre and post images - bool mUseMultiScaleApproach; // Apply multi-scale approach or not - int mSigmaGaussFilterStep; // Decreasing step of sigma value during iterations - bool mGenerateDisplacementImage; // Generate image with displaced pixels - int mNumberOfIterGaussFilter; // Number of iterations to be done in Gauss filter algorithm - int mNumberOfEndIterations; // Number of iterations to do while using original image in multi-scale approach - bool mDisplayLastTranslatedPointsCoordinates; // Whether to display the final coordinates of the translated points + int mNumberOfLines; // Uniform law generates random coordinates in interval [0, mNumberOfLines [ + int mNumberOfCols; // Uniform law generates random coordinates in interval [0, mNumberOfCols [ + bool mShow; // Print result + bool mUseMultiScaleApproach; // Apply multi-scale approach or not + bool mBuildRandomUniformGrid; // Whether to triangulate grid made of points whose coordinates follow a uniform law or have coordinates that form rectangles + bool mInitialiseTranslationWithPreviousExecution; // Initialise values of unknowns with values obtained at previous algorithm execution + bool mInitialiseWithUserValues; // Initalise or not with values given by user + tREAL8 mInitialiseXTranslationValue; // Value given by user to initialise x-translation unknowns + tREAL8 mInitialiseYTranslationValue; // Value given by user to initialise y-translation unknowns + bool mInitialiseWithMMVI; // Whether to initialise values of unknowns with pre-computed values from MicMacV1 or not + std::string mNameInitialDepX; // File name of initial X-displacement map + std::string mNameInitialDepY; // File name of initial Y-displacement map + std::string mNameIntermediateDepX; // File name to save to of intermediate X-displacement map between executions if initialisation with previous unknown values is true + std::string mNameIntermediateDepY; // File name to save to of intermediate Y-displacement map between executions if initialisation with previous unknown values is true + std::string mNameCorrelationMaskMMVI; // File name of mask file produced by MMVI that gives pixel locations where correlation was computed + bool mIsFirstExecution; // Whether current execution of algorithm is first execution or not + int mSigmaGaussFilterStep; // Decreasing step of sigma value during iterations + bool mGenerateDisplacementImage; // Generate image with displaced pixels + bool mFreezeTranslationX; // Freeze x-translation or not during optimisation + bool mFreezeTranslationY; // Freeze y-translation or not during optimisation + tREAL8 mWeightTranslationX; // Weight given to x-translation if soft freezing is applied (default : negative => not applied) + tREAL8 mWeightTranslationY; // Weight given to y-translation if soft freezing is applied (default : negative => not applied) + int mNumberOfIterGaussFilter; // Number of iterations to be done in Gauss filter algorithm + int mNumberOfEndIterations; // Number of iterations to do while using original image in multi-scale approach + bool mDisplayLastTranslationValues; // Whether to display the final coordinates of the translated points // == Internal variables ==== - cPt2di mSzImPre; // size of image - tIm mImPre; // memory representation of the image - tDIm *mDImPre; // memory representation of the image + tPt2di mSzImPre; // size of image + tIm mImPre; // memory representation of the image + tDIm *mDImPre; // memory representation of the image - cPt2di mSzImPost; // size of image - tIm mImPost; // memory representation of the image - tDIm *mDImPost; // memory representation of the image + tPt2di mSzImPost; // size of image + tIm mImPost; // memory representation of the image + tDIm *mDImPost; // memory representation of the image - cPt2di mSzImOut; // size of image - tIm mImOut; // memory representation of the image - tDIm *mDImOut; // memory representation of the image + tPt2di mSzImOut; // size of image + tIm mImOut; // memory representation of the image + tDIm *mDImOut; // memory representation of the image - cPt2di mSzImDepX; // size of image - tIm mImDepX; // memory representation of the image - tDIm *mDImDepX; // memory representation of the image + tPt2di mSzImDepX; // size of image + tIm mImDepX; // memory representation of the image + tDIm *mDImDepX; // memory representation of the image - cPt2di mSzImDepY; // size of image - tIm mImDepY; // memory representation of the image - tDIm *mDImDepY; // memory representation of the image + tPt2di mSzImDepY; // size of image + tIm mImDepY; // memory representation of the image + tDIm *mDImDepY; // memory representation of the image - double mSigmaGaussFilter; // Value of sigma in gauss filter + tPt2di mSzImIntermediateDepX; // size of image + tIm mImIntermediateDepX; // memory representation of the image + tDIm *mDImIntermediateDepX; // memory representation of the image + + tPt2di mSzImIntermediateDepY; // size of image + tIm mImIntermediateDepY; // memory representation of the image + tDIm *mDImIntermediateDepY; // memory representation of the image + + tPt2di mSzCorrelationMask; // size of image + tIm mImCorrelationMask; // memory representation of the image + tDIm *mDImCorrelationMask; // memory representation of the image + + tREAL8 mSigmaGaussFilter; // Value of sigma in gauss filter bool mIsLastIters; // Determines whether optimisation process is at last iters to optimise on original image - std::vector mVectorPts; // A vector containing a set of points cTriangulation2D mDelTri; // A Delaunay triangle - cResolSysNonLinear *mSys; // Non Linear Sys for solving problem - cCalculator *mEqTranslationTri; // calculator giving access to values and derivatives + cResolSysNonLinear *mSysTranslation; // Non Linear Sys for solving problem + cCalculator *mEqTranslationTri; // calculator giving access to values and derivatives }; } diff --git a/MMVII/src/MeshDisplacement/TriangleDeformationUtils.cpp b/MMVII/src/MeshDisplacement/TriangleDeformationUtils.cpp new file mode 100644 index 0000000000..8cf834f7ee --- /dev/null +++ b/MMVII/src/MeshDisplacement/TriangleDeformationUtils.cpp @@ -0,0 +1,804 @@ +#include "TriangleDeformationUtils.h" + +/** + \file TriangleDeformationUtils.cpp + \brief File containing annexe methods that can be used by + other classes linked to triangle deformation computation +**/ + +namespace MMVII +{ + /****************************************/ + /* */ + /* cPtInsideTriangles */ + /* */ + /****************************************/ + + cPtInsideTriangles::cPtInsideTriangles(const cTriangle2DCompiled &aCompTri, // a compiled triangle + const std::vector &aVectorFilledwithInsidePixels, // vector containing pixels insisde triangles + const size_t aFilledPixel, // a counter that is looping over pixels in triangles + cDataIm2D *&aDIm) // image + { + mFilledIndices = tPt2dr(aVectorFilledwithInsidePixels[aFilledPixel].x(), aVectorFilledwithInsidePixels[aFilledPixel].y()); + mBarycenterCoordinatesOfPixel = aCompTri.CoordBarry(mFilledIndices); + if (aDIm->InsideBL(mFilledIndices)) + mValueOfPixel = aDIm->GetVBL(mFilledIndices); + else + mValueOfPixel = aDIm->GetV(tPt2di(mFilledIndices.x(), mFilledIndices.y())); + } + + cPt3dr cPtInsideTriangles::GetBarycenterCoordinates() const { return mBarycenterCoordinatesOfPixel; } // Accessor + tPt2dr cPtInsideTriangles::GetCartesianCoordinates() const { return mFilledIndices; } // Accessor + tREAL8 cPtInsideTriangles::GetPixelValue() const { return mValueOfPixel; } // Accessor + + /****************************************/ + /* */ + /* cNodeOfTriangles */ + /* */ + /****************************************/ + + cNodeOfTriangles::cNodeOfTriangles() + { + } + + cNodeOfTriangles::cNodeOfTriangles(const tDenseVect &aVecSol, + const tIntVect &aIndicesVec, + const int adXIndex, + const int adYIndex, + const int aRadTrIndex, + const int aRadScIndex, + const tTri2dr &aTri, + const int aPointNumberInTri) + { + mInitialNodeCoordinates = aTri.Pt(aPointNumberInTri); + mCurXYDisplacementVector = tPt2dr(aVecSol(aIndicesVec.at(adXIndex)), + aVecSol(aIndicesVec.at(adYIndex))); + mCurRadTr = aVecSol(aIndicesVec.at(aRadTrIndex)); + mCurRadSc = aVecSol(aIndicesVec.at(aRadScIndex)); + } + + tPt2dr cNodeOfTriangles::GetInitialNodeCoordinates() const { return mInitialNodeCoordinates; } // Accessor + tPt2dr cNodeOfTriangles::GetCurrentXYDisplacementValues() const { return mCurXYDisplacementVector; } // Accessor + tREAL8 cNodeOfTriangles::GetCurrentRadiometryScaling() const { return mCurRadSc; } // Accessor + tREAL8 cNodeOfTriangles::GetCurrentRadiometryTranslation() const { return mCurRadTr; } // Accessor + tREAL8 &cNodeOfTriangles::GetCurrentRadiometryTranslation() { return mCurRadTr; } // Accessor + tREAL8 &cNodeOfTriangles::GetCurrentRadiometryScaling() { return mCurRadSc; } // Accessor + + //---------------------------------------------// + + void BuildUniformRandomVectorAndApplyDelaunay(const int aNumberOfPointsToGenerate, const int aRandomUniformLawUpperBoundLines, + const int aRandomUniformLawUpperBoundCols, cTriangulation2D &aDelaunayTri) + { + std::vector aVectorPts; + // Generate coordinates from drawing lines and columns of coordinates from a uniform distribution + for (int aNbPt = 0; aNbPt < aNumberOfPointsToGenerate; aNbPt++) + { + const tREAL8 aUniformRandomLine = RandUnif_N(aRandomUniformLawUpperBoundLines); + const tREAL8 aUniformRandomCol = RandUnif_N(aRandomUniformLawUpperBoundCols); + const tPt2dr aUniformRandomPt(aUniformRandomCol, aUniformRandomLine); // tPt2dr format + aVectorPts.push_back(aUniformRandomPt); + } + aDelaunayTri = aVectorPts; + + aDelaunayTri.MakeDelaunay(); // Delaunay triangulate randomly generated points. + } + + void DefineValueLimitsForPointGenerationAndBuildGrid(const int aNumberOfPointsToGenerate, int aNumberOfLines, int aNumberOfCols, + cTriangulation2D &aDelaunayTri, const tPt2di &aSzIm, + const bool aBuildUniformVector) + { + // If user hasn't defined another value than the default value, it is changed + if (aNumberOfLines == 1 && aNumberOfCols == 1) + { + // Maximum value of coordinates are drawn from [0, NumberOfImageLines[ for lines + aNumberOfLines = aSzIm.y(); + // Maximum value of coordinates are drawn from [0, NumberOfImageColumns[ for columns + aNumberOfCols = aSzIm.x(); + } + else + { + if (aNumberOfLines != 1 && aNumberOfCols == 1) + aNumberOfCols = aSzIm.x(); + else + { + if (aNumberOfLines == 1 && aNumberOfCols != 1) + aNumberOfLines = aSzIm.y(); + } + } + + if (aBuildUniformVector) + BuildUniformRandomVectorAndApplyDelaunay(aNumberOfPointsToGenerate, + aNumberOfLines, aNumberOfCols, + aDelaunayTri); + else + GeneratePointsForRectangleGrid(aNumberOfPointsToGenerate, aNumberOfLines, + aNumberOfCols, aDelaunayTri); + } + + void GeneratePointsForRectangleGrid(const int aNumberOfPoints, const int aGridSizeLines, + const int aGridSizeCols, cTriangulation2D &aDelaunayTri) + { + std::vector aGridVector; + const int anEdge = 10; // To take away variations linked to edges + + // be aware that step between grid points are integers + const int aDistanceLines = aGridSizeLines / std::sqrt(aNumberOfPoints); + const int aDistanceCols = aGridSizeCols / std::sqrt(aNumberOfPoints); + + const int anEndLinesLoop = aGridSizeLines - anEdge; + const int anEndColsLoop = aGridSizeCols - anEdge; + + for (int aLineNumber = anEdge; aLineNumber < anEndLinesLoop; aLineNumber += aDistanceLines) + { + for (int aColNumber = anEdge; aColNumber < anEndColsLoop; aColNumber += aDistanceCols) + { + const tPt2dr aGridPt = tPt2dr(aColNumber, aLineNumber); // tPt2dr format + aGridVector.push_back(aGridPt); + } + } + + aDelaunayTri = aGridVector; + + aDelaunayTri.MakeDelaunay(); // Delaunay triangulate randomly generated points. + } + + void InitialisationAfterExe(const cTriangulation2D &aDelaunayTri, + cResolSysNonLinear *&aSys, + const bool aUserInitialisation, + const tREAL8 aXTranslationInitVal, + const tREAL8 aYTranslationInitVal, + const tREAL8 aRadTranslationInitVal, + const tREAL8 aRadScaleInitVal) + { + const size_t aStartNumberPts = 4 * aDelaunayTri.NbPts(); + tDenseVect aVInit(aStartNumberPts, eModeInitImage::eMIA_Null); + + if (aUserInitialisation && aXTranslationInitVal != 0 && aYTranslationInitVal != 0 && aRadTranslationInitVal != 0 && aRadScaleInitVal != 1) + { + for (size_t aKtNumber = 0; aKtNumber < aStartNumberPts; aKtNumber++) + { + if (aKtNumber % 4 == 0 && aXTranslationInitVal != 0) + aVInit(aKtNumber) = aXTranslationInitVal; + if (aKtNumber % 4 == 1 && aYTranslationInitVal != 0) + aVInit(aKtNumber) = aYTranslationInitVal; + if (aKtNumber % 4 == 2 && aRadTranslationInitVal != 0) + aVInit(aKtNumber) = aRadTranslationInitVal; + if (aKtNumber % 4 == 3) + aVInit(aKtNumber) = aRadScaleInitVal; + } + } + else + { + for (size_t aKtNumber = 0; aKtNumber < aStartNumberPts; aKtNumber++) + { + if (aKtNumber % 4 == 3) + aVInit(aKtNumber) = 1; + } + } + + aSys = new cResolSysNonLinear(eModeSSR::eSSR_LsqDense, aVInit); + } + + void InitialiseWithPreviousExecutionValues(const cTriangulation2D &aDelTri, + cResolSysNonLinear *&aSys, + const std::string &aNameDepXFile, tIm &aImDepX, + tDIm *&aDImDepX, tPt2di &aSzImDepX, + const std::string &aNameDepYFile, tIm &aImDepY, + tDIm *&aDImDepY, tPt2di &aSzImDepY, + const std::string &aNameCorrelationMask, + tIm &aImCorrelationMask, tDIm *&aDImCorrelationMask, + tPt2di &aSzCorrelationMask) + { + tDenseVect aVInit(4 * aDelTri.NbPts(), eModeInitImage::eMIA_Null); + + ReadFileNameLoadData(aNameDepXFile, aImDepX, + aDImDepX, aSzImDepX); + ReadFileNameLoadData(aNameDepYFile, aImDepY, + aDImDepY, aSzImDepY); + + ReadFileNameLoadData(aNameCorrelationMask, aImCorrelationMask, + aDImCorrelationMask, aSzCorrelationMask); + + for (size_t aTr = 0; aTr < aDelTri.NbFace(); aTr++) + { + const tTri2dr aInitTri = aDelTri.KthTri(aTr); + const tPt3di aIndicesOfTriKnots = aDelTri.KthFace(aTr); + + //----------- index of unknown, finds the associated pixels of current triangle + const std::vector aInitVecInd = {4 * aIndicesOfTriKnots.x(), 4 * aIndicesOfTriKnots.x() + 1, + 4 * aIndicesOfTriKnots.x() + 2, 4 * aIndicesOfTriKnots.x() + 3, + 4 * aIndicesOfTriKnots.y(), 4 * aIndicesOfTriKnots.y() + 1, + 4 * aIndicesOfTriKnots.y() + 2, 4 * aIndicesOfTriKnots.y() + 3, + 4 * aIndicesOfTriKnots.z(), 4 * aIndicesOfTriKnots.z() + 1, + 4 * aIndicesOfTriKnots.z() + 2, 4 * aIndicesOfTriKnots.z() + 3}; + + // Get points coordinates associated to triangle + const cNodeOfTriangles aFirstInitPointOfTri = cNodeOfTriangles(aVInit, aInitVecInd, 0, 1, 2, 3, aInitTri, 0); + const cNodeOfTriangles aSecondInitPointOfTri = cNodeOfTriangles(aVInit, aInitVecInd, 4, 5, 6, 7, aInitTri, 1); + const cNodeOfTriangles aThirdInitPointOfTri = cNodeOfTriangles(aVInit, aInitVecInd, 8, 9, 10, 11, aInitTri, 2); + + aVInit(aInitVecInd.at(0)) = ReturnCorrectInitialisationValue(aDImCorrelationMask, aDImDepX, + aFirstInitPointOfTri, 0); + aVInit(aInitVecInd.at(1)) = ReturnCorrectInitialisationValue(aDImCorrelationMask, aDImDepY, + aFirstInitPointOfTri, 0); + aVInit(aInitVecInd.at(2)) = ReturnCorrectInitialisationValue(aDImCorrelationMask, aDImDepX, + aSecondInitPointOfTri, 0); + aVInit(aInitVecInd.at(3)) = ReturnCorrectInitialisationValue(aDImCorrelationMask, aDImDepY, + aSecondInitPointOfTri, 0); + aVInit(aInitVecInd.at(4)) = ReturnCorrectInitialisationValue(aDImCorrelationMask, aDImDepX, + aThirdInitPointOfTri, 0); + aVInit(aInitVecInd.at(5)) = ReturnCorrectInitialisationValue(aDImCorrelationMask, aDImDepY, + aThirdInitPointOfTri, 0); + } + + aSys = new cResolSysNonLinear(eModeSSR::eSSR_LsqDense, aVInit); + } + + void InitialisationAfterExeTranslation(const cTriangulation2D &aDelaunayTri, + cResolSysNonLinear *&aSysTranslation, + const bool aUserInitialisation, + const tREAL8 aXTranslationInitVal, + const tREAL8 aYTranslationInitVal) + { + const size_t aNumberPts = 2 * aDelaunayTri.NbPts(); + tDenseVect aVInitTranslation(aNumberPts, eModeInitImage::eMIA_Null); + + if (aUserInitialisation && aXTranslationInitVal != 0 && aYTranslationInitVal != 0) + { + for (size_t aKtNumber = 0; aKtNumber < aNumberPts; aKtNumber++) + { + if (aKtNumber % 2 == 0 && aXTranslationInitVal != 0) + aVInitTranslation(aKtNumber) = aXTranslationInitVal; + if (aKtNumber % 2 == 1 && aYTranslationInitVal != 0) + aVInitTranslation(aKtNumber) = aYTranslationInitVal; + } + } + + aSysTranslation = new cResolSysNonLinear(eModeSSR::eSSR_LsqDense, aVInitTranslation); + } + + void InitialiseWithPreviousExecutionValuesTranslation(const cTriangulation2D &aDelTri, + cResolSysNonLinear *&aSysTranslation, + const std::string &aNameDepXFile, tIm &aImDepX, + tDIm *&aDImDepX, tPt2di &aSzImDepX, + const std::string &aNameDepYFile, tIm &aImDepY, + tDIm *&aDImDepY, tPt2di &aSzImDepY, + const std::string &aNameCorrelationMask, + tIm &aImCorrelationMask, tDIm *&aDImCorrelationMask, + tPt2di &aSzCorrelationMask) + { + tDenseVect aVInitTranslation(2 * aDelTri.NbPts(), eModeInitImage::eMIA_Null); + + ReadFileNameLoadData(aNameDepXFile, aImDepX, + aDImDepX, aSzImDepX); + ReadFileNameLoadData(aNameDepYFile, aImDepY, + aDImDepY, aSzImDepY); + + ReadFileNameLoadData(aNameCorrelationMask, aImCorrelationMask, + aDImCorrelationMask, aSzCorrelationMask); + + for (size_t aTr = 0; aTr < aDelTri.NbFace(); aTr++) + { + const tTri2dr aInitTriTr = aDelTri.KthTri(aTr); + const tPt3di aInitIndicesOfTriKnots = aDelTri.KthFace(aTr); + + //----------- index of unknown, finds the associated pixels of current triangle + const std::vector aInitVecInd = {2 * aInitIndicesOfTriKnots.x(), 2 * aInitIndicesOfTriKnots.x() + 1, + 2 * aInitIndicesOfTriKnots.y(), 2 * aInitIndicesOfTriKnots.y() + 1, + 2 * aInitIndicesOfTriKnots.z(), 2 * aInitIndicesOfTriKnots.z() + 1}; + + // Get nodes associated to triangle + const cNodeOfTriangles aFirstInitPointOfTri = cNodeOfTriangles(aVInitTranslation, aInitVecInd, + 0, 1, 0, 1, aInitTriTr, 0); + const cNodeOfTriangles aSecondInitPointOfTri = cNodeOfTriangles(aVInitTranslation, aInitVecInd, + 2, 3, 2, 3, aInitTriTr, 1); + const cNodeOfTriangles aThirdInitPointOfTri = cNodeOfTriangles(aVInitTranslation, aInitVecInd, + 4, 5, 4, 5, aInitTriTr, 2); + + aVInitTranslation(aInitVecInd.at(0)) = ReturnCorrectInitialisationValue(aDImCorrelationMask, aDImDepX, + aFirstInitPointOfTri, 0); + aVInitTranslation(aInitVecInd.at(1)) = ReturnCorrectInitialisationValue(aDImCorrelationMask, aDImDepY, + aFirstInitPointOfTri, 0); + aVInitTranslation(aInitVecInd.at(2)) = ReturnCorrectInitialisationValue(aDImCorrelationMask, aDImDepX, + aSecondInitPointOfTri, 0); + aVInitTranslation(aInitVecInd.at(3)) = ReturnCorrectInitialisationValue(aDImCorrelationMask, aDImDepY, + aSecondInitPointOfTri, 0); + aVInitTranslation(aInitVecInd.at(4)) = ReturnCorrectInitialisationValue(aDImCorrelationMask, aDImDepX, + aThirdInitPointOfTri, 0); + aVInitTranslation(aInitVecInd.at(5)) = ReturnCorrectInitialisationValue(aDImCorrelationMask, aDImDepY, + aThirdInitPointOfTri, 0); + } + + aSysTranslation = new cResolSysNonLinear(eModeSSR::eSSR_LsqDense, aVInitTranslation); + } + + void InitialisationAfterExeRadiometry(const cTriangulation2D &aDelaunayTri, + cResolSysNonLinear *&aSysRadiometry, + const bool aUserInitialisation, + const tREAL8 aRadTranslationInitVal, + const tREAL8 aRadScaleInitVal) + { + const size_t aNumberPts = 2 * aDelaunayTri.NbPts(); + tDenseVect aVInitRadiometry(aNumberPts, eModeInitImage::eMIA_Null); + + if (aUserInitialisation && aRadTranslationInitVal != 0 && aRadScaleInitVal != 1) + { + for (size_t aKtNumber = 0; aKtNumber < aNumberPts; aKtNumber++) + { + if (aKtNumber % 2 == 0 && aRadTranslationInitVal != 0) + aVInitRadiometry(aKtNumber) = aRadTranslationInitVal; + if (aKtNumber % 2 == 1) + aVInitRadiometry(aKtNumber) = aRadScaleInitVal; + } + } + else + { + for (size_t aKtNumber = 0; aKtNumber < aNumberPts; aKtNumber++) + { + if (aKtNumber % 2 == 1) + aVInitRadiometry(aKtNumber) = 1; + } + } + + aSysRadiometry = new cResolSysNonLinear(eModeSSR::eSSR_LsqDense, aVInitRadiometry); + } + + bool CheckValidCorrelationValue(tDIm *aMask, const cNodeOfTriangles &aPtOfTri) + { + // const tPt2di aCoordKt = tPt2di(aPtOfTri.GetInitialNodeCoordinates().x(), aPtOfTri.GetInitialNodeCoordinates().y()); + const tPt2dr aCoordNode = aPtOfTri.GetInitialNodeCoordinates(); + bool aIsValidCorrelPoint; + if (aMask->InsideBL(aCoordNode)) + (aMask->GetVBL(aCoordNode) == 1) ? aIsValidCorrelPoint = true : aIsValidCorrelPoint = false; + else + aIsValidCorrelPoint = false; + return aIsValidCorrelPoint; + } + + tREAL8 ReturnCorrectInitialisationValue(tDIm *aMask, tDIm *aDispMap, + const cNodeOfTriangles &aPtOfTri, const tREAL8 aValueToReturnIfFalse) + { + // const tPt2di aCoordKt = tPt2di(aPtOfTri.GetInitialNodeCoordinates().x(), aPtOfTri.GetInitialNodeCoordinates().y()); + const tPt2dr aCoordNode = aPtOfTri.GetInitialNodeCoordinates(); + // Check if correlation is computed for the point + const bool aPointIsValid = CheckValidCorrelationValue(aMask, aPtOfTri); + tREAL8 aInitialisationValue; + if (aDispMap->InsideBL(aCoordNode)) + (aPointIsValid) ? aInitialisationValue = aDispMap->GetVBL(aCoordNode) : aInitialisationValue = aValueToReturnIfFalse; + else + aInitialisationValue = aValueToReturnIfFalse; + return aInitialisationValue; + } + + tPt2dr CheckReturnOfBilinearValue(tDIm *&aDImDispXMap, tDIm *&aDImDispYMap, + const tPt2dr &aRealCoordPoint, const tPt2di &aIntCoordPoint) + { + const bool aRealCoordPointInsideDispX = aDImDispXMap->InsideBL(aRealCoordPoint); + const bool aRealCoordPointInsideDispY = aDImDispYMap->InsideBL(aRealCoordPoint); + if (aRealCoordPointInsideDispX && aRealCoordPointInsideDispY) + return tPt2dr(aDImDispXMap->GetVBL(aRealCoordPoint), aDImDispYMap->GetVBL(aRealCoordPoint)); + else if (aRealCoordPointInsideDispX && !aRealCoordPointInsideDispY) + return tPt2dr(aDImDispXMap->GetVBL(aRealCoordPoint), aDImDispYMap->GetV(aIntCoordPoint)); + else if (!aRealCoordPointInsideDispX && aRealCoordPointInsideDispY) + return tPt2dr(aDImDispXMap->GetV(aIntCoordPoint), aDImDispYMap->GetVBL(aRealCoordPoint)); + else if (!aRealCoordPointInsideDispX && !aRealCoordPointInsideDispY) + return tPt2dr(aDImDispXMap->GetV(aIntCoordPoint), aDImDispYMap->GetV(aIntCoordPoint)); + else + return tPt2dr(0, 0); // so compiler accepts function + } + + void SubtractPrePostImageAndComputeAvgAndMax(tIm &aImDiff, tDIm *aDImDiff, tDIm *aDImPre, + tDIm *aDImPost, tPt2di &aSzImPre) + { + aImDiff = tIm(aSzImPre); + aDImDiff = &aImDiff.DIm(); + + for (const tPt2di &aDiffPix : *aDImDiff) + aDImDiff->SetV(aDiffPix, aDImPre->GetV(aDiffPix) - aDImPost->GetV(aDiffPix)); + const int aNumberOfPixelsInImage = aSzImPre.x() * aSzImPre.y(); + + tREAL8 aSumPixelValuesInDiffImage = 0; + tREAL8 aMaxPixelValuesInDiffImage = 0; + tREAL8 aDiffImPixelValue = 0; + + for (const tPt2di &aDiffPix : *aDImDiff) + { + aDiffImPixelValue = aDImDiff->GetV(aDiffPix); + aSumPixelValuesInDiffImage += aDiffImPixelValue; + if (aDiffImPixelValue > aMaxPixelValuesInDiffImage) + aMaxPixelValuesInDiffImage = aDiffImPixelValue; + } + StdOut() << "The average value of the difference image between the Pre and Post images is : " + << aSumPixelValuesInDiffImage / (tREAL8)aNumberOfPixelsInImage << std::endl; + StdOut() << "The maximum value of the difference image between the Pre and Post images is : " + << aMaxPixelValuesInDiffImage << std::endl; + } + + tPt2dr ApplyBarycenterTranslationFormulaToFilledPixel(const tPt2dr &aCurrentTranslationPointA, + const tPt2dr &aCurrentTranslationPointB, + const tPt2dr &aCurrentTranslationPointC, + const tDoubleVect &aVObs) + { + // apply current barycenter translation formula for x and y on current observations. + const tREAL8 aXTriCoord = aVObs[0] + aVObs[2] * aCurrentTranslationPointA.x() + aVObs[3] * aCurrentTranslationPointB.x() + + aVObs[4] * aCurrentTranslationPointC.x(); + const tREAL8 aYTriCoord = aVObs[1] + aVObs[2] * aCurrentTranslationPointA.y() + aVObs[3] * aCurrentTranslationPointB.y() + + aVObs[4] * aCurrentTranslationPointC.y(); + + const tPt2dr aCurrentTranslatedPixel = tPt2dr(aXTriCoord, aYTriCoord); + + return aCurrentTranslatedPixel; + } + + tPt2dr ApplyBarycenterTranslationFormulaToFilledPixel(const tPt2dr &aCurrentTranslationPointA, + const tPt2dr &aCurrentTranslationPointB, + const tPt2dr &aCurrentTranslationPointC, + const cPtInsideTriangles &aPixInsideTriangle) + { + const tPt2dr aCartesianCoordinates = aPixInsideTriangle.GetCartesianCoordinates(); + const cPt3dr aBarycenterCoordinates = aPixInsideTriangle.GetBarycenterCoordinates(); + // apply current barycenter translation formula for x and y on current observations. + const tREAL8 aXTriCoord = aCartesianCoordinates.x() + aBarycenterCoordinates.x() * aCurrentTranslationPointA.x() + + aBarycenterCoordinates.y() * aCurrentTranslationPointB.x() + aBarycenterCoordinates.z() * aCurrentTranslationPointC.x(); + const tREAL8 aYTriCoord = aCartesianCoordinates.y() + aBarycenterCoordinates.x() * aCurrentTranslationPointA.y() + + aBarycenterCoordinates.y() * aCurrentTranslationPointB.y() + aBarycenterCoordinates.z() * aCurrentTranslationPointC.y(); + + const tPt2dr aTranslatedPixel = tPt2dr(aXTriCoord, aYTriCoord); + + return aTranslatedPixel; + } + + tREAL8 ApplyBarycenterTranslationFormulaForTranslationRadiometry(const tREAL8 aCurrentRadTranslationPointA, + const tREAL8 aCurrentRadTranslationPointB, + const tREAL8 aCurrentRadTranslationPointC, + const tDoubleVect &aVObs) + { + const tREAL8 aCurentRadTranslation = aVObs[2] * aCurrentRadTranslationPointA + aVObs[3] * aCurrentRadTranslationPointB + + aVObs[4] * aCurrentRadTranslationPointC; + return aCurentRadTranslation; + } + + tREAL8 ApplyBarycenterTranslationFormulaForTranslationRadiometry(const tREAL8 aCurrentRadTranslationPointA, + const tREAL8 aCurrentRadTranslationPointB, + const tREAL8 aCurrentRadTranslationPointC, + const cPtInsideTriangles &aPixInsideTriangle) + { + const cPt3dr BarycenterCoordinateOfPoint = aPixInsideTriangle.GetBarycenterCoordinates(); + const tREAL8 aCurentRadTranslation = BarycenterCoordinateOfPoint.x() * aCurrentRadTranslationPointA + BarycenterCoordinateOfPoint.y() * aCurrentRadTranslationPointB + + BarycenterCoordinateOfPoint.z() * aCurrentRadTranslationPointC; + return aCurentRadTranslation; + } + + tREAL8 ApplyBarycenterTranslationFormulaForScalingRadiometry(const tREAL8 aCurrentRadScalingPointA, + const tREAL8 aCurrentRadScalingPointB, + const tREAL8 aCurrentRadScalingPointC, + const tDoubleVect &aVObs) + { + const tREAL8 aCurrentRadScaling = aVObs[2] * aCurrentRadScalingPointA + aVObs[3] * aCurrentRadScalingPointB + + aVObs[4] * aCurrentRadScalingPointC; + return aCurrentRadScaling; + } + + tREAL8 ApplyBarycenterTranslationFormulaForScalingRadiometry(const tREAL8 aCurrentRadScalingPointA, + const tREAL8 aCurrentRadScalingPointB, + const tREAL8 aCurrentRadScalingPointC, + const cPtInsideTriangles &aLastPixInsideTriangle) + { + const cPt3dr BarycenterCoordinateOfPoint = aLastPixInsideTriangle.GetBarycenterCoordinates(); + const tREAL8 aCurrentRadScaling = BarycenterCoordinateOfPoint.x() * aCurrentRadScalingPointA + BarycenterCoordinateOfPoint.y() * aCurrentRadScalingPointB + + BarycenterCoordinateOfPoint.z() * aCurrentRadScalingPointC; + return aCurrentRadScaling; + } + + void ReadFileNameLoadData(const std::string &aImageFilename, tIm &aImage, + tDIm *&aDataImage, tPt2di &aSzIm) + { + aImage = tIm::FromFile(aImageFilename); + + aDataImage = &aImage.DIm(); + aSzIm = aDataImage->Sz(); + } + + void LoadPrePostImageAndData(tIm &aCurIm, tDIm *&aCurDIm, const std::string &aPreOrPostImage, tIm &aImPre, tIm &aImPost) + { + (aPreOrPostImage == "pre") ? aCurIm = aImPre : aCurIm = aImPost; + aCurDIm = &aCurIm.DIm(); + } + + void InitialiseDisplacementMaps(tPt2di &aSzIm, tIm &aImDispMap, tDIm *&aDImDispMap, tPt2di &aSzImDispMap) + { + aImDispMap = tIm(aSzIm, 0, eModeInitImage::eMIA_Null); + aDImDispMap = &aImDispMap.DIm(); + aSzImDispMap = aDImDispMap->Sz(); + } + + bool ManageDifferentCasesOfEndIterations(const int aIterNumber, const int aNumberOfScales, const int aNumberOfEndIterations, + bool aIsLastIters, tIm &aImPre, tIm &aImPost, tIm &aCurPreIm, tDIm *&aCurPreDIm, + tIm &aCurPostIm, tDIm *&aCurPostDIm) + { + switch (aNumberOfEndIterations) + { + case 1: // one last iteration + if (aIterNumber == aNumberOfScales) + { + aIsLastIters = true; + LoadPrePostImageAndData(aCurPreIm, aCurPreDIm, "pre", aImPre, aImPost); + LoadPrePostImageAndData(aCurPostIm, aCurPostDIm, "post", aImPre, aImPost); + } + break; + case 2: // two last iterations + if ((aIterNumber == aNumberOfScales) || (aIterNumber == aNumberOfScales + aNumberOfEndIterations - 1)) + { + aIsLastIters = true; + LoadPrePostImageAndData(aCurPreIm, aCurPreDIm, "pre", aImPre, aImPost); + LoadPrePostImageAndData(aCurPostIm, aCurPostDIm, "post", aImPre, aImPost); + } + break; + case 3: // three last iterations + if ((aIterNumber == aNumberOfScales) || (aIterNumber == aNumberOfScales + aNumberOfEndIterations - 2) || + (aIterNumber == aNumberOfScales + aNumberOfEndIterations - 1)) + { + aIsLastIters = true; + LoadPrePostImageAndData(aCurPreIm, aCurPreDIm, "pre", aImPre, aImPost); + LoadPrePostImageAndData(aCurPostIm, aCurPostDIm, "post", aImPre, aImPost); + } + break; + default: // default is two last iterations + if ((aIterNumber == aNumberOfScales) || (aIterNumber == aNumberOfScales + aNumberOfEndIterations - 1)) + { + aIsLastIters = true; + LoadPrePostImageAndData(aCurPreIm, aCurPreDIm, "pre", aImPre, aImPost); + LoadPrePostImageAndData(aCurPostIm, aCurPostDIm, "post", aImPre, aImPost); + } + break; + } + return aIsLastIters; + } + + void FillDisplacementMapsAndOutputImage(const cPtInsideTriangles &aLastPixInsideTriangle, + const tPt2dr &aLastTranslatedFilledPoint, + const tREAL8 aLastRadiometryTranslation, + const tREAL8 aLastRadiometryScaling, tPt2di &aSzImOut, + tDIm *&aDImDepX, tDIm *&aDImDepY, tDIm *&aDImOut) + { + const tREAL8 aLastXCoordinate = aLastPixInsideTriangle.GetCartesianCoordinates().x(); + const tREAL8 aLastYCoordinate = aLastPixInsideTriangle.GetCartesianCoordinates().y(); + const tREAL8 aLastPixelValue = aLastPixInsideTriangle.GetPixelValue(); + + const tPt2di aLastCoordinate = tPt2di(aLastXCoordinate, aLastYCoordinate); + aDImDepX->SetV(aLastCoordinate, + aLastTranslatedFilledPoint.x() - aLastXCoordinate); + aDImDepY->SetV(aLastCoordinate, + aLastTranslatedFilledPoint.y() - aLastYCoordinate); + const tREAL8 aLastXTranslatedCoord = aLastXCoordinate + aDImDepX->GetV(aLastCoordinate); + const tREAL8 aLastYTranslatedCoord = aLastYCoordinate + aDImDepY->GetV(aLastCoordinate); + + const tREAL8 aLastRadiometryValue = aLastRadiometryScaling * aLastPixelValue + + aLastRadiometryTranslation; + + // Build image with intensities displaced + // deal with different cases of pixel being translated out of image + if (aLastXTranslatedCoord < 0 && aLastYTranslatedCoord < 0) + aDImOut->SetV(aLastCoordinate, aDImOut->GetV(tPt2di(0, 0))); + else if (aLastXTranslatedCoord >= aSzImOut.x() && aLastYTranslatedCoord >= aSzImOut.y()) + aDImOut->SetV(aLastCoordinate, aDImOut->GetV(tPt2di(aSzImOut.x() - 1, aSzImOut.y() - 1))); + else if (aLastXTranslatedCoord < 0 && aLastYTranslatedCoord >= aSzImOut.y()) + aDImOut->SetV(aLastCoordinate, aDImOut->GetV(tPt2di(0, aSzImOut.y() - 1))); + else if (aLastXTranslatedCoord >= aSzImOut.x() && aLastYTranslatedCoord < 0) + aDImOut->SetV(aLastCoordinate, aDImOut->GetV(tPt2di(aSzImOut.x() - 1, 0))); + else if (aLastXTranslatedCoord >= 0 && aLastXTranslatedCoord < aSzImOut.x() && + aLastYTranslatedCoord < 0) + aDImOut->SetV(aLastCoordinate, aDImOut->GetV(tPt2di(aLastXTranslatedCoord, 0))); + else if (aLastXTranslatedCoord >= 0 && aLastXTranslatedCoord < aSzImOut.x() && + aLastYTranslatedCoord > aSzImOut.y()) + aDImOut->SetV(aLastCoordinate, aDImOut->GetV(tPt2di(aLastXTranslatedCoord, aSzImOut.y() - 1))); + else if (aLastYTranslatedCoord >= 0 && aLastYTranslatedCoord < aSzImOut.y() && + aLastXTranslatedCoord < 0) + aDImOut->SetV(aLastCoordinate, aDImOut->GetV(tPt2di(0, aLastYTranslatedCoord))); + else if (aLastYTranslatedCoord >= 0 && aLastYTranslatedCoord < aSzImOut.y() && + aLastXTranslatedCoord > aSzImOut.x()) + aDImOut->SetV(aLastCoordinate, aDImOut->GetV(tPt2di(aSzImOut.x() - 1, aLastYTranslatedCoord))); + else + // at the translated pixel the untranslated pixel value is given computed with the right radiometry values + aDImOut->SetV(tPt2di(aLastXTranslatedCoord, aLastYTranslatedCoord), aLastRadiometryValue); + } + + void FillOutputImageRadiometry(const cPtInsideTriangles &aLastPixInsideTriangle, + const tREAL8 aLastRadiometryTranslation, + const tREAL8 aLastRadiometryScaling, + tDIm *&aDImOut) + { + const tREAL8 aLastXCoordinate = aLastPixInsideTriangle.GetCartesianCoordinates().x(); + const tREAL8 aLastYCoordinate = aLastPixInsideTriangle.GetCartesianCoordinates().y(); + + const tPt2di aLastCoordinate = tPt2di(aLastXCoordinate, aLastYCoordinate); + + const tREAL8 aLastRadiometryValue = aLastRadiometryScaling * aLastPixInsideTriangle.GetPixelValue() + + aLastRadiometryTranslation; + + // Build image with radiometric intensities + aDImOut->SetV(aLastCoordinate, aLastRadiometryValue); + } + + void FillDisplacementMapsTranslation(const cPtInsideTriangles &aLastPixInsideTriangle, + const tPt2dr &aLastTranslatedFilledPoint, tPt2di &aSzImOut, + tDIm *&aDImDepX, tDIm *&aDImDepY, tDIm *&aDImOut) + { + const tPt2dr aLastRealCoordinate = aLastPixInsideTriangle.GetCartesianCoordinates(); + const tREAL8 aLastXCoordinate = aLastRealCoordinate.x(); + const tREAL8 aLastYCoordinate = aLastRealCoordinate.y(); + const tREAL8 aLastPixelValue = aLastPixInsideTriangle.GetPixelValue(); + + const tPt2di aLastIntCoordinate = tPt2di(aLastXCoordinate, aLastYCoordinate); + + aDImDepX->SetV(aLastIntCoordinate, + aLastTranslatedFilledPoint.x() - aLastXCoordinate); + aDImDepY->SetV(aLastIntCoordinate, + aLastTranslatedFilledPoint.y() - aLastYCoordinate); + + tREAL8 aLastXTranslatedCoord = aLastXCoordinate + aDImDepX->GetV(aLastIntCoordinate); + tREAL8 aLastYTranslatedCoord = aLastYCoordinate + aDImDepY->GetV(aLastIntCoordinate); + if (aDImDepX->InsideBL(aLastRealCoordinate)) + aLastXTranslatedCoord = aLastXCoordinate + aDImDepX->GetVBL(aLastRealCoordinate); + if (aDImDepY->InsideBL(aLastRealCoordinate)) + aLastYTranslatedCoord = aLastYCoordinate + aDImDepY->GetVBL(aLastRealCoordinate); + + // Build image with intensities displaced + // deal with different cases of pixel being translated out of image + if (aLastXTranslatedCoord < 0 && aLastYTranslatedCoord < 0) + aDImOut->SetV(aLastIntCoordinate, aDImOut->GetV(tPt2di(0, 0))); + else if (aLastXTranslatedCoord >= aSzImOut.x() && aLastYTranslatedCoord >= aSzImOut.y()) + aDImOut->SetV(aLastIntCoordinate, aDImOut->GetV(tPt2di(aSzImOut.x() - 1, aSzImOut.y() - 1))); + else if (aLastXTranslatedCoord < 0 && aLastYTranslatedCoord >= aSzImOut.y()) + aDImOut->SetV(aLastIntCoordinate, aDImOut->GetV(tPt2di(0, aSzImOut.y() - 1))); + else if (aLastXTranslatedCoord >= aSzImOut.x() && aLastYTranslatedCoord < 0) + aDImOut->SetV(aLastIntCoordinate, aDImOut->GetV(tPt2di(aSzImOut.x() - 1, 0))); + else if (aLastXTranslatedCoord >= 0 && aLastXTranslatedCoord < aSzImOut.x() && + aLastYTranslatedCoord < 0) + aDImOut->SetV(aLastIntCoordinate, aDImOut->GetV(tPt2di(aLastXTranslatedCoord, 0))); + else if (aLastXTranslatedCoord >= 0 && aLastXTranslatedCoord < aSzImOut.x() && + aLastYTranslatedCoord > aSzImOut.y()) + aDImOut->SetV(aLastIntCoordinate, aDImOut->GetV(tPt2di(aLastXTranslatedCoord, aSzImOut.y() - 1))); + else if (aLastYTranslatedCoord >= 0 && aLastYTranslatedCoord < aSzImOut.y() && + aLastXTranslatedCoord < 0) + aDImOut->SetV(aLastIntCoordinate, aDImOut->GetV(tPt2di(0, aLastYTranslatedCoord))); + else if (aLastYTranslatedCoord >= 0 && aLastYTranslatedCoord < aSzImOut.y() && + aLastXTranslatedCoord > aSzImOut.x()) + aDImOut->SetV(aLastIntCoordinate, aDImOut->GetV(tPt2di(aSzImOut.x() - 1, aLastYTranslatedCoord))); + else + // at the translated pixel the untranslated pixel value is given + aDImOut->SetV(tPt2di(aLastXTranslatedCoord, aLastYTranslatedCoord), aLastPixelValue); + } + + void FillDiffDisplacementMap(tDIm *&aDImDispMap, tDIm *&aDImDiffMap, + tDIm *&aDImTranslatedDispMap, + const cPtInsideTriangles &aPixInsideTriangle, + const tREAL8 aPixInsideTriangleCoord, + const tREAL8 aTranslatedDispMapPointCoord, + const bool aComputeDiffDispMaps, const bool aComputeInterpTranslationDispMaps) + { + const tPt2di aIntCoordinate = tPt2di(aPixInsideTriangle.GetCartesianCoordinates().x(), aPixInsideTriangle.GetCartesianCoordinates().y()); + const tREAL8 aDiffBarycentricInterpTranslation = aTranslatedDispMapPointCoord - aPixInsideTriangleCoord; + if (aComputeDiffDispMaps) + // compute difference between value of pixel in ground-truth map and value of barycentric interpolated pixel from displacement map + aDImDiffMap->SetV(aIntCoordinate, std::abs(aDiffBarycentricInterpTranslation - aPixInsideTriangle.GetPixelValue())); + if (aComputeInterpTranslationDispMaps) + // Sets value to difference between pixel's original position in displacement map and interpolated value by barycentric interpolation formula + aDImTranslatedDispMap->SetV(aIntCoordinate, aDiffBarycentricInterpTranslation); + } + + void DisplayLastUnknownValuesAndComputeStatistics(const tDenseVect &aVFinalSol, const tDenseVect &aVInitSol) + { + tREAL8 aMaxFirstUnk = 0, aMinFirstUnk = 0, aMeanFirstUnk = 0, aVarianceMeanFirstUnk = 0; // aVarFirstUnk = 0; + tREAL8 aMaxSecondUnk = 0, aMinSecondUnk = 0, aMeanSecondUnk = 0, aVarianceMeanSecondUnk = 0; // aVarSecondUnk = 0; + const tREAL8 aVecSolSz = aVFinalSol.DIm().Sz(); + const tREAL8 aHalfVecSolSz = aVecSolSz / 2; + + for (int aFinalUnk = 0; aFinalUnk < aVecSolSz; aFinalUnk++) + { + const tREAL8 aFinalSolValue = aVFinalSol(aFinalUnk); + const tREAL8 aInitSolValue = aVInitSol(aFinalUnk); + StdOut() << aFinalSolValue << " " << aInitSolValue << " "; + if (aFinalUnk % 2 == 1 && aFinalUnk != 0) + StdOut() << std::endl; + + if (aFinalUnk % 2 == 0) + { + aMeanFirstUnk += aFinalSolValue; + if (aFinalSolValue > aMaxFirstUnk) + aMaxFirstUnk = aFinalSolValue; + if (aFinalSolValue < aMinFirstUnk) + aMinFirstUnk = aFinalSolValue; + } + else + { + aMeanSecondUnk += aFinalSolValue; + if (aFinalSolValue > aMaxSecondUnk) + aMaxSecondUnk = aFinalSolValue; + if (aFinalSolValue < aMinSecondUnk) + aMinSecondUnk = aFinalSolValue; + } + } + + aMeanFirstUnk /= aHalfVecSolSz; + aMeanSecondUnk /= aHalfVecSolSz; + + /* + for (tREAL8 var: aVFinalSol) + { + if (aFinalUnk % 2 == 0) + aVarFirstUnk += (var - aMeanFirstUnk) * (var - aMeanFirstUnk); + if (aFinalUnk % 2 == 0) + aVarSecondUnk += (var - aMeanSecondUnk) * (var - aMeanSecondUnk); + } + + aVarFirstUnk /= (aHalfVecSolSz - 1); + aVarSecondUnk /= (aHalfVecSolSz - 1); + */ + std::vector aVarianceVectorFirstUnk; + std::vector aVarianceVectorSecondUnk; + for (int aSolNumber = 0; aSolNumber < aVecSolSz; aSolNumber++) + { + const tREAL8 aFinalSolValue = aVFinalSol(aSolNumber); + if (aSolNumber % 2 == 0) + aVarianceVectorFirstUnk.push_back(std::abs(aFinalSolValue - aMeanFirstUnk) * std::abs(aFinalSolValue - aMeanFirstUnk)); + else + aVarianceVectorSecondUnk.push_back(std::abs(aFinalSolValue - aMeanSecondUnk) * std::abs(aFinalSolValue - aMeanSecondUnk)); + } + + for (int aSolNumber = 0; aSolNumber < aHalfVecSolSz; aSolNumber++) + { + if (aSolNumber % 2 == 0) + aVarianceMeanFirstUnk += aVarianceVectorFirstUnk[aSolNumber]; + else + aVarianceMeanSecondUnk += aVarianceVectorSecondUnk[aSolNumber]; + } + + aVarianceMeanFirstUnk /= aHalfVecSolSz; + aVarianceMeanSecondUnk /= aHalfVecSolSz; + + StdOut() << "The maximum value for the first unknown is : " << aMaxFirstUnk << " and the minimum value is : " + << aMinFirstUnk << std::endl; + StdOut() << "The maximum value for the second unknown is : " << aMaxSecondUnk << " and the minimum value is : " + << aMinSecondUnk << std::endl; + StdOut() << "The mean value for the first unknown is : " << aMeanFirstUnk << " and the standard deviation value is : " + << std::sqrt(aVarianceMeanFirstUnk) << std::endl; + StdOut() << "The mean value for the second unknown is : " << aMeanSecondUnk << " and the standard deviation value is : " + << std::sqrt(aVarianceMeanSecondUnk) << std::endl; + } + + void DisplayLastUnknownValues(const tDenseVect &aVFinalSol, const bool aDisplayLastRadiometryValues, + const bool aDisplayLastTranslationValues) + { + if (aDisplayLastRadiometryValues && aDisplayLastTranslationValues) + { + for (int aFinalUnk = 0; aFinalUnk < aVFinalSol.DIm().Sz(); aFinalUnk++) + { + StdOut() << aVFinalSol(aFinalUnk) << " "; + if (aFinalUnk % 4 == 3 && aFinalUnk != 0) + StdOut() << std::endl; + } + } + if (aDisplayLastRadiometryValues && !aDisplayLastTranslationValues) + { + for (int aFinalUnk = 0; aFinalUnk < aVFinalSol.DIm().Sz(); aFinalUnk++) + { + if (aFinalUnk % 4 == 0 || aFinalUnk % 4 == 1) + StdOut() << aVFinalSol(aFinalUnk) << " "; + if (aFinalUnk % 4 == 3 && aFinalUnk != 0) + StdOut() << std::endl; + } + } + else if (aDisplayLastRadiometryValues && !aDisplayLastTranslationValues) + { + for (int aFinalUnk = 0; aFinalUnk < aVFinalSol.DIm().Sz(); aFinalUnk++) + { + if (aFinalUnk % 4 == 2 || aFinalUnk % 4 == 3) + StdOut() << aVFinalSol(aFinalUnk) << " "; + if (aFinalUnk % 4 == 3 && aFinalUnk != 0) + StdOut() << std::endl; + } + } + } + +}; // namespace MMVII \ No newline at end of file diff --git a/MMVII/src/MeshDisplacement/TriangleDeformationUtils.h b/MMVII/src/MeshDisplacement/TriangleDeformationUtils.h new file mode 100644 index 0000000000..145592346d --- /dev/null +++ b/MMVII/src/MeshDisplacement/TriangleDeformationUtils.h @@ -0,0 +1,206 @@ +#ifndef _TRIANGLEDEFORMATIONUTILS_H_ +#define _TRIANGLEDEFORMATIONUTILS_H_ + +#include "MMVII_Geom2D.h" + +namespace MMVII +{ + typedef cIm2D tIm; + typedef cDataIm2D tDIm; + typedef cDenseVect tDenseVect; + typedef std::vector tDoubleVect; + + //----------------------------------------// + + /****************************************/ + /* */ + /* cPtInsideTriangles */ + /* */ + /****************************************/ + + class cPtInsideTriangles + { + public: + cPtInsideTriangles(const cTriangle2DCompiled &aCompTri, // a compiled triangle + const std::vector &aVectorFilledwithInsidePixels, // vector containing pixels inside triangles + const size_t aFilledPixel, // a counter that is looping over pixels in triangles + cDataIm2D *&aDIm); // image + cPt3dr GetBarycenterCoordinates() const; // Accessor for barycenter coordinates + tPt2dr GetCartesianCoordinates() const; // Accessor for cartesian coordinates + tREAL8 GetPixelValue() const; // Accessor for pixel value at coordinates + + private: + cPt3dr mBarycenterCoordinatesOfPixel; // Barycentric coordinates of pixel. + tPt2dr mFilledIndices; // 2D cartesian coordinates of pixel. + tREAL8 mValueOfPixel; // Intensity in image at pixel. + }; + + /****************************************/ + /* */ + /* cNodeOfTriangles */ + /* */ + /****************************************/ + + class cNodeOfTriangles + { + typedef cDenseVect tDenseVect; + typedef std::vector tIntVect; + + public: + cNodeOfTriangles(); // default constructor + cNodeOfTriangles(const tDenseVect &aVecSol, // Current solution vector + const tIntVect &aIndicesVec, // Indices of current triangle in solution vector + const int adXIndex, // Index for current x-displacement in solution vector + const int adYIndex, // Index for current y-displacement in solution vector + const int aRadTrIndex, // Index for current radiometry translation in solution vector + const int aRadScIndex, // Index for current radiometry scaling in solution vector + const tTri2dr &aTri, // Current triangle + const int aPointNumberInTri); // Index of point in triangle : 0, 1 or 2 + + tPt2dr GetInitialNodeCoordinates() const; // Accessor + tPt2dr GetCurrentXYDisplacementValues() const; // Accessor + tREAL8 GetCurrentRadiometryTranslation() const; // Accessor + tREAL8 &GetCurrentRadiometryTranslation(); // Accessor + tREAL8 GetCurrentRadiometryScaling() const; // Accessor + tREAL8 &GetCurrentRadiometryScaling(); // Accessor + + private: + tPt2dr mInitialNodeCoordinates; // Coordinates of knot before displacement + tPt2dr mCurXYDisplacementVector; // Vector containing current dx, dy displacement values + tREAL8 mCurRadSc; // Current radiometry scaling value + tREAL8 mCurRadTr; // Current radiometry translation value + }; + + //-------------------------------------------// + + // Build uniform vector of coordinates and apply Delaunay triangulation + void BuildUniformRandomVectorAndApplyDelaunay(const int aNumberOfPointsToGenerate, const int aRandomUniformLawUpperBoundLines, + const int aRandomUniformLawUpperBoundCols, cTriangulation2D &aDelaunayTri); + // Build points vector that have coordinates that make up a grid made of rectangles + void GeneratePointsForRectangleGrid(const int aNumberOfPoints, const int aGridSizeLines, + const int aGridSizeCols, cTriangulation2D &aDelaunayTri); + // Generate coordinates from uniform law for Delaunay triangulation application + void DefineValueLimitsForPointGenerationAndBuildGrid(const int aNumberOfPointsToGenerate, int aRandomUniformLawUpperBoundLines, + int aRandomUniformLawUpperBoundCols, cTriangulation2D &aDelaunayTri, + const tPt2di &aSzImPre, const bool aBuildUniformVector); + // Initialise values of unknowns at the beginning of optimisation process after user has input information + void InitialisationAfterExe(const cTriangulation2D &aDelaunayTri, + cResolSysNonLinear *&aSys, + const bool aUserInitialisation, + const tREAL8 aXTranslationInitVal, + const tREAL8 aYTranslationInitVal, + const tREAL8 aRadTranslationInitVal, + const tREAL8 aRadScaleInitVal); + // Initialise problem after user has input information for translation + void InitialisationAfterExeTranslation(const cTriangulation2D &aDelaunayTri, + cResolSysNonLinear *&aSysTranslation, + const bool aUserInitialisation, + const tREAL8 aXTranslationInitVal, + const tREAL8 aYTranslationInitVal); + // Initialise unknowns values with values obtained at previous exection + void InitialiseWithPreviousExecutionValuesTranslation(const cTriangulation2D &aDelTri, + cResolSysNonLinear *&aSysTranslation, + const std::string &aNameDepXFile, tIm &aImDepX, + tDIm *&aDImDepX, tPt2di &aSzImDepX, + const std::string &aNameDepYFile, tIm &aImDepY, + tDIm *&aDImDepY, tPt2di &aSzImDepY, + const std::string &aNameCorrelationMask, + tIm &aImCorrelationMask, tDIm *&aDImCorrelationMask, + tPt2di &aSzCorrelationMask); + // Initialise unknowns values with values obtained at previous execution + void InitialiseWithPreviousExecutionValues(const cTriangulation2D &aDelTri, + cResolSysNonLinear *&aSys, + const std::string &aNameDepXFile, tIm &aImDepX, + tDIm *&aDImDepX, tPt2di &aSzImDepX, + const std::string &aNameDepYFile, tIm &aImDepY, + tDIm *&aDImDepY, tPt2di &aSzImDepY, + const std::string &aNameCorrelationMask, + tIm &aImCorrelationMask, tDIm *&aDImCorrelationMask, + tPt2di &aSzCorrelationMask); + // Initialise problem after user has input information for radiometry + void InitialisationAfterExeRadiometry(const cTriangulation2D &aDelaunayTri, + cResolSysNonLinear *&aSysRadiometry, + const bool aUserInitialisation, + const tREAL8 aRadTranslationInitVal, + const tREAL8 aRadScaleInitVal); + // Check whether point has a correlation value or not thanks to MMVI correlation mask + bool CheckValidCorrelationValue(tDIm *aMask, const cNodeOfTriangles &aPtOfTri); + // Return correct value for initalisation depending on mask + tREAL8 ReturnCorrectInitialisationValue(tDIm *aMask, tDIm *aIntermediateDispMap, + const cNodeOfTriangles &aPtOfTri, const tREAL8 aValueToReturnIfFalse); + // Check if interpolated bilinear value in displacement map can be returned or if integer value is needed + tPt2dr CheckReturnOfBilinearValue(tDIm *&aDImDispXMap, tDIm *&aDImDispYMap, + const tPt2dr &aRealCoordPoint, const tPt2di &aIntCoordPoint); + // Construct difference image and compute average and max pixel value on ths image + void SubtractPrePostImageAndComputeAvgAndMax(tIm &aImDiff, tDIm *aDImDiff, tDIm *aDImPre, + tDIm *aDImPost, tPt2di &aSzImPre); + // Read image filename and loads into MMVII data + void ReadFileNameLoadData(const std::string &aImageFilename, tIm &aImage, + tDIm *&aDataImage, tPt2di &aSzIm); + // Loads current pre and post images + void LoadPrePostImageAndData(tIm &aCurIm, tDIm *&aCurDIm, const std::string &aPreOrPostImage, tIm &aImPre, tIm &aImPost); + // Initialise displacement maps with null coefficients + void InitialiseDisplacementMaps(tPt2di &aSzIm, tIm &aImDispMap, tDIm *&aDImDispMap, tPt2di &aSzImDispMap); + // Load image and data according to number of iterations to optimise on original image + bool ManageDifferentCasesOfEndIterations(const int aIterNumber, const int aNumberOfScales, const int aNumberOfEndIterations, + bool aIsLastIters, tIm &aImPre, tIm &aImPost, tIm &aCurPreIm, tDIm *&aCurPreDIm, + tIm &aCurPostIm, tDIm *&aCurPostDIm); + // Apply barycentric translation formula to current translation values with observations + tPt2dr ApplyBarycenterTranslationFormulaToFilledPixel(const tPt2dr &aCurrentTranslationPointA, + const tPt2dr &aCurrentTranslationPointB, + const tPt2dr &aCurrentTranslationPointC, + const tDoubleVect &aVObs); + // Apply barycentric translation formula to current translation values with observations with inside pixels + tPt2dr ApplyBarycenterTranslationFormulaToFilledPixel(const tPt2dr &aLastTranslationPointA, + const tPt2dr &aLastTranslationPointB, + const tPt2dr &aLastTranslationPointC, + const cPtInsideTriangles &aLastPixInsideTriangle); + // Apply barycentric translation formula to current radiometric translation values + tREAL8 ApplyBarycenterTranslationFormulaForTranslationRadiometry(const tREAL8 aCurrentRadTranslationPointA, + const tREAL8 aCurrentRadTranslationPointB, + const tREAL8 aCurrentRadTranslationPointC, + const tDoubleVect &aVObs); + tREAL8 ApplyBarycenterTranslationFormulaForTranslationRadiometry(const tREAL8 aCurrentRadTranslationPointA, + const tREAL8 aCurrentRadTranslationPointB, + const tREAL8 aCurrentRadTranslationPointC, + const cPtInsideTriangles &aPixInsideTriangle); + // Apply barycentric translation formula to current radiometric scaling values + tREAL8 ApplyBarycenterTranslationFormulaForScalingRadiometry(const tREAL8 aCurrentRadScalingPointA, + const tREAL8 aCurrentRadScalingPointB, + const tREAL8 aCurrentRadScalingPointC, + const tDoubleVect &aVObs); + tREAL8 ApplyBarycenterTranslationFormulaForScalingRadiometry(const tREAL8 aCurrentRadScalingPointA, + const tREAL8 aCurrentRadScalingPointB, + const tREAL8 aCurrentRadScalingPointC, + const cPtInsideTriangles &aLastPixInsideTriangle); + // Produces output image with computed radiometry and displacement maps with computed translations + void FillDisplacementMapsAndOutputImage(const cPtInsideTriangles &aLastPixInsideTriangle, + const tPt2dr &aLastTranslatedFilledPoint, + const tREAL8 aLastRadiometryTranslation, + const tREAL8 aLastRadiometryScaling, tPt2di &aSzImOut, + tDIm *&aDImDepX, tDIm *&aDImDepY, tDIm *&aDImOut); + // Produces output image when computing just radiometry + void FillOutputImageRadiometry(const cPtInsideTriangles &aLastPixInsideTriangle, + const tREAL8 aLastRadiometryTranslation, + const tREAL8 aLastRadiometryScaling, + tDIm *&aDImOut); + // Produces x and y displacement maps for computing just translation + void FillDisplacementMapsTranslation(const cPtInsideTriangles &aLastPixInsideTriangle, + const tPt2dr &aLastTranslatedFilledPoint, tPt2di &aSzImOut, + tDIm *&aDImDepX, tDIm *&aDImDepY, tDIm *&aDImOut); + // Fills displacement map with difference between ground truth and interpolated pixel in ground truth + void FillDiffDisplacementMap(tDIm *&aDImDispMap, tDIm *&aDImDiffMap, + tDIm *&aDImTranslatedDispMap, + const cPtInsideTriangles &aPixInsideTriangle, + const tREAL8 aPixInsideTriangleCoord, + const tREAL8 aTranslatedRealDispMapPointCoord, + const bool aComputeDiffDispMaps, const bool aComputeInterpTranslationDispMaps); + // Display last values of unknowns and compute statistics on these values : min, mean, max and variance + void DisplayLastUnknownValuesAndComputeStatistics(const tDenseVect &aVFinalSol, const tDenseVect &aVInitSol); + // Display values of unknowns at last iteration of optimisation process + void DisplayLastUnknownValues(const tDenseVect &aVFinalSol, const bool aDisplayLastRadiometryValues, + const bool aDisplayLastTranslationValues); + +} + +#endif // _TRIANGLEDEFORMATIONUTILS_H_ \ No newline at end of file diff --git a/MMVII/src/SymbDerGen/Formulas_TrianglesDeform.h b/MMVII/src/SymbDerGen/Formulas_TrianglesDeform.h index 053cbad86d..8d0bb55f17 100644 --- a/MMVII/src/SymbDerGen/Formulas_TrianglesDeform.h +++ b/MMVII/src/SymbDerGen/Formulas_TrianglesDeform.h @@ -23,9 +23,9 @@ namespace MMVII { } - static const std::vector VNamesUnknowns() { return std::vector{"GeomTrXPointA", "GeomTrYPointA", "RadTranslationPointA", "RadScalingPointA", - "GeomTrXPointB", "GeomTrYPointB", "RadTranslationPointB", "RadScalingPointB", - "GeomTrXPointC", "GeomTrYPointC", "RadTranslationPointC", "RadScalingPointC"}; } + static const std::vector VNamesUnknowns() { return Append(std::vector{"GeomTrXPointA", "GeomTrYPointA", "RadTranslationPointA", "RadScalingPointA"}, + Append(std::vector{"GeomTrXPointB", "GeomTrYPointB", "RadTranslationPointB", "RadScalingPointB"}, + std::vector{"GeomTrXPointC", "GeomTrYPointC", "RadTranslationPointC", "RadScalingPointC"})); } static const std::vector VNamesObs() { return Append( @@ -83,73 +83,6 @@ namespace MMVII } }; - class cTriangleDeformationTrRad - { - public: - cTriangleDeformationTrRad() - { - } - - static const std::vector VNamesUnknowns() { return std::vector{"GeomTrXPointA", "GeomTrYPointA", "RadTranslationPointA", "RadScalingPointA", - "GeomTrXPointB", "GeomTrYPointB", "RadTranslationPointB", "RadScalingPointB", - "GeomTrXPointC", "GeomTrYPointC", "RadTranslationPointC", "RadScalingPointC"}; } - static const std::vector VNamesObs() - { - return Append( - std::vector{"PixelCoordinatesX", "PixelCoordinatesY", "AlphaCoordPixel", "BetaCoordPixel", "GammaCoordPixel", "IntensityImPre"}, - FormalBilinIm2D_NameObs("T") // 6 obs for bilinear interpol of Im - ); - } - - std::string FormulaName() const { return "TriangleDeformationTrRad"; } - - template - static std::vector formula( - const std::vector &aVUnk, - const std::vector &aVObs) - { - - // extract observation - const auto &aXCoordinate = aVObs[0]; - const auto &aYCoordinate = aVObs[1]; - const auto &aAlphaCoordinate = aVObs[2]; - const auto &aBetaCoordinate = aVObs[3]; - const auto &aGammaCoordinate = aVObs[4]; - const auto &aIntensityImPre = aVObs[5]; - - // extract unknowns - const auto &aGeomTrXPointA = aVUnk[0]; - const auto &aGeomTrYPointA = aVUnk[1]; - const auto &aRadTranslationPointA = aVUnk[2]; - const auto &aRadScalingPointA = aVUnk[3]; - const auto &aGeomTrXPointB = aVUnk[4]; - const auto &aGeomTrYPointB = aVUnk[5]; - const auto &aRadTranslationPointB = aVUnk[6]; - const auto &aRadScalingPointB = aVUnk[7]; - const auto &aGeomTrXPointC = aVUnk[8]; - const auto &aGeomTrYPointC = aVUnk[9]; - const auto &aRadTranslationPointC = aVUnk[10]; - const auto &aRadScalingPointC = aVUnk[11]; - - // Apply barycentric translation formula to coordinates - auto aXTri = aXCoordinate + aAlphaCoordinate * aGeomTrXPointA + aBetaCoordinate * aGeomTrXPointB + aGammaCoordinate * aGeomTrXPointC; - auto aYTri = aYCoordinate + aAlphaCoordinate * aGeomTrYPointA + aBetaCoordinate * aGeomTrYPointB + aGammaCoordinate * aGeomTrYPointC; - - // Apply barycentric interpolation to radiometric factors - auto aRadTranslation = aAlphaCoordinate * aRadTranslationPointA + aBetaCoordinate * aRadTranslationPointB + aGammaCoordinate * aRadTranslationPointC; - auto aRadScaling = aAlphaCoordinate * aRadScalingPointA + aBetaCoordinate * aRadScalingPointB + aGammaCoordinate * aRadScalingPointC; - - // compute formula of bilinear interpolation - auto aBilinearValueTri = FormalBilinTri_Formula(aVObs, TriangleDisplacement_NbObs, aXTri, aYTri); - - // Take into account radiometry in minimisation process - auto aRadiometryValueTri = aRadScaling * aBilinearValueTri + aRadTranslation; - - // residual is simply the difference between values in before image and estimated value in new image - return {aIntensityImPre - aRadiometryValueTri}; - } - }; - class cTriangleDeformationTranslation { public: @@ -259,66 +192,6 @@ namespace MMVII } }; -class cTriangleDeformationRad - { - public: - cTriangleDeformationRad() - { - } - - static const std::vector VNamesUnknowns() { return Append(std::vector{"RadTranslationPointA", "RadScalingPointA"}, - std::vector{"RadTranslationPointB", "RadScalingPointB"}, - std::vector{"RadTranslationPointC", "RadScalingPointC"}); } - - static const std::vector VNamesObs() - { - return Append( - std::vector{"PixelCoordinatesX", "PixelCoordinatesY", "AlphaCoordPixel", "BetaCoordPixel", "GammaCoordPixel", "IntensityImPre"}, - FormalBilinIm2D_NameObs("T") // 6 obs for bilinear interpol of Im - ); - } - - std::string FormulaName() const { return "TriangleDeformationRad"; } - - template - static std::vector formula( - const std::vector &aVUnk, - const std::vector &aVObs) - { - // extract observation - const auto &aXCoordinate = aVObs[0]; - const auto &aYCoordinate = aVObs[1]; - const auto &aAlphaCoordinate = aVObs[2]; - const auto &aBetaCoordinate = aVObs[3]; - const auto &aGammaCoordinate = aVObs[4]; - const auto &aIntensityImPre = aVObs[5]; - - // extract unknowns - const auto &aRadTranslationPointA = aVUnk[0]; - const auto &aRadScalingPointA = aVUnk[1]; - const auto &aRadTranslationPointB = aVUnk[2]; - const auto &aRadScalingPointB = aVUnk[3]; - const auto &aRadTranslationPointC = aVUnk[4]; - const auto &aRadScalingPointC = aVUnk[5]; - - // Apply barycentric interpolation to radiometric factors - auto aRadTranslation = aAlphaCoordinate * aRadTranslationPointA + aBetaCoordinate * aRadTranslationPointB + aGammaCoordinate * aRadTranslationPointC; - auto aRadScaling = aAlphaCoordinate * aRadScalingPointA + aBetaCoordinate * aRadScalingPointB + aGammaCoordinate * aRadScalingPointC; - - // SymbPrint(aRadTranslation, "RadTranslation"); - // SymbPrint(aRadScaling, "RadScaling"); - - // compute formula of bilinear interpolation - auto aBilinearValueTri = FormalBilinTri_Formula(aVObs, TriangleDisplacement_NbObs, aXCoordinate, aYCoordinate); - - // Take into account radiometry in minimisation process - auto aRadiometryValueTri = aRadScaling * aBilinearValueTri + aRadTranslation; - - // residual is simply the difference between values in before image and estimated value in new image - return {aIntensityImPre - aRadiometryValueTri}; - } - }; - }; // MMVII #endif // _FORMULAS_TRIANGLES_DEFORM_H_ \ No newline at end of file diff --git a/MMVII/src/SymbDerGen/GenerateCodes.cpp b/MMVII/src/SymbDerGen/GenerateCodes.cpp index a44c2dd3f0..788f9ed1c2 100755 --- a/MMVII/src/SymbDerGen/GenerateCodes.cpp +++ b/MMVII/src/SymbDerGen/GenerateCodes.cpp @@ -314,11 +314,6 @@ cCalculator *EqDeformTri(bool WithDerive, int aSzBuf) return StdAllocCalc(NameFormula(cTriangleDeformation(), WithDerive), aSzBuf); } -cCalculator *EqDeformTriTrRad(bool WithDerive, int aSzBuf) -{ - return StdAllocCalc(NameFormula(cTriangleDeformationTrRad(), WithDerive), aSzBuf); -} - cCalculator *EqDeformTriTranslation(bool WithDerive, int aSzBuf) { return StdAllocCalc(NameFormula(cTriangleDeformationTranslation(), WithDerive), aSzBuf); @@ -329,11 +324,6 @@ cCalculator *EqDeformTriRadiometry(bool WithDerive, int aSzBuf) return StdAllocCalc(NameFormula(cTriangleDeformationRadiometry(), WithDerive), aSzBuf); } -cCalculator *EqDeformTriRad(bool WithDerive, int aSzBuf) -{ - return StdAllocCalc(NameFormula(cTriangleDeformationRad(), WithDerive), aSzBuf); -} - // dist3d // Cons distance template cCalculator * TplEqDist3D(bool WithDerive,int aSzBuf) @@ -841,10 +831,8 @@ int cAppliGenCode::Exe() GenCodesFormula((tREAL8*)nullptr,cDeformImHomotethy(IsLinearGrad) ,WithDer); GenCodesFormula((tREAL8 *)nullptr, cTriangleDeformation(), WithDer); - GenCodesFormula((tREAL8 *)nullptr, cTriangleDeformationTrRad(), WithDer); GenCodesFormula((tREAL8 *)nullptr, cTriangleDeformationTranslation(), WithDer); GenCodesFormula((tREAL8 *)nullptr, cTriangleDeformationRadiometry(), WithDer); - GenCodesFormula((tREAL8 *)nullptr, cTriangleDeformationRad(), WithDer); // =============== CODE FOR RADIOMETRY =========================================