Skip to content

Commit 8bb3863

Browse files
committed
New example - warpPerspective_demo.cpp
An example program shows using cv::findHomography and cv::warpPerspective for image warping
1 parent 87c27a0 commit 8bb3863

File tree

2 files changed

+184
-0
lines changed

2 files changed

+184
-0
lines changed

modules/imgproc/include/opencv2/imgproc.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2264,6 +2264,9 @@ CV_EXPORTS_W void warpAffine( InputArray src, OutputArray dst,
22642264
int borderMode = BORDER_CONSTANT,
22652265
const Scalar& borderValue = Scalar());
22662266

2267+
/** @example warpPerspective_demo.cpp
2268+
An example program shows using cv::findHomography and cv::warpPerspective for image warping
2269+
*/
22672270
/** @brief Applies a perspective transformation to an image.
22682271
22692272
The function warpPerspective transforms the source image using the specified matrix:

samples/cpp/warpPerspective_demo.cpp

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
/**
2+
@file warpPerspective_demo.cpp
3+
@brief a demo program shows how perspective transformation applied on an image
4+
@based on a sample code http://study.marearts.com/2015/03/image-warping-using-opencv.html
5+
@modified by Suleyman TURKMEN
6+
*/
7+
8+
#include "opencv2/imgproc.hpp"
9+
#include "opencv2/imgcodecs.hpp"
10+
#include "opencv2/highgui.hpp"
11+
#include "opencv2/calib3d.hpp"
12+
#include <iostream>
13+
14+
using namespace std;
15+
using namespace cv;
16+
17+
static void help(char** argv)
18+
{
19+
// print a welcome message, and the OpenCV version
20+
cout << "\nThis is a demo program shows how perspective transformation applied on an image, \n"
21+
"Using OpenCV version " << CV_VERSION << endl;
22+
23+
cout << "\nUsage:\n" << argv[0] << " [image_name -- Default ../data/right.jpg]\n" << endl;
24+
25+
cout << "\nHot keys: \n"
26+
"\tESC, q - quit the program\n"
27+
"\tr - change order of points to rotate transformation\n"
28+
"\tc - delete selected points\n"
29+
"\ti - change order of points to invers transformation \n"
30+
"\nUse your mouse to select a point and move it to see transformation changes" << endl;
31+
}
32+
33+
static void onMouse(int event, int x, int y, int, void*);
34+
Mat warping(Mat image, Size warped_image_size, vector< Point2f> srcPoints, vector< Point2f> dstPoints);
35+
36+
String windowTitle = "Perspective Transformation Demo";
37+
String labels[4] = { "TL","TR","BR","BL" };
38+
vector< Point2f> roi_corners;
39+
vector< Point2f> dst_corners(4);
40+
int roiIndex = 0;
41+
bool dragging;
42+
int selected_corner_index = 0;
43+
bool validation_needed = true;
44+
45+
int main(int argc, char** argv)
46+
{
47+
help(argv);
48+
CommandLineParser parser(argc, argv, "{@input| ../data/right.jpg |}");
49+
50+
string filename = parser.get<string>("@input");
51+
Mat original_image = imread( filename );
52+
Mat image;
53+
54+
float original_image_cols = (float)original_image.cols;
55+
float original_image_rows = (float)original_image.rows;
56+
roi_corners.push_back(Point2f( (float)(original_image_cols / 1.70), (float)(original_image_rows / 4.20) ));
57+
roi_corners.push_back(Point2f( (float)(original_image.cols / 1.15), (float)(original_image.rows / 3.32) ));
58+
roi_corners.push_back(Point2f( (float)(original_image.cols / 1.33), (float)(original_image.rows / 1.10) ));
59+
roi_corners.push_back(Point2f( (float)(original_image.cols / 1.93), (float)(original_image.rows / 1.36) ));
60+
61+
namedWindow(windowTitle, WINDOW_NORMAL);
62+
namedWindow("Warped Image", WINDOW_AUTOSIZE);
63+
moveWindow("Warped Image", 20, 20);
64+
moveWindow(windowTitle, 330, 20);
65+
66+
setMouseCallback(windowTitle, onMouse, 0);
67+
68+
bool endProgram = false;
69+
while (!endProgram)
70+
{
71+
if ( validation_needed & (roi_corners.size() < 4) )
72+
{
73+
validation_needed = false;
74+
image = original_image.clone();
75+
76+
for (size_t i = 0; i < roi_corners.size(); ++i)
77+
{
78+
circle( image, roi_corners[i], 5, Scalar(0, 255, 0), 3 );
79+
80+
if( i > 0 )
81+
{
82+
line(image, roi_corners[i-1], roi_corners[(i)], Scalar(0, 0, 255), 2);
83+
circle(image, roi_corners[i], 5, Scalar(0, 255, 0), 3);
84+
putText(image, labels[i].c_str(), roi_corners[i], QT_FONT_NORMAL, 0.8, Scalar(255, 0, 0), 2);
85+
}
86+
}
87+
imshow( windowTitle, image );
88+
}
89+
90+
if ( validation_needed & ( roi_corners.size() == 4 ))
91+
{
92+
image = original_image.clone();
93+
for ( int i = 0; i < 4; ++i )
94+
{
95+
line(image, roi_corners[i], roi_corners[(i + 1) % 4], Scalar(0, 0, 255), 2);
96+
circle(image, roi_corners[i], 5, Scalar(0, 255, 0), 3);
97+
putText(image, labels[i].c_str(), roi_corners[i], QT_FONT_NORMAL, 0.8, Scalar(255, 0, 0), 2);
98+
}
99+
100+
imshow( windowTitle, image );
101+
102+
dst_corners[0].x = 0;
103+
dst_corners[0].y = 0;
104+
dst_corners[1].x = (float)std::max(norm(roi_corners[0] - roi_corners[1]), norm(roi_corners[2] - roi_corners[3]));
105+
dst_corners[1].y = 0;
106+
dst_corners[2].x = (float)std::max(norm(roi_corners[0] - roi_corners[1]), norm(roi_corners[2] - roi_corners[3]));
107+
dst_corners[2].y = (float)std::max(norm(roi_corners[1] - roi_corners[2]), norm(roi_corners[3] - roi_corners[0]));
108+
dst_corners[3].x = 0;
109+
dst_corners[3].y = (float)std::max(norm(roi_corners[1] - roi_corners[2]), norm(roi_corners[3] - roi_corners[0]));
110+
111+
Size warped_image_size = Size(cvRound(dst_corners[2].x), cvRound(dst_corners[2].y));
112+
113+
Mat H = findHomography(roi_corners, dst_corners); //get homography
114+
115+
Mat warped_image;
116+
warpPerspective(original_image, warped_image, H, warped_image_size); // do perspective transformation
117+
118+
imshow("Warped Image", warped_image);
119+
}
120+
121+
char c = (char)waitKey( 10 );
122+
123+
if ((c == 'q') | (c == 'Q') | (c == 27))
124+
{
125+
endProgram = true;
126+
}
127+
128+
if ((c == 'c') | (c == 'C'))
129+
{
130+
roi_corners.clear();
131+
}
132+
133+
if ((c == 'r') | (c == 'R'))
134+
{
135+
roi_corners.push_back(roi_corners[0]);
136+
roi_corners.erase(roi_corners.begin());
137+
}
138+
139+
if ((c == 'i') | (c == 'I'))
140+
{
141+
swap(roi_corners[0], roi_corners[1]);
142+
swap(roi_corners[2], roi_corners[3]);
143+
}
144+
}
145+
return 0;
146+
}
147+
148+
static void onMouse(int event, int x, int y, int, void*)
149+
{
150+
// Action when left button is pressed
151+
if (roi_corners.size() == 4)
152+
{
153+
for (int i = 0; i < 4; ++i)
154+
{
155+
if ((event == EVENT_LBUTTONDOWN) & ((abs(roi_corners[i].x - x) < 10)) & (abs(roi_corners[i].y - y) < 10))
156+
{
157+
selected_corner_index = i;
158+
dragging = true;
159+
}
160+
}
161+
}
162+
else if ( event == EVENT_LBUTTONDOWN )
163+
{
164+
roi_corners.push_back( Point2f( (float) x, (float) y ) );
165+
validation_needed = true;
166+
}
167+
168+
// Action when left button is released
169+
if (event == EVENT_LBUTTONUP)
170+
{
171+
dragging = false;
172+
}
173+
174+
// Action when left button is pressed and mouse has moved over the window
175+
if ((event == EVENT_MOUSEMOVE) && dragging)
176+
{
177+
roi_corners[selected_corner_index].x = (float) x;
178+
roi_corners[selected_corner_index].y = (float) y;
179+
validation_needed = true;
180+
}
181+
}

0 commit comments

Comments
 (0)