Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/samples/tapi/squares.cpp
16337 views
1
2
#include "opencv2/core.hpp"
3
#include "opencv2/core/ocl.hpp"
4
#include "opencv2/core/utility.hpp"
5
#include "opencv2/imgproc.hpp"
6
#include "opencv2/imgcodecs.hpp"
7
#include "opencv2/highgui.hpp"
8
#include <iostream>
9
10
using namespace cv;
11
using namespace std;
12
13
int thresh = 50, N = 11;
14
const char* wndname = "Square Detection Demo";
15
16
// helper function:
17
// finds a cosine of angle between vectors
18
// from pt0->pt1 and from pt0->pt2
19
static double angle( Point pt1, Point pt2, Point pt0 )
20
{
21
double dx1 = pt1.x - pt0.x;
22
double dy1 = pt1.y - pt0.y;
23
double dx2 = pt2.x - pt0.x;
24
double dy2 = pt2.y - pt0.y;
25
return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
26
}
27
28
29
// returns sequence of squares detected on the image.
30
static void findSquares( const UMat& image, vector<vector<Point> >& squares )
31
{
32
squares.clear();
33
UMat pyr, timg, gray0(image.size(), CV_8U), gray;
34
35
// down-scale and upscale the image to filter out the noise
36
pyrDown(image, pyr, Size(image.cols/2, image.rows/2));
37
pyrUp(pyr, timg, image.size());
38
vector<vector<Point> > contours;
39
40
// find squares in every color plane of the image
41
for( int c = 0; c < 3; c++ )
42
{
43
int ch[] = {c, 0};
44
mixChannels(timg, gray0, ch, 1);
45
46
// try several threshold levels
47
for( int l = 0; l < N; l++ )
48
{
49
// hack: use Canny instead of zero threshold level.
50
// Canny helps to catch squares with gradient shading
51
if( l == 0 )
52
{
53
// apply Canny. Take the upper threshold from slider
54
// and set the lower to 0 (which forces edges merging)
55
Canny(gray0, gray, 0, thresh, 5);
56
// dilate canny output to remove potential
57
// holes between edge segments
58
dilate(gray, gray, UMat(), Point(-1,-1));
59
}
60
else
61
{
62
// apply threshold if l!=0:
63
// tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
64
threshold(gray0, gray, (l+1)*255/N, 255, THRESH_BINARY);
65
}
66
67
// find contours and store them all as a list
68
findContours(gray, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
69
70
vector<Point> approx;
71
72
// test each contour
73
for( size_t i = 0; i < contours.size(); i++ )
74
{
75
// approximate contour with accuracy proportional
76
// to the contour perimeter
77
78
approxPolyDP(contours[i], approx, arcLength(contours[i], true)*0.02, true);
79
80
// square contours should have 4 vertices after approximation
81
// relatively large area (to filter out noisy contours)
82
// and be convex.
83
// Note: absolute value of an area is used because
84
// area may be positive or negative - in accordance with the
85
// contour orientation
86
if( approx.size() == 4 &&
87
fabs(contourArea(approx)) > 1000 &&
88
isContourConvex(approx) )
89
{
90
double maxCosine = 0;
91
92
for( int j = 2; j < 5; j++ )
93
{
94
// find the maximum cosine of the angle between joint edges
95
double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
96
maxCosine = MAX(maxCosine, cosine);
97
}
98
99
// if cosines of all angles are small
100
// (all angles are ~90 degree) then write quandrange
101
// vertices to resultant sequence
102
if( maxCosine < 0.3 )
103
squares.push_back(approx);
104
}
105
}
106
}
107
}
108
}
109
110
// the function draws all the squares in the image
111
static void drawSquares( UMat& _image, const vector<vector<Point> >& squares )
112
{
113
Mat image = _image.getMat(ACCESS_WRITE);
114
for( size_t i = 0; i < squares.size(); i++ )
115
{
116
const Point* p = &squares[i][0];
117
int n = (int)squares[i].size();
118
polylines(image, &p, &n, 1, true, Scalar(0,255,0), 3, LINE_AA);
119
}
120
}
121
122
123
// draw both pure-C++ and ocl square results onto a single image
124
static UMat drawSquaresBoth( const UMat& image,
125
const vector<vector<Point> >& sqs)
126
{
127
UMat imgToShow(Size(image.cols, image.rows), image.type());
128
image.copyTo(imgToShow);
129
130
drawSquares(imgToShow, sqs);
131
132
return imgToShow;
133
}
134
135
136
int main(int argc, char** argv)
137
{
138
const char* keys =
139
"{ i input | ../data/pic1.png | specify input image }"
140
"{ o output | squares_output.jpg | specify output save path}"
141
"{ h help | | print help message }"
142
"{ m cpu_mode | | run without OpenCL }";
143
144
CommandLineParser cmd(argc, argv, keys);
145
146
if(cmd.has("help"))
147
{
148
cout << "Usage : " << argv[0] << " [options]" << endl;
149
cout << "Available options:" << endl;
150
cmd.printMessage();
151
return EXIT_SUCCESS;
152
}
153
if (cmd.has("cpu_mode"))
154
{
155
ocl::setUseOpenCL(false);
156
cout << "OpenCL was disabled" << endl;
157
}
158
159
string inputName = cmd.get<string>("i");
160
string outfile = cmd.get<string>("o");
161
162
int iterations = 10;
163
namedWindow( wndname, WINDOW_AUTOSIZE );
164
vector<vector<Point> > squares;
165
166
UMat image;
167
imread(inputName, 1).copyTo(image);
168
if( image.empty() )
169
{
170
cout << "Couldn't load " << inputName << endl;
171
cmd.printMessage();
172
return EXIT_FAILURE;
173
}
174
175
int j = iterations;
176
int64 t_cpp = 0;
177
//warm-ups
178
cout << "warming up ..." << endl;
179
findSquares(image, squares);
180
181
do
182
{
183
int64 t_start = getTickCount();
184
findSquares(image, squares);
185
t_cpp += cv::getTickCount() - t_start;
186
187
t_start = getTickCount();
188
189
cout << "run loop: " << j << endl;
190
}
191
while(--j);
192
cout << "average time: " << 1000.0f * (double)t_cpp / getTickFrequency() / iterations << "ms" << endl;
193
194
UMat result = drawSquaresBoth(image, squares);
195
imshow(wndname, result);
196
imwrite(outfile, result);
197
waitKey(0);
198
199
return EXIT_SUCCESS;
200
}
201
202