~paparazzi-uav/paparazzi/v5.0-manual

« back to all changes in this revision

Viewing changes to sw/ext/opencv_bebop/opencv/modules/imgproc/src/generalized_hough.cpp

  • Committer: Paparazzi buildbot
  • Date: 2016-05-18 15:00:29 UTC
  • Revision ID: felix.ruess+docbot@gmail.com-20160518150029-e8lgzi5kvb4p7un9
Manual import commit 4b8bbb730080dac23cf816b98908dacfabe2a8ec from v5.0 branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*M///////////////////////////////////////////////////////////////////////////////////////
 
2
//
 
3
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
 
4
//
 
5
//  By downloading, copying, installing or using the software you agree to this license.
 
6
//  If you do not agree to this license, do not download, install,
 
7
//  copy or use the software.
 
8
//
 
9
//
 
10
//                        Intel License Agreement
 
11
//                For Open Source Computer Vision Library
 
12
//
 
13
// Copyright (C) 2000, Intel Corporation, all rights reserved.
 
14
// Third party copyrights are property of their respective owners.
 
15
//
 
16
// Redistribution and use in source and binary forms, with or without modification,
 
17
// are permitted provided that the following conditions are met:
 
18
//
 
19
//   * Redistribution's of source code must retain the above copyright notice,
 
20
//     this list of conditions and the following disclaimer.
 
21
//
 
22
//   * Redistribution's in binary form must reproduce the above copyright notice,
 
23
//     this list of conditions and the following disclaimer in the documentation
 
24
//     and/or other materials provided with the distribution.
 
25
//
 
26
//   * The name of Intel Corporation may not be used to endorse or promote products
 
27
//     derived from this software without specific prior written permission.
 
28
//
 
29
// This software is provided by the copyright holders and contributors "as is" and
 
30
// any express or implied warranties, including, but not limited to, the implied
 
31
// warranties of merchantability and fitness for a particular purpose are disclaimed.
 
32
// In no event shall the Intel Corporation or contributors be liable for any direct,
 
33
// indirect, incidental, special, exemplary, or consequential damages
 
34
// (including, but not limited to, procurement of substitute goods or services;
 
35
// loss of use, data, or profits; or business interruption) however caused
 
36
// and on any theory of liability, whether in contract, strict liability,
 
37
// or tort (including negligence or otherwise) arising in any way out of
 
38
// the use of this software, even if advised of the possibility of such damage.
 
39
//
 
40
//M*/
 
41
 
 
42
#include "precomp.hpp"
 
43
#include <functional>
 
44
#include <limits>
 
45
 
 
46
using namespace cv;
 
47
 
 
48
// common
 
49
 
 
50
namespace
 
