-
Notifications
You must be signed in to change notification settings - Fork 0
/
image_stitching.cpp
136 lines (107 loc) · 4.74 KB
/
image_stitching.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace cv;
int main() {
// We use FAST for keypoint detection and BRIEF for description
// Combined in ORB for orientation component
Ptr<ORB> detector = ORB::create();
Ptr<DescriptorMatcher> descriptor_matcher = DescriptorMatcher::create(DescriptorMatcher::BRUTEFORCE);
std::vector<KeyPoint> lastFrameKeypoints1, lastFrameKeypoints2;
Mat lastFrameDescriptors1, lastFrameDescriptors2;
std::vector<DMatch > matches;
int movementDirection = 0;
std::string image_path1 = samples::findFile("Hill1.jpg");
std::string image_path2 = samples::findFile("Hill2.jpg");
Mat image1 = imread(image_path1);
Mat image2 = imread(image_path2);
// Find keypoints and their descriptor using ORB
detector->detectAndCompute(image1, noArray(), lastFrameKeypoints1, lastFrameDescriptors1);
detector->detectAndCompute(image2, noArray(), lastFrameKeypoints2, lastFrameDescriptors2);
// Match the descriptor between two images, put them in matches vector
descriptor_matcher->match(lastFrameDescriptors1, lastFrameDescriptors2, matches);
std::vector<Point2d> first_good_point, second_good_point;
first_good_point.reserve(matches.size());
second_good_point.reserve(matches.size());
// Calculate max and min distance between keypoints
// distance = similarity between descriptors, less distance -> more similar
double max_dist = 0;
double min_dist = 100;
for (const auto& m : matches) {
double dist = m.distance;
if (dist < min_dist) {
min_dist = dist;
}
if (dist > max_dist) {
max_dist = dist;
}
}
// Get all valid matches
// If distane is <= min_dist * 1.5 its valid
// Value can be changed, higher value means more keypoints
for (const auto& current_match : matches) {
if (current_match.distance <= 1.5 * min_dist) {
// Matches variable holds the index values of x-y positions of the keypoints in both images.
// queryIdx gives key poinst index which has a match and trainIdx gives its corresponding matched key
// These index values can then be used to find the key points in the key points arrays.
first_good_point.push_back(lastFrameKeypoints1.at(current_match.queryIdx).pt);
second_good_point.push_back(lastFrameKeypoints2.at(current_match.trainIdx).pt);
}
}
// Stitching
// To stitch we are cropping the images with the unwanted or repeating regions
Rect cropped_image1(0, 0, image1.cols, image1.rows);
Rect cropped_image2(0, 0, image2.cols, image2.rows);
// find minimum horizontal value for image 1 to crop
//e.g. img1 size = 200 first keypoint having match found at position 100 crop img1 to pixel 0 to 100, i.e. crop everything above
// crop image2 to from corresponding x value to the width. Same procedure
//e.g. img2 width 200 point found at 50 crop image 50-200, so cut everything to the left
// movementDirection tells us if the two images are aligned or not
// if not, adjust them accordingly
int imgWidth = image1.cols;
for (int i = 0; i < first_good_point.size(); ++i)
{
if (first_good_point[i].x < imgWidth)
{
// Crop image at minimum horizontal point where matched keypoint is detected
cropped_image1.width = first_good_point.at(i).x;
cropped_image2.x = second_good_point[i].x;
cropped_image2.width = image2.cols - cropped_image2.x;
movementDirection = first_good_point[i].y - second_good_point[i].y;
imgWidth = first_good_point[i].x;
}
}
image1 = image1(cropped_image1);
image2 = image2(cropped_image2);
int maxHeight;
int maxWidth;
if (image1.rows > image2.rows) {
maxHeight = image1.rows;
} else {
maxHeight = image2.rows;
}
maxWidth = image1.cols + image2.cols;
Mat result = Mat::zeros(Size(maxWidth, maxHeight + abs(movementDirection)), CV_8UC3);
if (movementDirection > 0)
{
Mat half1(result, Rect(0, 0, image1.cols, image1.rows));
image1.copyTo(half1);
Mat half2(result, Rect(image1.cols, abs(movementDirection),image2.cols, image2.rows));
image2.copyTo(half2);
}
else
{
Mat half1(result, Rect(0, abs(movementDirection), image1.cols, image1.rows));
image1.copyTo(half1);
Mat half2(result, Rect(image1.cols,0 ,image2.cols, image2.rows));
image2.copyTo(half2);
}
imshow("Stitched Image", result);
int k = waitKey(0);
if (k == 's') {
imwrite("StitchedImage.png", result);
}
return 0;
}