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

时间:2011-06-20 23:33:56

标签: c++ image matlab image-processing image-manipulation

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

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

2 个答案:

答案 0 :(得分:2)

我建议您在c ++中使用OpenCV,并且可以调用和使用许多图像处理工具和功能。

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

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

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

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

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

  • Homography(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; 

}

答案 1 :(得分:1)

Raw C ++没有您在其中引用的任何概念。但是,您可以使用许多可以进行各种转换的C ++图像处理库。 DevILFreeImage应该能够进行分层,以及一些变换。