Calculate offset/skew/rotation of similar images in C++
I have multiple images taken simultaneously pointing at the same direction from the same starting location. However, there is still a slight offset开发者_如何学JAVA because these cameras were not in the exact same place when the picture was taking. I'm looking for a way to calculate the optimal translation/shear/skew/rotation needed to apply to match one image to another so that they overlay (almost) perfectly.
The images are in a .raw format which I am reading in 16 bits at a time.
I have been suggested (by my employer who is not a programmer [I'm an intern btw]) to take a portion of the source image (not at the edges) and brute-force search for a same-sized portion with a high correlation in data values. I'm hoping there is a less-wasteful algorithm.
Here is a short code that does what you want (I use openCV 2.2):
- Suppose you have 2 images: srcImage,dstImage, and you want to align them
- The code is very simple. Use it as basis for your algorithm.
Code:
// Detect special points on each image that can be corresponded
Ptr<FeatureDetector> detector = new SurfFeatureDetector(2000); // Detector for features
vector<KeyPoint> srcFeatures; // Detected key points on first image
vector<KeyPoint> dstFeatures;
detector->detect(srcImage,srcFeatures);
detector->detect(dstImage,dstFeatures);
// Extract descriptors of the features
SurfDescriptorExtractor extractor;
Mat projDescriptors, camDescriptors;
extractor.compute(srcImage, srcFeatures, srcDescriptors);
extractor.compute(dstImage , dstFeatures, dstDescriptors );
// Match descriptors of 2 images (find pairs of corresponding points)
BruteForceMatcher<L2<float>> matcher; // Use FlannBasedMatcher matcher. It is better
vector<DMatch> matches;
matcher.match(srcDescriptors, dstDescriptors, matches);
// Extract pairs of points
vector<int> pairOfsrcKP(matches.size()), pairOfdstKP(matches.size());
for( size_t i = 0; i < matches.size(); i++ ){
pairOfsrcKP[i] = matches[i].queryIdx;
pairOfdstKP[i] = matches[i].trainIdx;
}
vector<Point2f> sPoints; KeyPoint::convert(srcFeatures, sPoints,pairOfsrcKP);
vector<Point2f> dPoints; KeyPoint::convert(dstFeatures, dPoints,pairOfdstKP);
// Matched pairs of 2D points. Those pairs will be used to calculate homography
Mat src2Dfeatures;
Mat dst2Dfeatures;
Mat(sPoints).copyTo(src2Dfeatures);
Mat(dPoints).copyTo(dst2Dfeatures);
// Calculate homography
vector<uchar> outlierMask;
Mat H;
H = findHomography( src2Dfeatures, dst2Dfeatures, outlierMask, RANSAC, 3);
// Show the result (only for debug)
if (debug){
Mat outimg;
drawMatches(srcImage, srcFeatures,dstImage, dstFeatures, matches, outimg, Scalar::all(-1), Scalar::all(-1),
reinterpret_cast<const vector<char>&> (outlierMask));
imshow("Matches: Src image (left) to dst (right)", outimg);
cvWaitKey(0);
}
// Now you have the resulting homography. I mean that: H(srcImage) is alligned to dstImage. Apply H using the below code
Mat AlignedSrcImage;
warpPerspective(srcImage,AlignedSrcImage,H,dstImage.Size(),INTER_LINEAR,BORDER_CONSTANT);
Mat AlignedDstImageToSrc;
warpPerspective(dstImage,AlignedDstImageToSrc,H.inv(),srcImage.Size(),INTER_LINEAR,BORDER_CONSTANT);
Are the images taken standing from the same position but you're just rotated a bit so that they're not aligned correctly? If so then the images are related by a homography - i.e. a projective transformation. Given a set of correspondences between the images (you need at least 4 pairs), the standard way to find the homography is to use the DLT algorithm.
Avoid linker errors using the below code:
#include "cv.h"
#include "highgui.h"
using namespace cv;
// Directives to linker to include openCV lib files.
#pragma comment(lib, "opencv_core220.lib")
#pragma comment(lib, "opencv_highgui220.lib")
#pragma comment(lib, "opencv_contrib220.lib")
#pragma comment(lib, "opencv_imgproc220.lib")
#pragma comment(lib, "opencv_gpu220.lib")
#pragma comment(lib, "opencv_video220.lib")
#pragma comment(lib, "opencv_legacy220.lib")
#pragma comment(lib, "opencv_ml220.lib")
#pragma comment(lib, "opencv_objdetect220.lib")
#pragma comment(lib, "opencv_ffmpeg220.lib")
#pragma comment(lib, "opencv_flann220.lib")
#pragma comment(lib, "opencv_features2d220.lib")
#pragma comment(lib, "opencv_calib3d220.lib")
// Your code here...
int main(void){
Mat B = Mat:eye(3,3,CV_8U);
return -1;
}
精彩评论