单应矩阵变化前后效果
#include "openMVG/features/feature.hpp"
#include "openMVG/features/sift/SIFT_Anatomy_Image_Describer.hpp"
#include "openMVG/features/svg_features.hpp"
#include "openMVG/image/image_io.hpp"
#include "openMVG/image/image_concat.hpp"
#include "openMVG/image/image_warping.hpp"
#include "openMVG/numeric/eigen_alias_definition.hpp"
#include "openMVG/matching/regions_matcher.hpp"
#include "openMVG/matching/svg_matches.hpp"
#include "openMVG/multiview/solver_homography_kernel.hpp"
#include "openMVG/robust_estimation/robust_estimator_ACRansac.hpp"
#include "openMVG/robust_estimation/robust_estimator_ACRansacKernelAdaptator.hpp"
#include "openMVG/types.hpp"
#include "third_party/cmdLine/cmdLine.h"
#include "third_party/stlplus3/filesystemSimplified/file_system.hpp"
#include <cstdlib>
#include <iostream>
#include <string>
#include <utility>
using namespace openMVG;
using namespace openMVG::image;
using namespace openMVG::matching;
using namespace openMVG::robust;
using namespace std;
int main() {
//https://blog.csdn.net/m0_48465302/article/details/138082521
//特征匹配部分见专栏
//初始化矩阵估计的Kernel,包括基础矩阵都是用这个Kernel
std::vector<uint32_t> vec_inliers;
using KernelType =
ACKernelAdaptor<
openMVG::homography::kernel::FourPointSolver,
openMVG::homography::kernel::AsymmetricError,
UnnormalizerI,
Mat3>;
KernelType kernel(
xL, imageL.Width(), imageL.Height(),
xR, imageR.Width(), imageR.Height(),
false);
//使用Ransac方法估计单应矩阵,迭代次数设置为1024
Mat3 H;
const std::pair<double,double> ACRansacOut = ACRANSAC(kernel, vec_inliers, 1024, &H,
std::numeric_limits<double>::infinity(),
true);
const double & thresholdH = ACRansacOut.first;
//基础矩阵估计
std::vector<uint32_t> vec_inliers;
using KernelType =
ACKernelAdaptor<
openMVG::fundamental::kernel::SevenPointSolver,
openMVG::fundamental::kernel::SymmetricEpipolarDistanceError,
UnnormalizerT,
Mat3>;
KernelType kernel(
xL, imageL.Width(), imageL.Height(),
xR, imageR.Width(), imageR.Height(),
true); // configure as point to line error model.
Mat3 F;
const std::pair<double,double> ACRansacOut = ACRANSAC(kernel, vec_inliers, 1024, &F,
Square(4.0), // Upper bound of authorized threshold
true);
const double & thresholdF = ACRansacOut.first;
//估计单应矩阵使用的模型内点数量需要大于阈值
if (vec_inliers.size() > KernelType::MINIMUM_SAMPLES *2.5) {
std::cout << "\nFound a homography under the confidence threshold of: "
<< thresholdH << " pixels\n\twith: " << vec_inliers.size() << " inliers"
<< " from: " << vec_PutativeMatches.size()
<< " putatives correspondences"
<< std::endl;
//可视化估计单应矩阵使用的模型内点
const bool bVertical = true;
InlierMatches2SVG
(
jpg_filenameL,
{imageL.Width(), imageL.Height()},
regionsL->GetRegionsPositions(),
jpg_filenameR,
{imageR.Width(), imageR.Height()},
regionsR->GetRegionsPositions(),
vec_PutativeMatches,
vec_inliers,
"04_ACRansacHomography.svg",
bVertical
);
//计算模拟内点估计单应矩阵的误差
std::vector<double> vec_residuals(vec_inliers.size(), 0.0);
for ( size_t i = 0; i < vec_inliers.size(); ++i) {
const SIOPointFeature & LL = regionsL->Features()[vec_PutativeMatches[vec_inliers[i]].i_];
const SIOPointFeature & RR = regionsR->Features()[vec_PutativeMatches[vec_inliers[i]].j_];
// 误差计算
vec_residuals[i] = std::sqrt(KernelType::ErrorT::Error(H,
LL.coords().cast<double>(),
RR.coords().cast<double>()));
}
// 计算模型内点误差的最小值、最大值、均值,中位数...
float dMin, dMax, dMean, dMedian;
minMaxMeanMedian<float>(vec_residuals.cbegin(), vec_residuals.cend(),
dMin, dMax, dMean, dMedian);
std::cout << std::endl
<< "Homography matrix estimation, residuals statistics:" << "\n"
<< "\t-- Residual min:\t" << dMin << std::endl
<< "\t-- Residual median:\t" << dMedian << std::endl
<< "\t-- Residual max:\t " << dMax << std::endl
<< "\t-- Residual mean:\t " << dMean << std::endl;
//读取右图像
ReadImage(jpg_filenameR.c_str(), &image);
WriteImage("query.png", image);
// 将右图像通过单应矩阵变换为左边图像作为输出并保存
Image<RGBColor> imaOut(imageL.Width(), imageL.Height());
image::Warp(image, H, imaOut);
const std::string imageNameOut = "query_warped.png";
WriteImage(imageNameOut.c_str(), imaOut);
}
else {
std::cout << "ACRANSAC was unable to estimate a rigid homography"
<< std::endl;
}
}
return EXIT_SUCCESS;
}