51
{
 
52
    double toRad(double a)
 
53
    {
 
54
        return a * CV_PI / 180.0;
 
55
    }
 
56
 
 
57
    bool notNull(float v)
 
58
    {
 
59
        return fabs(v) > std::numeric_limits<float>::epsilon();
 
60
    }
 
61
 
 
62
    class GeneralizedHoughBase
 
63
    {
 
64
    protected:
 
65
        GeneralizedHoughBase();
 
66
        virtual ~GeneralizedHoughBase() {}
 
67
 
 
68
        void setTemplateImpl(InputArray templ, Point templCenter);
 
69
        void setTemplateImpl(InputArray edges, InputArray dx, InputArray dy, Point templCenter);
 
70
 
 
71
        void detectImpl(InputArray image, OutputArray positions, OutputArray votes);
 
72
        void detectImpl(InputArray edges, InputArray dx, InputArray dy, OutputArray positions, OutputArray votes);
 
73
 
 
74
        virtual void processTempl() = 0;
 
75
        virtual void processImage() = 0;
 
76
 
 
77
        int cannyLowThresh_;
 
78
        int cannyHighThresh_;
 
79
        double minDist_;
 
80
        double dp_;
 
81
 
 
82
        Size templSize_;
 
83
        Point templCenter_;
 
84
        Mat templEdges_;
 
85
        Mat templDx_;
 
86
        Mat templDy_;
 
87
 
 
88
        Size imageSize_;
 
89
        Mat imageEdges_;
 
90
        Mat imageDx_;
 
91
        Mat imageDy_;
 
92
 
 
93
        std::vector<Vec4f> posOutBuf_;
 
94
        std::vector<Vec3i> voteOutBuf_;
 
95
 
 
96
    private:
 
97
        void calcEdges(InputArray src, Mat& edges, Mat& dx, Mat& dy);
 
98
        void filterMinDist();
 
99
        void convertTo(OutputArray positions, OutputArray votes);
 
100
    };
 
101
 
 
102
    GeneralizedHoughBase::GeneralizedHoughBase()
 
103
    {
 
104
        cannyLowThresh_ = 50;
 
105
        cannyHighThresh_ = 100;
 
106
        minDist_ = 1.0;
 
107
        dp_ = 1.0;
 
108
    }
 
109
 
 
110
    void GeneralizedHoughBase::calcEdges(InputArray _src, Mat& edges, Mat& dx, Mat& dy)
 
111
    {
 
112
        Mat src = _src.getMat();
 
113
 
 
114
        CV_Assert( src.type() == CV_8UC1 );
 
115
        CV_Assert( cannyLowThresh_ > 0 && cannyLowThresh_ < cannyHighThresh_ );
 
116
 
 
117
        Canny(src, edges, cannyLowThresh_, cannyHighThresh_);
 
118
        Sobel(src, dx, CV_32F, 1, 0);
 
119
        Sobel(src, dy, CV_32F, 0, 1);
 
120
    }
 
121
 
 
122
    void GeneralizedHoughBase::setTemplateImpl(InputArray templ, Point templCenter)
 
123
    {
 
124
        calcEdges(templ, templEdges_, templDx_, templDy_);
 
125
 
 
126
        if (templCenter == Point(-1, -1))
 
127
            templCenter = Point(templEdges_.cols / 2, templEdges_.rows / 2);
 
128
 
 
129
        templSize_ = templEdges_.size();
 
130
        templCenter_ = templCenter;
 
131
 
 
132
        processTempl();
 
133
    }
 
134
 
 
135
    void GeneralizedHoughBase::setTemplateImpl(InputArray edges, InputArray dx, InputArray dy, Point templCenter)
 
136
    {
 
137
        edges.getMat().copyTo(templEdges_);
 
138
        dx.getMat().copyTo(templDx_);
 
139
        dy.getMat().copyTo(templDy_);
 
140
 
 
141
        CV_Assert( templEdges_.type() == CV_8UC1 );
 
142
        CV_Assert( templDx_.type() == CV_32FC1 && templDx_.size() == templEdges_.size() );
 
143
        CV_Assert( templDy_.type() == templDx_.type() && templDy_.size() == templEdges_.size() );
 
144
 
 
145
        if (templCenter == Point(-1, -1))
 
146
            templCenter = Point(templEdges_.cols / 2, templEdges_.rows / 2);
 
147
 
 
148
        templSize_ = templEdges_.size();
 
149
        templCenter_ = templCenter;
 
150
 
 
151
        processTempl();
 
152
    }
 
153
 
 
154
    void GeneralizedHoughBase::detectImpl(InputArray image, OutputArray positions, OutputArray votes)
 
155
    {
 
156
        calcEdges(image, imageEdges_, imageDx_, imageDy_);
 
157
 
 
158
        imageSize_ = imageEdges_.size();
 
159
 
 
160
        posOutBuf_.clear();
 
161
        voteOutBuf_.clear();
 
162
 
 
163
        processImage();
 
164
 
 
165
        if (!posOutBuf_.empty())
 
166
        {
 
167
            if (minDist_ > 1)
 
168
                filterMinDist();
 
169
            convertTo(positions, votes);
 
170
        }
 
171
        else
 
172
        {
 
173
            positions.release();
 
174
            if (votes.needed())
 
175
                votes.release();
 
176
        }
 
177
    }
 
178
 
 
179
    void GeneralizedHoughBase::detectImpl(InputArray edges, InputArray dx, InputArray dy, OutputArray positions, OutputArray votes)
 
180
    {
 
181
        edges.getMat().copyTo(imageEdges_);
 
182
        dx.getMat().copyTo(imageDx_);
 
183
        dy.getMat().copyTo(imageDy_);
 
184
 
 
185
        CV_Assert( imageEdges_.type() == CV_8UC1 );
 
186
        CV_Assert( imageDx_.type() == CV_32FC1 && imageDx_.size() == imageEdges_.size() );
 
187
        CV_Assert( imageDy_.type() == imageDx_.type() && imageDy_.size() == imageEdges_.size() );
 
188
 
 
189
        imageSize_ = imageEdges_.size();
 
190
 
 
191
        posOutBuf_.clear();
 
192
        voteOutBuf_.clear();
 
193
 
 
194
        processImage();
 
195
 
 
196
        if (!posOutBuf_.empty())
 
197
        {
 
198
            if (minDist_ > 1)
 
199
                filterMinDist();
 
200
            convertTo(positions, votes);
 
201
        }
 
202
        else
 
203
        {
 
204
            positions.release();
 
205
            if (votes.needed())
 
206
                votes.release();
 
207
        }
 
208
    }
 
209
 
 
210
    class Vec3iGreaterThanIdx
 
211
    {
 
212
    public:
 
213
        Vec3iGreaterThanIdx( const Vec3i* _arr ) : arr(_arr) {}
 
214
        bool operator()(size_t a, size_t b) const { return arr[a][0] > arr[b][0]; }
 
215
        const Vec3i* arr;
 
216
    };
 
217
 
 
218
    void GeneralizedHoughBase::filterMinDist()
 
219
    {
 
220
        size_t oldSize = posOutBuf_.size();
 
221
        const bool hasVotes = !voteOutBuf_.empty();
 
222
 
 
223
        CV_Assert( !hasVotes || voteOutBuf_.size() == oldSize );
 
224
 
 
225
        std::vector<Vec4f> oldPosBuf(posOutBuf_);
 
226
        std::vector<Vec3i> oldVoteBuf(voteOutBuf_);
 
227
 
 
228
        std::vector<size_t> indexies(oldSize);
 
229
        for (size_t i = 0; i < oldSize; ++i)
 
230
            indexies[i] = i;
 
231
        std::sort(indexies.begin(), indexies.end(), Vec3iGreaterThanIdx(&oldVoteBuf[0]));
 
232
 
 
233
        posOutBuf_.clear();
 
234
        voteOutBuf_.clear();
 
235
 
 
236
        const int cellSize = cvRound(minDist_);
 
237
        const int gridWidth = (imageSize_.width + cellSize - 1) / cellSize;
 
238
        const int gridHeight = (imageSize_.height + cellSize - 1) / cellSize;
 
239
 
 
240
        std::vector< std::vector<Point2f> > grid(gridWidth * gridHeight);
 
241
 
 
242
        const double minDist2 = minDist_ * minDist_;
 
243
 
 
244
        for (size_t i = 0; i < oldSize; ++i)
 
245
        {
 
246
            const size_t ind = indexies[i];
 
247
 
 
248
            Point2f p(oldPosBuf[ind][0], oldPosBuf[ind][1]);
 
249
 
 
250
            bool good = true;
 
251
 
 
252
            const int xCell = static_cast<int>(p.x / cellSize);
 
253
            const int yCell = static_cast<int>(p.y / cellSize);
 
254
 
 
255
            int x1 = xCell - 1;
 
256
            int y1 = yCell - 1;
 
257
            int x2 = xCell + 1;
 
258
            int y2 = yCell + 1;
 
259
 
 
260
            // boundary check
 
261
            x1 = std::max(0, x1);
 
262
            y1 = std::max(0, y1);
 
263
            x2 = std::min(gridWidth - 1, x2);
 
264
            y2 = std::min(gridHeight - 1, y2);
 
265
 
 
266
            for (int yy = y1; yy <= y2; ++yy)
 
267
            {
 
268
                for (int xx = x1; xx <= x2; ++xx)
 
269
                {
 
270
                    const std::vector<Point2f>& m = grid[yy * gridWidth + xx];
 
271
 
 
272
                    for(size_t j = 0; j < m.size(); ++j)
 
273
                    {
 
274
                        const Point2f d = p - m[j];
 
275
 
 
276
                        if (d.ddot(d) < minDist2)
 
277
                        {
 
278
                            good = false;
 
279
                            goto break_out;
 
280
                        }
 
281
                    }
 
282
                }
 
283
            }
 
284
 
 
285
            break_out:
 
286
 
 
287
            if(good)
 
288
            {
 
289
                grid[yCell * gridWidth + xCell].push_back(p);
 
290
 
 
291
                posOutBuf_.push_back(oldPosBuf[ind]);
 
292
                if (hasVotes)
 
293
                    voteOutBuf_.push_back(oldVoteBuf[ind]);
 
294
            }
 
295
        }
 
296
    }
 
297
 
 
298
    void GeneralizedHoughBase::convertTo(OutputArray _positions, OutputArray _votes)
 
299
    {
 
300
        const int total = static_cast<int>(posOutBuf_.size());
 
301
        const bool hasVotes = !voteOutBuf_.empty();
 
302
 
 
303
        CV_Assert( !hasVotes || voteOutBuf_.size() == posOutBuf_.size() );
 
304
 
 
305
        _positions.create(1, total, CV_32FC4);
 
306
        Mat positions = _positions.getMat();
 
307
        Mat(1, total, CV_32FC4, &posOutBuf_[0]).copyTo(positions);
 
308
 
 
309
        if (_votes.needed())
 
310
        {
 
311
            if (!hasVotes)
 
312
            {
 
313
                _votes.release();
 
314
            }
 
315
            else
 
316
            {
 
317
                _votes.create(1, total, CV_32SC3);
 
318
                Mat votes = _votes.getMat();
 
319
                Mat(1, total, CV_32SC3, &voteOutBuf_[0]).copyTo(votes);
 
320
            }
 
321
        }
 
322
    }
 
323
}
 
