我正在将代码从Matlab转换为C ++,其中一个我不理解的函数是imtransform。我需要“注册”一个图像,这基本上意味着拉伸,倾斜和旋转我的图像,使其与另一个图像正确重叠。
Matlab的imtransform会为你做注册,但是当我用C ++编程时,我需要知道什么是抽象的。图像配准涉及的正常数学是什么?如何从2个数据阵列(组成图像)到1个阵列,这是重叠的组合图像?
答案 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)