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