324
 
 
325
// GeneralizedHoughBallard
 
326
 
 
327
namespace
 
328
{
 
329
    class GeneralizedHoughBallardImpl : public GeneralizedHoughBallard, private GeneralizedHoughBase
 
330
    {
 
331
    public:
 
332
        GeneralizedHoughBallardImpl();
 
333
 
 
334
        void setTemplate(InputArray templ, Point templCenter) { setTemplateImpl(templ, templCenter); }
 
335
        void setTemplate(InputArray edges, InputArray dx, InputArray dy, Point templCenter) { setTemplateImpl(edges, dx, dy, templCenter); }
 
336
 
 
337
        void detect(InputArray image, OutputArray positions, OutputArray votes) { detectImpl(image, positions, votes); }
 
338
        void detect(InputArray edges, InputArray dx, InputArray dy, OutputArray positions, OutputArray votes) { detectImpl(edges, dx, dy, positions, votes); }
 
339
 
 
340
        void setCannyLowThresh(int cannyLowThresh) { cannyLowThresh_ = cannyLowThresh; }
 
341
        int getCannyLowThresh() const { return cannyLowThresh_; }
 
342
 
 
343
        void setCannyHighThresh(int cannyHighThresh) { cannyHighThresh_ = cannyHighThresh; }
 
344
        int getCannyHighThresh() const { return cannyHighThresh_; }
 
345
 
 
346
        void setMinDist(double minDist) { minDist_ = minDist; }
 
347
        double getMinDist() const { return minDist_; }
 
348
 
 
349
        void setDp(double dp) { dp_ = dp; }
 
350
        double getDp() const { return dp_; }
 
351
 
 
352
        void setMaxBufferSize(int) {  }
 
353
        int getMaxBufferSize() const { return 0; }
 
354
 
 
355
        void setLevels(int levels) { levels_ = levels; }
 
356
        int getLevels() const { return levels_; }
 
357
 
 
358
        void setVotesThreshold(int votesThreshold) { votesThreshold_ = votesThreshold; }
 
359
        int getVotesThreshold() const { return votesThreshold_; }
 
360
 
 
361
    private:
 
362
        void processTempl();
 
363
        void processImage();
 
364
 
 
365
        void calcHist();
 
366
        void findPosInHist();
 
367
 
 
368
        int levels_;
 
369
        int votesThreshold_;
 
370
 
 
371
        std::vector< std::vector<Point> > r_table_;
 
372
        Mat hist_;
 
373
    };
 
374
 
 
375
    GeneralizedHoughBallardImpl::GeneralizedHoughBallardImpl()
 
376
    {
 
377
        levels_ = 360;
 
378
        votesThreshold_ = 100;
 
379
    }
 
380
 
 
381
    void GeneralizedHoughBallardImpl::processTempl()
 
382
    {
 
383
        CV_Assert( levels_ > 0 );
 
384
 
 
385
        const double thetaScale = levels_ / 360.0;
 
386
 
 
387
        r_table_.resize(levels_ + 1);
 
388
        std::for_each(r_table_.begin(), r_table_.end(), std::mem_fun_ref(&std::vector<Point>::clear));
 
389
 
 
390
        for (int y = 0; y < templSize_.height; ++y)
 
391
        {
 
392
            const uchar* edgesRow = templEdges_.ptr(y);
 
393
            const float* dxRow = templDx_.ptr<float>(y);
 
394
            const float* dyRow = templDy_.ptr<float>(y);
 
395
 
 
396
            for (int x = 0; x < templSize_.width; ++x)
 
397
            {
 
398
                const Point p(x, y);
 
399
 
 
400
                if (edgesRow[x] && (notNull(dyRow[x]) || notNull(dxRow[x])))
 
401
                {
 
402
                    const float theta = fastAtan2(dyRow[x], dxRow[x]);
 
403
                    const int n = cvRound(theta * thetaScale);
 
404
                    r_table_[n].push_back(p - templCenter_);
 
405
                }
 
406
            }
 
407
        }
 
408
    }
 
409
 
 
410
    void GeneralizedHoughBallardImpl::processImage()
 
411
    {
 
412
        calcHist();
 
413
        findPosInHist();
 
414
    }
 
415
 
 
416
    void GeneralizedHoughBallardImpl::calcHist()
 
417
    {
 
418
        CV_Assert( imageEdges_.type() == CV_8UC1 );
 
419
        CV_Assert( imageDx_.type() == CV_32FC1 && imageDx_.size() == imageSize_);
 
420
        CV_Assert( imageDy_.type() == imageDx_.type() && imageDy_.size() == imageSize_);
 
421
        CV_Assert( levels_ > 0 && r_table_.size() == static_cast<size_t>(levels_ + 1) );
 
422
        CV_Assert( dp_ > 0.0 );
 
423
 
 
424
        const double thetaScale = levels_ / 360.0;
 
425
        const double idp = 1.0 / dp_;
 
426
 
 
427
        hist_.create(cvCeil(imageSize_.height * idp) + 2, cvCeil(imageSize_.width * idp) + 2, CV_32SC1);
 
428
        hist_.setTo(0);
 
429
 
 
430
        const int rows = hist_.rows - 2;
 
431
        const int cols = hist_.cols - 2;
 
432
 
 
433
        for (int y = 0; y < imageSize_.height; ++y)
 
434
        {
 
435
            const uchar* edgesRow = imageEdges_.ptr(y);
 
436
            const float* dxRow = imageDx_.ptr<float>(y);
 
437
            const float* dyRow = imageDy_.ptr<float>(y);
 
438
 
 
439
            for (int x = 0; x < imageSize_.width; ++x)
 
440
            {
 
441
                const Point p(x, y);
 
442
 
 
443
                if (edgesRow[x] && (notNull(dyRow[x]) || notNull(dxRow[x])))
 
444
                {
 
445
                    const float theta = fastAtan2(dyRow[x], dxRow[x]);
 
446
                    const int n = cvRound(theta * thetaScale);
 
447
 
 
448
                    const std::vector<Point>& r_row = r_table_[n];
 
449
 
 
450
                    for (size_t j = 0; j < r_row.size(); ++j)
 
451
                    {
 
452
                        Point c = p - r_row[j];
 
453
 
 
454
                        c.x = cvRound(c.x * idp);
 
455
                        c.y = cvRound(c.y * idp);
 
456
 
 
457
                        if (c.x >= 0 && c.x < cols && c.y >= 0 && c.y < rows)
 
458
                            ++hist_.at<int>(c.y + 1, c.x + 1);
 
459
                    }
 
460
                }
 
461
            }
 
462
        }
 
463
    }
 
464
 
 
465
    void GeneralizedHoughBallardImpl::findPosInHist()
 
466
    {
 
467
        CV_Assert( votesThreshold_ > 0 );
 
468
 
 
469
        const int histRows = hist_.rows - 2;
 
470
        const int histCols = hist_.cols - 2;
 
471
 
 
472
        for(int y = 0; y < histRows; ++y)
 
473
        {
 
474
            const int* prevRow = hist_.ptr<int>(y);
 
475
            const int* curRow = hist_.ptr<int>(y + 1);
 
476
            const int* nextRow = hist_.ptr<int>(y + 2);
 
477
 
 
478
            for(int x = 0; x < histCols; ++x)
 
479
            {
 
480
                const int votes = curRow[x + 1];
 
481
 
 
482
                if (votes > votesThreshold_ && votes > curRow[x] && votes >= curRow[x + 2] && votes > prevRow[x + 1] && votes >= nextRow[x + 1])
 
483
                {
 
484
                    posOutBuf_.push_back(Vec4f(static_cast<float>(x * dp_), static_cast<float>(y * dp_), 1.0f, 0.0f));
 
485
                    voteOutBuf_.push_back(Vec3i(votes, 0, 0));
 
486
                }
 
487
            }
 
488
        }
 
489
    }
 
490
}
 
