/*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // // By downloading, copying, installing or using the software you agree to this license. // If you do not agree to this license, do not download, install, // copy or use the software. // // // License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. // Copyright (C) 2009, Willow Garage Inc., all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistribution's of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistribution's in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * The name of the copyright holders may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and // any express or implied warranties, including, but not limited to, the implied // warranties of merchantability and fitness for a particular purpose are disclaimed. // In no event shall the Intel Corporation or contributors be liable for any direct, // indirect, incidental, special, exemplary, or consequential damages // (including, but not limited to, procurement of substitute goods or services; // loss of use, data, or profits; or business interruption) however caused // and on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out of // the use of this software, even if advised of the possibility of such damage. // //M*/ #include "precomp.hpp" using namespace cv; using namespace cv::cuda; #if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) || !defined(HAVE_OPENCV_CUDAARITHM) Ptr cv::cuda::createGeneralizedHoughBallard() { throw_no_cuda(); return Ptr(); } Ptr cv::cuda::createGeneralizedHoughGuil() { throw_no_cuda(); return Ptr(); } #else /* !defined (HAVE_CUDA) */ namespace cv { namespace cuda { namespace device { namespace ght { template int buildEdgePointList_gpu(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList); void buildRTable_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, PtrStepSz r_table, int* r_sizes, short2 templCenter, int levels); void Ballard_Pos_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, PtrStepSz r_table, const int* r_sizes, PtrStepSzi hist, float dp, int levels); int Ballard_Pos_findPosInHist_gpu(PtrStepSzi hist, float4* out, int3* votes, int maxSize, float dp, int threshold); void Guil_Full_setTemplFeatures(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2); void Guil_Full_setImageFeatures(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2); void Guil_Full_buildTemplFeatureList_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, int* sizes, int maxSize, float xi, float angleEpsilon, int levels, float2 center, float maxDist); void Guil_Full_buildImageFeatureList_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount, int* sizes, int maxSize, float xi, float angleEpsilon, int levels, float2 center, float maxDist); void Guil_Full_calcOHist_gpu(const int* templSizes, const int* imageSizes, int* OHist, float minAngle, float maxAngle, float angleStep, int angleRange, int levels, int tMaxSize); void Guil_Full_calcSHist_gpu(const int* templSizes, const int* imageSizes, int* SHist, float angle, float angleEpsilon, float minScale, float maxScale, float iScaleStep, int scaleRange, int levels, int tMaxSize); void Guil_Full_calcPHist_gpu(const int* templSizes, const int* imageSizes, PtrStepSzi PHist, float angle, float angleEpsilon, float scale, float dp, int levels, int tMaxSize); int Guil_Full_findPosInHist_gpu(PtrStepSzi hist, float4* out, int3* votes, int curSize, int maxSize, float angle, int angleVotes, float scale, int scaleVotes, float dp, int threshold); } }}} // common namespace { class GeneralizedHoughBase { protected: GeneralizedHoughBase(); virtual ~GeneralizedHoughBase() {} void setTemplateImpl(InputArray templ, Point templCenter); void setTemplateImpl(InputArray edges, InputArray dx, InputArray dy, Point templCenter); void detectImpl(InputArray image, OutputArray positions, OutputArray votes); void detectImpl(InputArray edges, InputArray dx, InputArray dy, OutputArray positions, OutputArray votes); void buildEdgePointList(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy); virtual void processTempl() = 0; virtual void processImage() = 0; int cannyLowThresh_; int cannyHighThresh_; double minDist_; double dp_; int maxBufferSize_; Size templSize_; Point templCenter_; GpuMat templEdges_; GpuMat templDx_; GpuMat templDy_; Size imageSize_; GpuMat imageEdges_; GpuMat imageDx_; GpuMat imageDy_; GpuMat edgePointList_; GpuMat outBuf_; int posCount_; private: #ifdef HAVE_OPENCV_CUDAFILTERS void calcEdges(InputArray src, GpuMat& edges, GpuMat& dx, GpuMat& dy); #endif void filterMinDist(); void convertTo(OutputArray positions, OutputArray votes); #ifdef HAVE_OPENCV_CUDAFILTERS Ptr canny_; Ptr filterDx_; Ptr filterDy_; #endif std::vector oldPosBuf_; std::vector oldVoteBuf_; std::vector newPosBuf_; std::vector newVoteBuf_; std::vector indexies_; }; GeneralizedHoughBase::GeneralizedHoughBase() { cannyLowThresh_ = 50; cannyHighThresh_ = 100; minDist_ = 1.0; dp_ = 1.0; maxBufferSize_ = 10000; #ifdef HAVE_OPENCV_CUDAFILTERS canny_ = cuda::createCannyEdgeDetector(cannyLowThresh_, cannyHighThresh_); filterDx_ = cuda::createSobelFilter(CV_8UC1, CV_32S, 1, 0); filterDy_ = cuda::createSobelFilter(CV_8UC1, CV_32S, 0, 1); #endif } #ifdef HAVE_OPENCV_CUDAFILTERS void GeneralizedHoughBase::calcEdges(InputArray _src, GpuMat& edges, GpuMat& dx, GpuMat& dy) { GpuMat src = _src.getGpuMat(); CV_Assert( src.type() == CV_8UC1 ); CV_Assert( cannyLowThresh_ > 0 && cannyLowThresh_ < cannyHighThresh_ ); ensureSizeIsEnough(src.size(), CV_32SC1, dx); ensureSizeIsEnough(src.size(), CV_32SC1, dy); filterDx_->apply(src, dx); filterDy_->apply(src, dy); ensureSizeIsEnough(src.size(), CV_8UC1, edges); canny_->setLowThreshold(cannyLowThresh_); canny_->setHighThreshold(cannyHighThresh_); canny_->detect(dx, dy, edges); } #endif void GeneralizedHoughBase::setTemplateImpl(InputArray templ, Point templCenter) { #ifndef HAVE_OPENCV_CUDAFILTERS (void) templ; (void) templCenter; throw_no_cuda(); #else calcEdges(templ, templEdges_, templDx_, templDy_); if (templCenter == Point(-1, -1)) templCenter = Point(templEdges_.cols / 2, templEdges_.rows / 2); templSize_ = templEdges_.size(); templCenter_ = templCenter; processTempl(); #endif } void GeneralizedHoughBase::setTemplateImpl(InputArray edges, InputArray dx, InputArray dy, Point templCenter) { edges.getGpuMat().copyTo(templEdges_); dx.getGpuMat().copyTo(templDx_); dy.getGpuMat().copyTo(templDy_); CV_Assert( templEdges_.type() == CV_8UC1 ); CV_Assert( templDx_.type() == CV_32FC1 && templDx_.size() == templEdges_.size() ); CV_Assert( templDy_.type() == templDx_.type() && templDy_.size() == templEdges_.size() ); if (templCenter == Point(-1, -1)) templCenter = Point(templEdges_.cols / 2, templEdges_.rows / 2); templSize_ = templEdges_.size(); templCenter_ = templCenter; processTempl(); } void GeneralizedHoughBase::detectImpl(InputArray image, OutputArray positions, OutputArray votes) { #ifndef HAVE_OPENCV_CUDAFILTERS (void) image; (void) positions; (void) votes; throw_no_cuda(); #else calcEdges(image, imageEdges_, imageDx_, imageDy_); imageSize_ = imageEdges_.size(); posCount_ = 0; processImage(); if (posCount_ == 0) { positions.release(); if (votes.needed()) votes.release(); } else { if (minDist_ > 1) filterMinDist(); convertTo(positions, votes); } #endif } void GeneralizedHoughBase::detectImpl(InputArray edges, InputArray dx, InputArray dy, OutputArray positions, OutputArray votes) { edges.getGpuMat().copyTo(imageEdges_); dx.getGpuMat().copyTo(imageDx_); dy.getGpuMat().copyTo(imageDy_); CV_Assert( imageEdges_.type() == CV_8UC1 ); CV_Assert( imageDx_.type() == CV_32FC1 && imageDx_.size() == imageEdges_.size() ); CV_Assert( imageDy_.type() == imageDx_.type() && imageDy_.size() == imageEdges_.size() ); imageSize_ = imageEdges_.size(); posCount_ = 0; processImage(); if (posCount_ == 0) { positions.release(); if (votes.needed()) votes.release(); } else { if (minDist_ > 1) filterMinDist(); convertTo(positions, votes); } } void GeneralizedHoughBase::buildEdgePointList(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy) { using namespace cv::cuda::device::ght; typedef int (*func_t)(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList); static const func_t funcs[] = { 0, 0, 0, buildEdgePointList_gpu, buildEdgePointList_gpu, buildEdgePointList_gpu, 0 }; CV_Assert( edges.type() == CV_8UC1 ); CV_Assert( dx.size() == edges.size() ); CV_Assert( dy.type() == dx.type() && dy.size() == edges.size() ); const func_t func = funcs[dx.depth()]; CV_Assert( func != 0 ); edgePointList_.cols = (int) (edgePointList_.step / sizeof(int)); ensureSizeIsEnough(2, edges.size().area(), CV_32SC1, edgePointList_); edgePointList_.cols = func(edges, dx, dy, edgePointList_.ptr(0), edgePointList_.ptr(1)); } struct IndexCmp { const int3* aux; explicit IndexCmp(const int3* _aux) : aux(_aux) {} bool operator ()(int l1, int l2) const { return aux[l1].x > aux[l2].x; } }; void GeneralizedHoughBase::filterMinDist() { oldPosBuf_.resize(posCount_); oldVoteBuf_.resize(posCount_); cudaSafeCall( cudaMemcpy(&oldPosBuf_[0], outBuf_.ptr(0), posCount_ * sizeof(float4), cudaMemcpyDeviceToHost) ); cudaSafeCall( cudaMemcpy(&oldVoteBuf_[0], outBuf_.ptr(1), posCount_ * sizeof(int3), cudaMemcpyDeviceToHost) ); indexies_.resize(posCount_); for (int i = 0; i < posCount_; ++i) indexies_[i] = i; std::sort(indexies_.begin(), indexies_.end(), IndexCmp(&oldVoteBuf_[0])); newPosBuf_.clear(); newVoteBuf_.clear(); newPosBuf_.reserve(posCount_); newVoteBuf_.reserve(posCount_); const int cellSize = cvRound(minDist_); const int gridWidth = (imageSize_.width + cellSize - 1) / cellSize; const int gridHeight = (imageSize_.height + cellSize - 1) / cellSize; std::vector< std::vector > grid(gridWidth * gridHeight); const double minDist2 = minDist_ * minDist_; for (int i = 0; i < posCount_; ++i) { const int ind = indexies_[i]; Point2f p(oldPosBuf_[ind].x, oldPosBuf_[ind].y); bool good = true; const int xCell = static_cast(p.x / cellSize); const int yCell = static_cast(p.y / cellSize); int x1 = xCell - 1; int y1 = yCell - 1; int x2 = xCell + 1; int y2 = yCell + 1; // boundary check x1 = std::max(0, x1); y1 = std::max(0, y1); x2 = std::min(gridWidth - 1, x2); y2 = std::min(gridHeight - 1, y2); for (int yy = y1; yy <= y2; ++yy) { for (int xx = x1; xx <= x2; ++xx) { const std::vector& m = grid[yy * gridWidth + xx]; for(size_t j = 0; j < m.size(); ++j) { const Point2f d = p - m[j]; if (d.ddot(d) < minDist2) { good = false; goto break_out; } } } } break_out: if(good) { grid[yCell * gridWidth + xCell].push_back(p); newPosBuf_.push_back(oldPosBuf_[ind]); newVoteBuf_.push_back(oldVoteBuf_[ind]); } } posCount_ = static_cast(newPosBuf_.size()); cudaSafeCall( cudaMemcpy(outBuf_.ptr(0), &newPosBuf_[0], posCount_ * sizeof(float4), cudaMemcpyHostToDevice) ); cudaSafeCall( cudaMemcpy(outBuf_.ptr(1), &newVoteBuf_[0], posCount_ * sizeof(int3), cudaMemcpyHostToDevice) ); } void GeneralizedHoughBase::convertTo(OutputArray positions, OutputArray votes) { ensureSizeIsEnough(1, posCount_, CV_32FC4, positions); GpuMat(1, posCount_, CV_32FC4, outBuf_.ptr(0), outBuf_.step).copyTo(positions); if (votes.needed()) { ensureSizeIsEnough(1, posCount_, CV_32FC3, votes); GpuMat(1, posCount_, CV_32FC4, outBuf_.ptr(1), outBuf_.step).copyTo(votes); } } } // GeneralizedHoughBallard namespace { class GeneralizedHoughBallardImpl : public GeneralizedHoughBallard, private GeneralizedHoughBase { public: GeneralizedHoughBallardImpl(); void setTemplate(InputArray templ, Point templCenter) { setTemplateImpl(templ, templCenter); } void setTemplate(InputArray edges, InputArray dx, InputArray dy, Point templCenter) { setTemplateImpl(edges, dx, dy, templCenter); } void detect(InputArray image, OutputArray positions, OutputArray votes) { detectImpl(image, positions, votes); } void detect(InputArray edges, InputArray dx, InputArray dy, OutputArray positions, OutputArray votes) { detectImpl(edges, dx, dy, positions, votes); } void setCannyLowThresh(int cannyLowThresh) { cannyLowThresh_ = cannyLowThresh; } int getCannyLowThresh() const { return cannyLowThresh_; } void setCannyHighThresh(int cannyHighThresh) { cannyHighThresh_ = cannyHighThresh; } int getCannyHighThresh() const { return cannyHighThresh_; } void setMinDist(double minDist) { minDist_ = minDist; } double getMinDist() const { return minDist_; } void setDp(double dp) { dp_ = dp; } double getDp() const { return dp_; } void setMaxBufferSize(int maxBufferSize) { maxBufferSize_ = maxBufferSize; } int getMaxBufferSize() const { return maxBufferSize_; } void setLevels(int levels) { levels_ = levels; } int getLevels() const { return levels_; } void setVotesThreshold(int votesThreshold) { votesThreshold_ = votesThreshold; } int getVotesThreshold() const { return votesThreshold_; } private: void processTempl(); void processImage(); void calcHist(); void findPosInHist(); int levels_; int votesThreshold_; GpuMat r_table_; GpuMat r_sizes_; GpuMat hist_; }; GeneralizedHoughBallardImpl::GeneralizedHoughBallardImpl() { levels_ = 360; votesThreshold_ = 100; } void GeneralizedHoughBallardImpl::processTempl() { using namespace cv::cuda::device::ght; CV_Assert( levels_ > 0 ); buildEdgePointList(templEdges_, templDx_, templDy_); ensureSizeIsEnough(levels_ + 1, maxBufferSize_, CV_16SC2, r_table_); ensureSizeIsEnough(1, levels_ + 1, CV_32SC1, r_sizes_); r_sizes_.setTo(Scalar::all(0)); if (edgePointList_.cols > 0) { buildRTable_gpu(edgePointList_.ptr(0), edgePointList_.ptr(1), edgePointList_.cols, r_table_, r_sizes_.ptr(), make_short2(templCenter_.x, templCenter_.y), levels_); cuda::min(r_sizes_, maxBufferSize_, r_sizes_); } } void GeneralizedHoughBallardImpl::processImage() { calcHist(); findPosInHist(); } void GeneralizedHoughBallardImpl::calcHist() { using namespace cv::cuda::device::ght; CV_Assert( levels_ > 0 && r_table_.rows == (levels_ + 1) && r_sizes_.cols == (levels_ + 1) ); CV_Assert( dp_ > 0.0); const double idp = 1.0 / dp_; buildEdgePointList(imageEdges_, imageDx_, imageDy_); ensureSizeIsEnough(cvCeil(imageSize_.height * idp) + 2, cvCeil(imageSize_.width * idp) + 2, CV_32SC1, hist_); hist_.setTo(Scalar::all(0)); if (edgePointList_.cols > 0) { Ballard_Pos_calcHist_gpu(edgePointList_.ptr(0), edgePointList_.ptr(1), edgePointList_.cols, r_table_, r_sizes_.ptr(), hist_, (float)dp_, levels_); } } void GeneralizedHoughBallardImpl::findPosInHist() { using namespace cv::cuda::device::ght; CV_Assert( votesThreshold_ > 0 ); ensureSizeIsEnough(2, maxBufferSize_, CV_32FC4, outBuf_); posCount_ = Ballard_Pos_findPosInHist_gpu(hist_, outBuf_.ptr(0), outBuf_.ptr(1), maxBufferSize_, (float)dp_, votesThreshold_); } } Ptr cv::cuda::createGeneralizedHoughBallard() { return makePtr(); } // GeneralizedHoughGuil namespace { class GeneralizedHoughGuilImpl : public GeneralizedHoughGuil, private GeneralizedHoughBase { public: GeneralizedHoughGuilImpl(); void setTemplate(InputArray templ, Point templCenter) { setTemplateImpl(templ, templCenter); } void setTemplate(InputArray edges, InputArray dx, InputArray dy, Point templCenter) { setTemplateImpl(edges, dx, dy, templCenter); } void detect(InputArray image, OutputArray positions, OutputArray votes) { detectImpl(image, positions, votes); } void detect(InputArray edges, InputArray dx, InputArray dy, OutputArray positions, OutputArray votes) { detectImpl(edges, dx, dy, positions, votes); } void setCannyLowThresh(int cannyLowThresh) { cannyLowThresh_ = cannyLowThresh; } int getCannyLowThresh() const { return cannyLowThresh_; } void setCannyHighThresh(int cannyHighThresh) { cannyHighThresh_ = cannyHighThresh; } int getCannyHighThresh() const { return cannyHighThresh_; } void setMinDist(double minDist) { minDist_ = minDist; } double getMinDist() const { return minDist_; } void setDp(double dp) { dp_ = dp; } double getDp() const { return dp_; } void setMaxBufferSize(int maxBufferSize) { maxBufferSize_ = maxBufferSize; } int getMaxBufferSize() const { return maxBufferSize_; } void setXi(double xi) { xi_ = xi; } double getXi() const { return xi_; } void setLevels(int levels) { levels_ = levels; } int getLevels() const { return levels_; } void setAngleEpsilon(double angleEpsilon) { angleEpsilon_ = angleEpsilon; } double getAngleEpsilon() const { return angleEpsilon_; } void setMinAngle(double minAngle) { minAngle_ = minAngle; } double getMinAngle() const { return minAngle_; } void setMaxAngle(double maxAngle) { maxAngle_ = maxAngle; } double getMaxAngle() const { return maxAngle_; } void setAngleStep(double angleStep) { angleStep_ = angleStep; } double getAngleStep() const { return angleStep_; } void setAngleThresh(int angleThresh) { angleThresh_ = angleThresh; } int getAngleThresh() const { return angleThresh_; } void setMinScale(double minScale) { minScale_ = minScale; } double getMinScale() const { return minScale_; } void setMaxScale(double maxScale) { maxScale_ = maxScale; } double getMaxScale() const { return maxScale_; } void setScaleStep(double scaleStep) { scaleStep_ = scaleStep; } double getScaleStep() const { return scaleStep_; } void setScaleThresh(int scaleThresh) { scaleThresh_ = scaleThresh; } int getScaleThresh() const { return scaleThresh_; } void setPosThresh(int posThresh) { posThresh_ = posThresh; } int getPosThresh() const { return posThresh_; } private: void processTempl(); void processImage(); double xi_; int levels_; double angleEpsilon_; double minAngle_; double maxAngle_; double angleStep_; int angleThresh_; double minScale_; double maxScale_; double scaleStep_; int scaleThresh_; int posThresh_; struct Feature { GpuMat p1_pos; GpuMat p1_theta; GpuMat p2_pos; GpuMat d12; GpuMat r1; GpuMat r2; GpuMat sizes; int maxSize; void create(int levels, int maxCapacity, bool isTempl); }; typedef void (*set_func_t)(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2); typedef void (*build_func_t)(const unsigned int* coordList, const float* thetaList, int pointsCount, int* sizes, int maxSize, float xi, float angleEpsilon, int levels, float2 center, float maxDist); void buildFeatureList(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, Feature& features, set_func_t set_func, build_func_t build_func, bool isTempl, Point2d center = Point2d()); void calcOrientation(); void calcScale(double angle); void calcPosition(double angle, int angleVotes, double scale, int scaleVotes); Feature templFeatures_; Feature imageFeatures_; std::vector< std::pair > angles_; std::vector< std::pair > scales_; GpuMat hist_; std::vector h_buf_; }; GeneralizedHoughGuilImpl::GeneralizedHoughGuilImpl() { maxBufferSize_ = 1000; xi_ = 90.0; levels_ = 360; angleEpsilon_ = 1.0; minAngle_ = 0.0; maxAngle_ = 360.0; angleStep_ = 1.0; angleThresh_ = 15000; minScale_ = 0.5; maxScale_ = 2.0; scaleStep_ = 0.05; scaleThresh_ = 1000; posThresh_ = 100; } void GeneralizedHoughGuilImpl::processTempl() { using namespace cv::cuda::device::ght; buildFeatureList(templEdges_, templDx_, templDy_, templFeatures_, Guil_Full_setTemplFeatures, Guil_Full_buildTemplFeatureList_gpu, true, templCenter_); h_buf_.resize(templFeatures_.sizes.cols); cudaSafeCall( cudaMemcpy(&h_buf_[0], templFeatures_.sizes.data, h_buf_.size() * sizeof(int), cudaMemcpyDeviceToHost) ); templFeatures_.maxSize = *std::max_element(h_buf_.begin(), h_buf_.end()); } void GeneralizedHoughGuilImpl::processImage() { using namespace cv::cuda::device::ght; CV_Assert( levels_ > 0 ); CV_Assert( templFeatures_.sizes.cols == levels_ + 1 ); CV_Assert( minAngle_ >= 0.0 && minAngle_ < maxAngle_ && maxAngle_ <= 360.0 ); CV_Assert( angleStep_ > 0.0 && angleStep_ < 360.0 ); CV_Assert( angleThresh_ > 0 ); CV_Assert( minScale_ > 0.0 && minScale_ < maxScale_ ); CV_Assert( scaleStep_ > 0.0 ); CV_Assert( scaleThresh_ > 0 ); CV_Assert( dp_ > 0.0 ); CV_Assert( posThresh_ > 0 ); const double iAngleStep = 1.0 / angleStep_; const int angleRange = cvCeil((maxAngle_ - minAngle_) * iAngleStep); const double iScaleStep = 1.0 / scaleStep_; const int scaleRange = cvCeil((maxScale_ - minScale_) * iScaleStep); const double idp = 1.0 / dp_; const int histRows = cvCeil(imageSize_.height * idp); const int histCols = cvCeil(imageSize_.width * idp); ensureSizeIsEnough(histRows + 2, std::max(angleRange + 1, std::max(scaleRange + 1, histCols + 2)), CV_32SC1, hist_); h_buf_.resize(std::max(angleRange + 1, scaleRange + 1)); ensureSizeIsEnough(2, maxBufferSize_, CV_32FC4, outBuf_); buildFeatureList(imageEdges_, imageDx_, imageDy_, imageFeatures_, Guil_Full_setImageFeatures, Guil_Full_buildImageFeatureList_gpu, false); calcOrientation(); for (size_t i = 0; i < angles_.size(); ++i) { const double angle = angles_[i].first; const int angleVotes = angles_[i].second; calcScale(angle); for (size_t j = 0; j < scales_.size(); ++j) { const double scale = scales_[j].first; const int scaleVotes = scales_[j].second; calcPosition(angle, angleVotes, scale, scaleVotes); } } } void GeneralizedHoughGuilImpl::Feature::create(int levels, int maxCapacity, bool isTempl) { if (!isTempl) { ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC2, p1_pos); ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC2, p2_pos); } ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC1, p1_theta); ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC1, d12); if (isTempl) { ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC2, r1); ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC2, r2); } ensureSizeIsEnough(1, levels + 1, CV_32SC1, sizes); sizes.setTo(Scalar::all(0)); maxSize = 0; } void GeneralizedHoughGuilImpl::buildFeatureList(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, Feature& features, set_func_t set_func, build_func_t build_func, bool isTempl, Point2d center) { CV_Assert( levels_ > 0 ); const double maxDist = sqrt((double) templSize_.width * templSize_.width + templSize_.height * templSize_.height) * maxScale_; features.create(levels_, maxBufferSize_, isTempl); set_func(features.p1_pos, features.p1_theta, features.p2_pos, features.d12, features.r1, features.r2); buildEdgePointList(edges, dx, dy); if (edgePointList_.cols > 0) { build_func(edgePointList_.ptr(0), edgePointList_.ptr(1), edgePointList_.cols, features.sizes.ptr(), maxBufferSize_, (float)xi_, (float)angleEpsilon_, levels_, make_float2((float)center.x, (float)center.y), (float)maxDist); } } void GeneralizedHoughGuilImpl::calcOrientation() { using namespace cv::cuda::device::ght; const double iAngleStep = 1.0 / angleStep_; const int angleRange = cvCeil((maxAngle_ - minAngle_) * iAngleStep); hist_.setTo(Scalar::all(0)); Guil_Full_calcOHist_gpu(templFeatures_.sizes.ptr(), imageFeatures_.sizes.ptr(0), hist_.ptr(), (float)minAngle_, (float)maxAngle_, (float)angleStep_, angleRange, levels_, templFeatures_.maxSize); cudaSafeCall( cudaMemcpy(&h_buf_[0], hist_.data, h_buf_.size() * sizeof(int), cudaMemcpyDeviceToHost) ); angles_.clear(); for (int n = 0; n < angleRange; ++n) { if (h_buf_[n] >= angleThresh_) { const double angle = minAngle_ + n * angleStep_; angles_.push_back(std::make_pair(angle, h_buf_[n])); } } } void GeneralizedHoughGuilImpl::calcScale(double angle) { using namespace cv::cuda::device::ght; const double iScaleStep = 1.0 / scaleStep_; const int scaleRange = cvCeil((maxScale_ - minScale_) * iScaleStep); hist_.setTo(Scalar::all(0)); Guil_Full_calcSHist_gpu(templFeatures_.sizes.ptr(), imageFeatures_.sizes.ptr(0), hist_.ptr(), (float)angle, (float)angleEpsilon_, (float)minScale_, (float)maxScale_, (float)iScaleStep, scaleRange, levels_, templFeatures_.maxSize); cudaSafeCall( cudaMemcpy(&h_buf_[0], hist_.data, h_buf_.size() * sizeof(int), cudaMemcpyDeviceToHost) ); scales_.clear(); for (int s = 0; s < scaleRange; ++s) { if (h_buf_[s] >= scaleThresh_) { const double scale = minScale_ + s * scaleStep_; scales_.push_back(std::make_pair(scale, h_buf_[s])); } } } void GeneralizedHoughGuilImpl::calcPosition(double angle, int angleVotes, double scale, int scaleVotes) { using namespace cv::cuda::device::ght; hist_.setTo(Scalar::all(0)); Guil_Full_calcPHist_gpu(templFeatures_.sizes.ptr(), imageFeatures_.sizes.ptr(0), hist_, (float)angle, (float)angleEpsilon_, (float)scale, (float)dp_, levels_, templFeatures_.maxSize); posCount_ = Guil_Full_findPosInHist_gpu(hist_, outBuf_.ptr(0), outBuf_.ptr(1), posCount_, maxBufferSize_, (float)angle, angleVotes, (float)scale, scaleVotes, (float)dp_, posThresh_); } } Ptr cv::cuda::createGeneralizedHoughGuil() { return makePtr(); } #endif /* !defined (HAVE_CUDA) */