1#include <vector>
2#include <iostream>
3#include <string>
4
5#include "opencv2/core.hpp"
6#include "opencv2/core/utility.hpp"
7#include "opencv2/imgproc.hpp"
8#include "opencv2/cudaimgproc.hpp"
9#include "opencv2/highgui.hpp"
10
11#include "tick_meter.hpp"
12
13using namespace std;
14using namespace cv;
15
16static Mat loadImage(const string& name)
17{
18    Mat image = imread(name, IMREAD_GRAYSCALE);
19    if (image.empty())
20    {
21        cerr << "Can't load image - " << name << endl;
22        exit(-1);
23    }
24    return image;
25}
26
27int main(int argc, const char* argv[])
28{
29    CommandLineParser cmd(argc, argv,
30        "{ image i        | ../data/pic1.png  | input image }"
31        "{ template t     | templ.png | template image }"
32        "{ full           |           | estimate scale and rotation }"
33        "{ gpu            |           | use gpu version }"
34        "{ minDist        | 100       | minimum distance between the centers of the detected objects }"
35        "{ levels         | 360       | R-Table levels }"
36        "{ votesThreshold | 30        | the accumulator threshold for the template centers at the detection stage. The smaller it is, the more false positions may be detected }"
37        "{ angleThresh    | 10000     | angle votes treshold }"
38        "{ scaleThresh    | 1000      | scale votes treshold }"
39        "{ posThresh      | 100       | position votes threshold }"
40        "{ dp             | 2         | inverse ratio of the accumulator resolution to the image resolution }"
41        "{ minScale       | 0.5       | minimal scale to detect }"
42        "{ maxScale       | 2         | maximal scale to detect }"
43        "{ scaleStep      | 0.05      | scale step }"
44        "{ minAngle       | 0         | minimal rotation angle to detect in degrees }"
45        "{ maxAngle       | 360       | maximal rotation angle to detect in degrees }"
46        "{ angleStep      | 1         | angle step in degrees }"
47        "{ maxBufSize     | 1000      | maximal size of inner buffers }"
48        "{ help h ?       |           | print help message }"
49    );
50
51    cmd.about("This program demonstrates arbitary object finding with the Generalized Hough transform.");
52
53    if (cmd.has("help"))
54    {
55        cmd.printMessage();
56        return 0;
57    }
58
59    const string templName = cmd.get<string>("template");
60    const string imageName = cmd.get<string>("image");
61    const bool full = cmd.has("full");
62    const bool useGpu = cmd.has("gpu");
63    const double minDist = cmd.get<double>("minDist");
64    const int levels = cmd.get<int>("levels");
65    const int votesThreshold = cmd.get<int>("votesThreshold");
66    const int angleThresh = cmd.get<int>("angleThresh");
67    const int scaleThresh = cmd.get<int>("scaleThresh");
68    const int posThresh = cmd.get<int>("posThresh");
69    const double dp = cmd.get<double>("dp");
70    const double minScale = cmd.get<double>("minScale");
71    const double maxScale = cmd.get<double>("maxScale");
72    const double scaleStep = cmd.get<double>("scaleStep");
73    const double minAngle = cmd.get<double>("minAngle");
74    const double maxAngle = cmd.get<double>("maxAngle");
75    const double angleStep = cmd.get<double>("angleStep");
76    const int maxBufSize = cmd.get<int>("maxBufSize");
77
78    if (!cmd.check())
79    {
80        cmd.printErrors();
81        return -1;
82    }
83
84    Mat templ = loadImage(templName);
85    Mat image = loadImage(imageName);
86
87    Ptr<GeneralizedHough> alg;
88
89    if (!full)
90    {
91        Ptr<GeneralizedHoughBallard> ballard = useGpu ? cuda::createGeneralizedHoughBallard() : createGeneralizedHoughBallard();
92
93        ballard->setMinDist(minDist);
94        ballard->setLevels(levels);
95        ballard->setDp(dp);
96        ballard->setMaxBufferSize(maxBufSize);
97        ballard->setVotesThreshold(votesThreshold);
98
99        alg = ballard;
100    }
101    else
102    {
103        Ptr<GeneralizedHoughGuil> guil = useGpu ? cuda::createGeneralizedHoughGuil() : createGeneralizedHoughGuil();
104
105        guil->setMinDist(minDist);
106        guil->setLevels(levels);
107        guil->setDp(dp);
108        guil->setMaxBufferSize(maxBufSize);
109
110        guil->setMinAngle(minAngle);
111        guil->setMaxAngle(maxAngle);
112        guil->setAngleStep(angleStep);
113        guil->setAngleThresh(angleThresh);
114
115        guil->setMinScale(minScale);
116        guil->setMaxScale(maxScale);
117        guil->setScaleStep(scaleStep);
118        guil->setScaleThresh(scaleThresh);
119
120        guil->setPosThresh(posThresh);
121
122        alg = guil;
123    }
124
125    vector<Vec4f> position;
126    TickMeter tm;
127
128    if (useGpu)
129    {
130        cuda::GpuMat d_templ(templ);
131        cuda::GpuMat d_image(image);
132        cuda::GpuMat d_position;
133
134        alg->setTemplate(d_templ);
135
136        tm.start();
137
138        alg->detect(d_image, d_position);
139        d_position.download(position);
140
141        tm.stop();
142    }
143    else
144    {
145        alg->setTemplate(templ);
146
147        tm.start();
148
149        alg->detect(image, position);
150
151        tm.stop();
152    }
153
154    cout << "Found : " << position.size() << " objects" << endl;
155    cout << "Detection time : " << tm.getTimeMilli() << " ms" << endl;
156
157    Mat out;
158    cv::cvtColor(image, out, COLOR_GRAY2BGR);
159
160    for (size_t i = 0; i < position.size(); ++i)
161    {
162        Point2f pos(position[i][0], position[i][1]);
163        float scale = position[i][2];
164        float angle = position[i][3];
165
166        RotatedRect rect;
167        rect.center = pos;
168        rect.size = Size2f(templ.cols * scale, templ.rows * scale);
169        rect.angle = angle;
170
171        Point2f pts[4];
172        rect.points(pts);
173
174        line(out, pts[0], pts[1], Scalar(0, 0, 255), 3);
175        line(out, pts[1], pts[2], Scalar(0, 0, 255), 3);
176        line(out, pts[2], pts[3], Scalar(0, 0, 255), 3);
177        line(out, pts[3], pts[0], Scalar(0, 0, 255), 3);
178    }
179
180    imshow("out", out);
181    waitKey();
182
183    return 0;
184}
185