491
 
 
492
Ptr<GeneralizedHoughBallard> cv::createGeneralizedHoughBallard()
 
493
{
 
494
    return makePtr<GeneralizedHoughBallardImpl>();
 
495
}
 
496
 
 
497
// GeneralizedHoughGuil
 
498
 
 
499
namespace
 
500
{
 
501
    class GeneralizedHoughGuilImpl : public GeneralizedHoughGuil, private GeneralizedHoughBase
 
502
    {
 
503
    public:
 
504
        GeneralizedHoughGuilImpl();
 
505
 
 
506
        void setTemplate(InputArray templ, Point templCenter) { setTemplateImpl(templ, templCenter); }
 
507
        void setTemplate(InputArray edges, InputArray dx, InputArray dy, Point templCenter) { setTemplateImpl(edges, dx, dy, templCenter); }
 
508
 
 
509
        void detect(InputArray image, OutputArray positions, OutputArray votes) { detectImpl(image, positions, votes); }
 
510
        void detect(InputArray edges, InputArray dx, InputArray dy, OutputArray positions, OutputArray votes) { detectImpl(edges, dx, dy, positions, votes); }
 
511
 
 
512
        void setCannyLowThresh(int cannyLowThresh) { cannyLowThresh_ = cannyLowThresh; }
 
513
        int getCannyLowThresh() const { return cannyLowThresh_; }
 
514
 
 
515
        void setCannyHighThresh(int cannyHighThresh) { cannyHighThresh_ = cannyHighThresh; }
 
516
        int getCannyHighThresh() const { return cannyHighThresh_; }
 
517
 
 
518
        void setMinDist(double minDist) { minDist_ = minDist; }
 
519
        double getMinDist() const { return minDist_; }
 
520
 
 
521
        void setDp(double dp) { dp_ = dp; }
 
522
        double getDp() const { return dp_; }
 
523
 
 
524
        void setMaxBufferSize(int maxBufferSize) { maxBufferSize_ = maxBufferSize; }
 
525
        int getMaxBufferSize() const { return maxBufferSize_; }
 
526
 
 
527
        void setXi(double xi) { xi_ = xi; }
 
528
        double getXi() const { return xi_; }
 
529
 
 
530
        void setLevels(int levels) { levels_ = levels; }
 
531
        int getLevels() const { return levels_; }
 
532
 
 
533
        void setAngleEpsilon(double angleEpsilon) { angleEpsilon_ = angleEpsilon; }
 
534
        double getAngleEpsilon() const { return angleEpsilon_; }
 
535
 
 
536
        void setMinAngle(double minAngle) { minAngle_ = minAngle; }
 
537
        double getMinAngle() const { return minAngle_; }
 
538
 
 
539
        void setMaxAngle(double maxAngle) { maxAngle_ = maxAngle; }
 
540
        double getMaxAngle() const { return maxAngle_; }
 
541
 
 
542
        void setAngleStep(double angleStep) { angleStep_ = angleStep; }
 
543
        double getAngleStep() const { return angleStep_; }
 
544
 
 
545
        void setAngleThresh(int angleThresh) { angleThresh_ = angleThresh; }
 
546
        int getAngleThresh() const { return angleThresh_; }
 
547
 
 
548
        void setMinScale(double minScale) { minScale_ = minScale; }
 
549
        double getMinScale() const { return minScale_; }
 
550
 
 
551
        void setMaxScale(double maxScale) { maxScale_ = maxScale; }
 
552
        double getMaxScale() const { return maxScale_; }
 
553
 
 
554
        void setScaleStep(double scaleStep) { scaleStep_ = scaleStep; }
 
555
        double getScaleStep() const { return scaleStep_; }
 
556
 
 
557
        void setScaleThresh(int scaleThresh) { scaleThresh_ = scaleThresh; }
 
558
        int getScaleThresh() const { return scaleThresh_; }
 
559
 
 
560
        void setPosThresh(int posThresh) { posThresh_ = posThresh; }
 
561
        int getPosThresh() const { return posThresh_; }
 
562
 
 
563
    private:
 
564
        void processTempl();
 
565
        void processImage();
 
566
 
 
567
        int maxBufferSize_;
 
568
        double xi_;
 
569
        int levels_;
 
570
        double angleEpsilon_;
 
571
 
 
572
        double minAngle_;
 
573
        double maxAngle_;
 
574
        double angleStep_;
 
575
        int angleThresh_;
 
576
 
 
577
        double minScale_;
 
578
        double maxScale_;
 
579
        double scaleStep_;
 
580
        int scaleThresh_;
 
581
 
 
582
        int posThresh_;
 
583
 
 
584
        struct ContourPoint
 
585
        {
 
586
            Point2d pos;
 
587
            double theta;
 
588
        };
 
589
 
 
590
        struct Feature
 
591
        {
 
592
            ContourPoint p1;
 
593
            ContourPoint p2;
 
594
 
 
595
            double alpha12;
 
596
            double d12;
 
597
 
 
598
            Point2d r1;
 
599
            Point2d r2;
 
600
        };
 
601
 
 
602
        void buildFeatureList(const Mat& edges, const Mat& dx, const Mat& dy, std::vector< std::vector<Feature> >& features, Point2d center = Point2d());
 
603
        void getContourPoints(const Mat& edges, const Mat& dx, const Mat& dy, std::vector<ContourPoint>& points);
 
604
 
 
605
        void calcOrientation();
 
606
        void calcScale(double angle);
 
607
        void calcPosition(double angle, int angleVotes, double scale, int scaleVotes);
 
608
 
 
609
        std::vector< std::vector<Feature> > templFeatures_;
 
610
        std::vector< std::vector<Feature> > imageFeatures_;
 
611
 
 
612
        std::vector< std::pair<double, int> > angles_;
 
613
        std::vector< std::pair<double, int> > scales_;
 
614
    };
 
615
 
 
616
    double clampAngle(double a)
 
617
    {
 
618
        double res = a;
 
619
 
 
620
        while (res > 360.0)
 
621
            res -= 360.0;
 
622
        while (res < 0)
 
623
            res += 360.0;
 
624
 
 
625
        return res;
 
626
    }
 
627
 
 
628
    bool angleEq(double a, double b, double eps = 1.0)
 
629
    {
 
630
        return (fabs(clampAngle(a - b)) <= eps);
 
631
    }
 
632
 
 
633
    GeneralizedHoughGuilImpl::GeneralizedHoughGuilImpl()
 
634
    {
 
635
        maxBufferSize_ = 1000;
 
636
        xi_ = 90.0;
 
637
        levels_ = 360;
 
638
        angleEpsilon_ = 1.0;
 
639
 
 
640
        minAngle_ = 0.0;
 
641
        maxAngle_ = 360.0;
 
642
        angleStep_ = 1.0;
 
643
        angleThresh_ = 15000;
 
644
 
 
645
        minScale_ = 0.5;
 
646
        maxScale_ = 2.0;
 
647
        scaleStep_ = 0.05;
 
648
        scaleThresh_ = 1000;
 
649
 
 
650
        posThresh_ = 100;
 
651
    }
 
652
 
 
653
    void GeneralizedHoughGuilImpl::processTempl()
 
654
    {
 
655
        buildFeatureList(templEdges_, templDx_, templDy_, templFeatures_, templCenter_);
 
656
    }
 
657
 
 
658
    void GeneralizedHoughGuilImpl::processImage()
 
659
    {
 
660
        buildFeatureList(imageEdges_, imageDx_, imageDy_, imageFeatures_);
 
661
 
 
662
        calcOrientation();
 
663
 
 
664
        for (size_t i = 0; i < angles_.size(); ++i)
 
665
        {
 
666
            const double angle = angles_[i].first;
 
667
            const int angleVotes = angles_[i].second;
 
668
 
 
669
            calcScale(angle);
 
670
 
 
671
            for (size_t j = 0; j < scales_.size(); ++j)
 
672
            {
 
673
                const double scale = scales_[j].first;
 
674
                const int scaleVotes = scales_[j].second;
 
675
 
 
676
                calcPosition(angle, angleVotes, scale, scaleVotes);
 
677
            }
 
678
        }
 
679
    }
 
680
 
 
681
    void GeneralizedHoughGuilImpl::buildFeatureList(const Mat& edges, const Mat& dx, const Mat& dy, std::vector< std::vector<Feature> >& features, Point2d center)
 
682
    {
 
683
        CV_Assert( levels_ > 0 );
 
684
 
 
685
        const double maxDist = sqrt((double) templSize_.width * templSize_.width + templSize_.height * templSize_.height) * maxScale_;
 
686
 
 
687
        const double alphaScale = levels_ / 360.0;
 
688
 
 
689
        std::vector<ContourPoint> points;
 
690
        getContourPoints(edges, dx, dy, points);
 
691
 
 
692
        features.resize(levels_ + 1);
 
693
        std::for_each(features.begin(), features.end(), std::mem_fun_ref(&std::vector<Feature>::clear));
 
694
        std::for_each(features.begin(), features.end(), std::bind2nd(std::mem_fun_ref(&std::vector<Feature>::reserve), maxBufferSize_));
 
695
 
 
696
        for (size_t i = 0; i < points.size(); ++i)
 
697
        {
 
698
            ContourPoint p1 = points[i];
 
699
 
 
700
            for (size_t j = 0; j < points.size(); ++j)
 
701
            {
 
702
                ContourPoint p2 = points[j];
 
703
 
 
704
                if (angleEq(p1.theta - p2.theta, xi_, angleEpsilon_))
 
705
                {
 
706
                    const Point2d d = p1.pos - p2.pos;
 
707
 
 
708
                    Feature f;
 
709
 
 
710
                    f.p1 = p1;
 
711
                    f.p2 = p2;
 
712
 
 
713
                    f.alpha12 = clampAngle(fastAtan2((float)d.y, (float)d.x) - p1.theta);
 
714
                    f.d12 = norm(d);
 
715
 
 
716
                    if (f.d12 > maxDist)
 
717
                        continue;
 
718
 
 
719
                    f.r1 = p1.pos - center;
 
720
                    f.r2 = p2.pos - center;
 
721
 
 
722
                    const int n = cvRound(f.alpha12 * alphaScale);
 
723
 
 
724
                    if (features[n].size() < static_cast<size_t>(maxBufferSize_))
 
725
                        features[n].push_back(f);
 
726
                }
 
727
            }
 
728
        }
 
729
    }
 
730
 
 
731
    void GeneralizedHoughGuilImpl::getContourPoints(const Mat& edges, const Mat& dx, const Mat& dy, std::vector<ContourPoint>& points)
 
732
    {
 
733
        CV_Assert( edges.type() == CV_8UC1 );
 
734
        CV_Assert( dx.type() == CV_32FC1 && dx.size == edges.size );
 
735
        CV_Assert( dy.type() == dx.type() && dy.size == edges.size );
 
736
 
 
737
        points.clear();
 
738
        points.reserve(edges.size().area());
 
739
 
 
740
        for (int y = 0; y < edges.rows; ++y)
 
741
        {
 
742
            const uchar* edgesRow = edges.ptr(y);
 
743
            const float* dxRow = dx.ptr<float>(y);
 
744
            const float* dyRow = dy.ptr<float>(y);
 
745
 
 
746
            for (int x = 0; x < edges.cols; ++x)
 
747
            {
 
748
                if (edgesRow[x] && (notNull(dyRow[x]) || notNull(dxRow[x])))
 
749
                {
 
750
                    ContourPoint p;
 
751
 
 
752
                    p.pos = Point2d(x, y);
 
753
                    p.theta = fastAtan2(dyRow[x], dxRow[x]);
 
754
 
 
755
                    points.push_back(p);
 
756
                }
 
757
            }
 
758
        }
 
759
    }
 
760
 
 
761
    void GeneralizedHoughGuilImpl::calcOrientation()
 
762
    {
 
763
        CV_Assert( levels_ > 0 );
 
764
        CV_Assert( templFeatures_.size() == static_cast<size_t>(levels_ + 1) );
 
765
        CV_Assert( imageFeatures_.size() == templFeatures_.size() );
 
766
        CV_Assert( minAngle_ >= 0.0 && minAngle_ < maxAngle_ && maxAngle_ <= 360.0 );
 
767
        CV_Assert( angleStep_ > 0.0 && angleStep_ < 360.0 );
 
768
        CV_Assert( angleThresh_ > 0 );
 
769
 
 
770
        const double iAngleStep = 1.0 / angleStep_;
 
771
        const int angleRange = cvCeil((maxAngle_ - minAngle_) * iAngleStep);
 
772
 
 
773
        std::vector<int> OHist(angleRange + 1, 0);
 
774
        for (int i = 0; i <= levels_; ++i)
 
775
        {
 
776
            const std::vector<Feature>& templRow = templFeatures_[i];
 
777
            const std::vector<Feature>& imageRow = imageFeatures_[i];
 
778
 
 
779
            for (size_t j = 0; j < templRow.size(); ++j)
 
780
            {
 
781
                Feature templF = templRow[j];
 
782
 
 
783
                for (size_t k = 0; k < imageRow.size(); ++k)
 
784
                {
 
785
                    Feature imF = imageRow[k];
 
786
 
 
787
                    const double angle = clampAngle(imF.p1.theta - templF.p1.theta);
 
788
                    if (angle >= minAngle_ && angle <= maxAngle_)
 
789
                    {
 
790
                        const int n = cvRound((angle - minAngle_) * iAngleStep);
 
791
                        ++OHist[n];
 
792
                    }
 
793
                }
 
794
            }
 
795
        }
 
796
 
 
797
        angles_.clear();
 
798
 
 
799
        for (int n = 0; n < angleRange; ++n)
 
800
        {
 
801
            if (OHist[n] >= angleThresh_)
 
802
            {
 
803
                const double angle = minAngle_ + n * angleStep_;
 
804
                angles_.push_back(std::make_pair(angle, OHist[n]));
 
805
            }
 
806
        }
 
807
    }
 
808
 
 
809
    void GeneralizedHoughGuilImpl::calcScale(double angle)
 
810
    {
 
811
        CV_Assert( levels_ > 0 );
 
812
        CV_Assert( templFeatures_.size() == static_cast<size_t>(levels_ + 1) );
 
813
        CV_Assert( imageFeatures_.size() == templFeatures_.size() );
 
814
        CV_Assert( minScale_ > 0.0 && minScale_ < maxScale_ );
 
815
        CV_Assert( scaleStep_ > 0.0 );
 
816
        CV_Assert( scaleThresh_ > 0 );
 
817
 
 
818
        const double iScaleStep = 1.0 / scaleStep_;
 
819
        const int scaleRange = cvCeil((maxScale_ - minScale_) * iScaleStep);
 
820
 
 
821
        std::vector<int> SHist(scaleRange + 1, 0);
 
822
 
 
823
        for (int i = 0; i <= levels_; ++i)
 
824
        {
 
825
            const std::vector<Feature>& templRow = templFeatures_[i];
 
826
            const std::vector<Feature>& imageRow = imageFeatures_[i];
 
827
 
 
828
            for (size_t j = 0; j < templRow.size(); ++j)
 
829
            {
 
830
                Feature templF = templRow[j];
 
831
 
 
832
                templF.p1.theta += angle;
 
833
 
 
834
                for (size_t k = 0; k < imageRow.size(); ++k)
 
835
                {
 
836
                    Feature imF = imageRow[k];
 
837
 
 
838
                    if (angleEq(imF.p1.theta, templF.p1.theta, angleEpsilon_))
 
839
                    {
 
840
                        const double scale = imF.d12 / templF.d12;
 
841
                        if (scale >= minScale_ && scale <= maxScale_)
 
842
                        {
 
843
                            const int s = cvRound((scale - minScale_) * iScaleStep);
 
844
                            ++SHist[s];
 
845
                        }
 
846
                    }
 
847
                }
 
848
            }
 
849
        }
 
850
 
 
851
        scales_.clear();
 
852
 
 
853
        for (int s = 0; s < scaleRange; ++s)
 
854
        {
 
855
            if (SHist[s] >= scaleThresh_)
 
856
            {
 
857
                const double scale = minScale_ + s * scaleStep_;
 
858
                scales_.push_back(std::make_pair(scale, SHist[s]));
 
859
            }
 
860
        }
 
861
    }
 
862
 
 
863
    void GeneralizedHoughGuilImpl::calcPosition(double angle, int angleVotes, double scale, int scaleVotes)
 
864
    {
 
865
        CV_Assert( levels_ > 0 );
 
866
        CV_Assert( templFeatures_.size() == static_cast<size_t>(levels_ + 1) );
 
867
        CV_Assert( imageFeatures_.size() == templFeatures_.size() );
 
868
        CV_Assert( dp_ > 0.0 );
 
869
        CV_Assert( posThresh_ > 0 );
 
870
 
 
871
        const double sinVal = sin(toRad(angle));
 
872
        const double cosVal = cos(toRad(angle));
 
873
        const double idp = 1.0 / dp_;
 
874
 
 
875
        const int histRows = cvCeil(imageSize_.height * idp);
 
876
        const int histCols = cvCeil(imageSize_.width * idp);
 
877
 
 
878
        Mat DHist(histRows + 2, histCols + 2, CV_32SC1, Scalar::all(0));
 
879
 
 
880
        for (int i = 0; i <= levels_; ++i)
 
881
        {
 
882
            const std::vector<Feature>& templRow = templFeatures_[i];
 
883
            const std::vector<Feature>& imageRow = imageFeatures_[i];
 
884
 
 
885
            for (size_t j = 0; j < templRow.size(); ++j)
 
886
            {
 
887
                Feature templF = templRow[j];
 
888
 
 
889
                templF.p1.theta += angle;
 
890
 
 
891
                templF.r1 *= scale;
 
892
                templF.r2 *= scale;
 
893
 
 
894
                templF.r1 = Point2d(cosVal * templF.r1.x - sinVal * templF.r1.y, sinVal * templF.r1.x + cosVal * templF.r1.y);
 
895
                templF.r2 = Point2d(cosVal * templF.r2.x - sinVal * templF.r2.y, sinVal * templF.r2.x + cosVal * templF.r2.y);
 
896
 
 
897
                for (size_t k = 0; k < imageRow.size(); ++k)
 
898
                {
 
899
                    Feature imF = imageRow[k];
 
900
 
 
901
                    if (angleEq(imF.p1.theta, templF.p1.theta, angleEpsilon_))
 
902
                    {
 
903
                        Point2d c1, c2;
 
904
 
 
905
                        c1 = imF.p1.pos - templF.r1;
 
906
                        c1 *= idp;
 
907
 
 
908
                        c2 = imF.p2.pos - templF.r2;
 
909
                        c2 *= idp;
 
910
 
 
911
                        if (fabs(c1.x - c2.x) > 1 || fabs(c1.y - c2.y) > 1)
 
912
                            continue;
 
913
 
 
914
                        if (c1.y >= 0 && c1.y < histRows && c1.x >= 0 && c1.x < histCols)
 
915
                            ++DHist.at<int>(cvRound(c1.y) + 1, cvRound(c1.x) + 1);
 
916
                    }
 
917
                }
 
918
            }
 
919
        }
 
920
 
 
921
        for(int y = 0; y < histRows; ++y)
 
922
        {
 
923
            const int* prevRow = DHist.ptr<int>(y);
 
924
            const int* curRow = DHist.ptr<int>(y + 1);
 
925
            const int* nextRow = DHist.ptr<int>(y + 2);
 
926
 
 
927
            for(int x = 0; x < histCols; ++x)
 
928
            {
 
929
                const int votes = curRow[x + 1];
 
930
 
 
931
                if (votes > posThresh_ && votes > curRow[x] && votes >= curRow[x + 2] && votes > prevRow[x + 1] && votes >= nextRow[x + 1])
 
932
                {
 
933
                    posOutBuf_.push_back(Vec4f(static_cast<float>(x * dp_), static_cast<float>(y * dp_), static_cast<float>(scale), static_cast<float>(angle)));
 
934
                    voteOutBuf_.push_back(Vec3i(votes, scaleVotes, angleVotes));
 
935
                }
 
936
            }
 
937
        }
 
938
    }
 
939
}
 
940
 
 
941
Ptr<GeneralizedHoughGuil> cv::createGeneralizedHoughGuil()
 
942
{
 
943
    return makePtr<GeneralizedHoughGuilImpl>();
 
944
}