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 45using namespace cv; 46using namespace cv::cuda; 47 48#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) || !defined(HAVE_OPENCV_CUDAARITHM) 49 50Ptr<cuda::CornersDetector> cv::cuda::createGoodFeaturesToTrackDetector(int, int, double, double, int, bool, double) { throw_no_cuda(); return Ptr<cuda::CornersDetector>(); } 51 52#else /* !defined (HAVE_CUDA) */ 53 54namespace cv { namespace cuda { namespace device 55{ 56 namespace gfft 57 { 58 int findCorners_gpu(PtrStepSzf eig, float threshold, PtrStepSzb mask, float2* corners, int max_count); 59 void sortCorners_gpu(PtrStepSzf eig, float2* corners, int count); 60 } 61}}} 62 63namespace 64{ 65 class GoodFeaturesToTrackDetector : public CornersDetector 66 { 67 public: 68 GoodFeaturesToTrackDetector(int srcType, int maxCorners, double qualityLevel, double minDistance, 69 int blockSize, bool useHarrisDetector, double harrisK); 70 71 void detect(InputArray image, OutputArray corners, InputArray mask, Stream& stream); 72 73 private: 74 int maxCorners_; 75 double qualityLevel_; 76 double minDistance_; 77 78 Ptr<cuda::CornernessCriteria> cornerCriteria_; 79 80 GpuMat Dx_; 81 GpuMat Dy_; 82 GpuMat buf_; 83 GpuMat eig_; 84 GpuMat tmpCorners_; 85 }; 86 87 GoodFeaturesToTrackDetector::GoodFeaturesToTrackDetector(int srcType, int maxCorners, double qualityLevel, double minDistance, 88 int blockSize, bool useHarrisDetector, double harrisK) : 89 maxCorners_(maxCorners), qualityLevel_(qualityLevel), minDistance_(minDistance) 90 { 91 CV_Assert( qualityLevel_ > 0 && minDistance_ >= 0 && maxCorners_ >= 0 ); 92 93 cornerCriteria_ = useHarrisDetector ? 94 cuda::createHarrisCorner(srcType, blockSize, 3, harrisK) : 95 cuda::createMinEigenValCorner(srcType, blockSize, 3); 96 } 97 98 void GoodFeaturesToTrackDetector::detect(InputArray _image, OutputArray _corners, InputArray _mask, Stream& stream) 99 { 100 // TODO : implement async version 101 (void) stream; 102 103 using namespace cv::cuda::device::gfft; 104 105 GpuMat image = _image.getGpuMat(); 106 GpuMat mask = _mask.getGpuMat(); 107 108 CV_Assert( mask.empty() || (mask.type() == CV_8UC1 && mask.size() == image.size()) ); 109 110 ensureSizeIsEnough(image.size(), CV_32FC1, eig_); 111 cornerCriteria_->compute(image, eig_); 112 113 double maxVal = 0; 114 cuda::minMax(eig_, 0, &maxVal); 115 116 ensureSizeIsEnough(1, std::max(1000, static_cast<int>(image.size().area() * 0.05)), CV_32FC2, tmpCorners_); 117 118 int total = findCorners_gpu(eig_, static_cast<float>(maxVal * qualityLevel_), mask, tmpCorners_.ptr<float2>(), tmpCorners_.cols); 119 120 if (total == 0) 121 { 122 _corners.release(); 123 return; 124 } 125 126 sortCorners_gpu(eig_, tmpCorners_.ptr<float2>(), total); 127 128 if (minDistance_ < 1) 129 { 130 tmpCorners_.colRange(0, maxCorners_ > 0 ? std::min(maxCorners_, total) : total).copyTo(_corners); 131 } 132 else 133 { 134 std::vector<Point2f> tmp(total); 135 Mat tmpMat(1, total, CV_32FC2, (void*)&tmp[0]); 136 tmpCorners_.colRange(0, total).download(tmpMat); 137 138 std::vector<Point2f> tmp2; 139 tmp2.reserve(total); 140 141 const int cell_size = cvRound(minDistance_); 142 const int grid_width = (image.cols + cell_size - 1) / cell_size; 143 const int grid_height = (image.rows + cell_size - 1) / cell_size; 144 145 std::vector< std::vector<Point2f> > grid(grid_width * grid_height); 146 147 for (int i = 0; i < total; ++i) 148 { 149 Point2f p = tmp[i]; 150 151 bool good = true; 152 153 int x_cell = static_cast<int>(p.x / cell_size); 154 int y_cell = static_cast<int>(p.y / cell_size); 155 156 int x1 = x_cell - 1; 157 int y1 = y_cell - 1; 158 int x2 = x_cell + 1; 159 int y2 = y_cell + 1; 160 161 // boundary check 162 x1 = std::max(0, x1); 163 y1 = std::max(0, y1); 164 x2 = std::min(grid_width - 1, x2); 165 y2 = std::min(grid_height - 1, y2); 166 167 for (int yy = y1; yy <= y2; yy++) 168 { 169 for (int xx = x1; xx <= x2; xx++) 170 { 171 std::vector<Point2f>& m = grid[yy * grid_width + xx]; 172 173 if (!m.empty()) 174 { 175 for(size_t j = 0; j < m.size(); j++) 176 { 177 float dx = p.x - m[j].x; 178 float dy = p.y - m[j].y; 179 180 if (dx * dx + dy * dy < minDistance_ * minDistance_) 181 { 182 good = false; 183 goto break_out; 184 } 185 } 186 } 187 } 188 } 189 190 break_out: 191 192 if(good) 193 { 194 grid[y_cell * grid_width + x_cell].push_back(p); 195 196 tmp2.push_back(p); 197 198 if (maxCorners_ > 0 && tmp2.size() == static_cast<size_t>(maxCorners_)) 199 break; 200 } 201 } 202 203 _corners.create(1, static_cast<int>(tmp2.size()), CV_32FC2); 204 GpuMat corners = _corners.getGpuMat(); 205 206 corners.upload(Mat(1, static_cast<int>(tmp2.size()), CV_32FC2, &tmp2[0])); 207 } 208 } 209} 210 211Ptr<cuda::CornersDetector> cv::cuda::createGoodFeaturesToTrackDetector(int srcType, int maxCorners, double qualityLevel, double minDistance, 212 int blockSize, bool useHarrisDetector, double harrisK) 213{ 214 return Ptr<cuda::CornersDetector>( 215 new GoodFeaturesToTrackDetector(srcType, maxCorners, qualityLevel, minDistance, blockSize, useHarrisDetector, harrisK)); 216} 217 218#endif /* !defined (HAVE_CUDA) */ 219