如何手动注册图像(图像注册)

How to register an image manually (image registration)

本文关键字:图像 注册 何手动      更新时间:2023-10-16

我正在将代码从Matlab转换为C++,其中一个我不理解的函数是imtransform。我需要"配准"一个图像,这基本上意味着拉伸、倾斜和旋转我的图像,使其与另一个图像正确重叠。

Matlab的imtransform为您注册,但当我用C++编程时,我需要知道抽象了什么。图像配准中涉及的普通数学是什么?如何从2个数据阵列(组成图像)到1个阵列,即组合图像重叠?

我建议您在c++中使用OpenCV,并且有很多图像处理工具和函数可以调用和使用。

配准模块实现参数化图像配准。实现的方法是直接对齐,即直接使用像素值来计算一对图像之间的配准,而不是基于特征的配准。

表示这些模型的OpenCV常量具有前缀MOTION_,并显示在括号内。

  • 平移(MOTION_TRANSLATION):可以将第一个图像偏移(平移)(x,y)以获得第二个图像。我们只需要估计两个参数x和y。

  • 欧几里得(MOTION_EUCLIDEAN):第一个图像是第二个图像的旋转和移位版本。有三个参数,x,y和角度。您将在图4中注意到,当一个正方形进行欧几里得变换时,其大小不变,平行线保持平行,变换后直角保持不变。

  • 仿射(MOTION_AFFINE):仿射变换是旋转、平移(移位)、缩放和剪切的组合。此变换有六个参数。当正方形经过仿射变换时,平行线保持平行,但以直角相交的线不再保持正交。

  • 同态(MOTION_HOMOGRAPHY):上面描述的所有变换都是2D变换。它们不考虑3D效果。另一方面,单应性变换可以解释一些3D效果(但不是全部)。此变换有8个参数。当使用单应性变换时,正方形可以变为任何四边形。

参考:https://docs.opencv.org/3.4.2/db/d61/group__reg.html

这是一个我发现对图像配准非常有用的例子:

#include <opencv2/opencv.hpp>
#include "opencv2/xfeatures2d.hpp"
#include "opencv2/features2d.hpp"
using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;
const int MAX_FEATURES = 500;
const float GOOD_MATCH_PERCENT = 0.15f;

void alignImages(Mat &im1, Mat &im2, Mat &im1Reg, Mat &h)
{

  Mat im1Gray, im2Gray;
  cvtColor(im1, im1Gray, CV_BGR2GRAY);
  cvtColor(im2, im2Gray, CV_BGR2GRAY);
  // Variables to store keypoints and descriptors
  std::vector<KeyPoint> keypoints1, keypoints2;
  Mat descriptors1, descriptors2;
  // Detect ORB features and compute descriptors.
  Ptr<Feature2D> orb = ORB::create(MAX_FEATURES);
  orb->detectAndCompute(im1Gray, Mat(), keypoints1, descriptors1);
  orb->detectAndCompute(im2Gray, Mat(), keypoints2, descriptors2);
  // Match features.
  std::vector<DMatch> matches;
  Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");
  matcher->match(descriptors1, descriptors2, matches, Mat());
  // Sort matches by score
  std::sort(matches.begin(), matches.end());
  // Remove not so good matches
  const int numGoodMatches = matches.size() * GOOD_MATCH_PERCENT;
  matches.erase(matches.begin()+numGoodMatches, matches.end());

  // Draw top matches
  Mat imMatches;
  drawMatches(im1, keypoints1, im2, keypoints2, matches, imMatches);
  imwrite("matches.jpg", imMatches);

  // Extract location of good matches
  std::vector<Point2f> points1, points2;
  for( size_t i = 0; i < matches.size(); i++ )
  {
    points1.push_back( keypoints1[ matches[i].queryIdx ].pt );
    points2.push_back( keypoints2[ matches[i].trainIdx ].pt );
  }
  // Find homography
  h = findHomography( points1, points2, RANSAC );
  // Use homography to warp image
  warpPerspective(im1, im1Reg, h, im2.size());
}

int main(int argc, char **argv)
{
  // Read reference image
  string refFilename("form.jpg"); 
  cout << "Reading reference image : " << refFilename << endl; 
  Mat imReference = imread(refFilename);

  // Read image to be aligned
  string imFilename("scanned-form.jpg");
  cout << "Reading image to align : " << imFilename << endl; 
  Mat im = imread(imFilename);

  // Registered image will be resotred in imReg. 
  // The estimated homography will be stored in h. 
  Mat imReg, h;
  // Align images
  cout << "Aligning images ..." << endl; 
  alignImages(im, imReference, imReg, h);
  // Write aligned image to disk. 
  string outFilename("aligned.jpg");
  cout << "Saving aligned image : " << outFilename << endl; 
  imwrite(outFilename, imReg);
  // Print estimated homography
  cout << "Estimated homography : n" << h << endl; 
}

Raw C++中没有任何您所提到的概念。但是,您可以使用许多C++的图像处理库来进行各种转换。DevIL和FreeImage应该能够进行分层,以及一些转换。