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 "opencl_kernels_imgproc.hpp" 44 45#include <cstdio> 46#include <vector> 47#include <iostream> 48#include <functional> 49 50namespace cv 51{ 52 53struct greaterThanPtr : 54 public std::binary_function<const float *, const float *, bool> 55{ 56 bool operator () (const float * a, const float * b) const 57 { return *a > *b; } 58}; 59 60#ifdef HAVE_OPENCL 61 62struct Corner 63{ 64 float val; 65 short y; 66 short x; 67 68 bool operator < (const Corner & c) const 69 { return val > c.val; } 70}; 71 72static bool ocl_goodFeaturesToTrack( InputArray _image, OutputArray _corners, 73 int maxCorners, double qualityLevel, double minDistance, 74 InputArray _mask, int blockSize, 75 bool useHarrisDetector, double harrisK ) 76{ 77 UMat eig, maxEigenValue; 78 if( useHarrisDetector ) 79 cornerHarris( _image, eig, blockSize, 3, harrisK ); 80 else 81 cornerMinEigenVal( _image, eig, blockSize, 3 ); 82 83 Size imgsize = _image.size(); 84 size_t total, i, j, ncorners = 0, possibleCornersCount = 85 std::max(1024, static_cast<int>(imgsize.area() * 0.1)); 86 bool haveMask = !_mask.empty(); 87 UMat corners_buffer(1, (int)possibleCornersCount + 1, CV_32FC2); 88 CV_Assert(sizeof(Corner) == corners_buffer.elemSize()); 89 Mat tmpCorners; 90 91 // find threshold 92 { 93 CV_Assert(eig.type() == CV_32FC1); 94 int dbsize = ocl::Device::getDefault().maxComputeUnits(); 95 size_t wgs = ocl::Device::getDefault().maxWorkGroupSize(); 96 97 int wgs2_aligned = 1; 98 while (wgs2_aligned < (int)wgs) 99 wgs2_aligned <<= 1; 100 wgs2_aligned >>= 1; 101 102 ocl::Kernel k("maxEigenVal", ocl::imgproc::gftt_oclsrc, 103 format("-D OP_MAX_EIGEN_VAL -D WGS=%d -D groupnum=%d -D WGS2_ALIGNED=%d%s", 104 (int)wgs, dbsize, wgs2_aligned, haveMask ? " -D HAVE_MASK" : "")); 105 if (k.empty()) 106 return false; 107 108 UMat mask = _mask.getUMat(); 109 maxEigenValue.create(1, dbsize, CV_32FC1); 110 111 ocl::KernelArg eigarg = ocl::KernelArg::ReadOnlyNoSize(eig), 112 dbarg = ocl::KernelArg::PtrWriteOnly(maxEigenValue), 113 maskarg = ocl::KernelArg::ReadOnlyNoSize(mask), 114 cornersarg = ocl::KernelArg::PtrWriteOnly(corners_buffer); 115 116 if (haveMask) 117 k.args(eigarg, eig.cols, (int)eig.total(), dbarg, maskarg); 118 else 119 k.args(eigarg, eig.cols, (int)eig.total(), dbarg); 120 121 size_t globalsize = dbsize * wgs; 122 if (!k.run(1, &globalsize, &wgs, false)) 123 return false; 124 125 ocl::Kernel k2("maxEigenValTask", ocl::imgproc::gftt_oclsrc, 126 format("-D OP_MAX_EIGEN_VAL -D WGS=%d -D WGS2_ALIGNED=%d -D groupnum=%d", 127 wgs, wgs2_aligned, dbsize)); 128 if (k2.empty()) 129 return false; 130 131 k2.args(dbarg, (float)qualityLevel, cornersarg); 132 133 if (!k2.runTask(false)) 134 return false; 135 } 136 137 // collect list of pointers to features - put them into temporary image 138 { 139 ocl::Kernel k("findCorners", ocl::imgproc::gftt_oclsrc, 140 format("-D OP_FIND_CORNERS%s", haveMask ? " -D HAVE_MASK" : "")); 141 if (k.empty()) 142 return false; 143 144 ocl::KernelArg eigarg = ocl::KernelArg::ReadOnlyNoSize(eig), 145 cornersarg = ocl::KernelArg::PtrWriteOnly(corners_buffer), 146 thresholdarg = ocl::KernelArg::PtrReadOnly(maxEigenValue); 147 148 if (!haveMask) 149 k.args(eigarg, cornersarg, eig.rows - 2, eig.cols - 2, thresholdarg, 150 (int)possibleCornersCount); 151 else 152 { 153 UMat mask = _mask.getUMat(); 154 k.args(eigarg, ocl::KernelArg::ReadOnlyNoSize(mask), 155 cornersarg, eig.rows - 2, eig.cols - 2, 156 thresholdarg, (int)possibleCornersCount); 157 } 158 159 size_t globalsize[2] = { eig.cols - 2, eig.rows - 2 }; 160 if (!k.run(2, globalsize, NULL, false)) 161 return false; 162 163 tmpCorners = corners_buffer.getMat(ACCESS_RW); 164 total = std::min<size_t>(tmpCorners.at<Vec2i>(0, 0)[0], possibleCornersCount); 165 if (total == 0) 166 { 167 _corners.release(); 168 return true; 169 } 170 } 171 172 Corner* corner_ptr = tmpCorners.ptr<Corner>() + 1; 173 std::sort(corner_ptr, corner_ptr + total); 174 175 std::vector<Point2f> corners; 176 corners.reserve(total); 177 178 if (minDistance >= 1) 179 { 180 // Partition the image into larger grids 181 int w = imgsize.width, h = imgsize.height; 182 183 const int cell_size = cvRound(minDistance); 184 const int grid_width = (w + cell_size - 1) / cell_size; 185 const int grid_height = (h + cell_size - 1) / cell_size; 186 187 std::vector<std::vector<Point2f> > grid(grid_width*grid_height); 188 minDistance *= minDistance; 189 190 for( i = 0; i < total; i++ ) 191 { 192 const Corner & c = corner_ptr[i]; 193 bool good = true; 194 195 int x_cell = c.x / cell_size; 196 int y_cell = c.y / cell_size; 197 198 int x1 = x_cell - 1; 199 int y1 = y_cell - 1; 200 int x2 = x_cell + 1; 201 int y2 = y_cell + 1; 202 203 // boundary check 204 x1 = std::max(0, x1); 205 y1 = std::max(0, y1); 206 x2 = std::min(grid_width - 1, x2); 207 y2 = std::min(grid_height - 1, y2); 208 209 for( int yy = y1; yy <= y2; yy++ ) 210 for( int xx = x1; xx <= x2; xx++ ) 211 { 212 std::vector<Point2f> &m = grid[yy * grid_width + xx]; 213 214 if( m.size() ) 215 { 216 for(j = 0; j < m.size(); j++) 217 { 218 float dx = c.x - m[j].x; 219 float dy = c.y - m[j].y; 220 221 if( dx*dx + dy*dy < minDistance ) 222 { 223 good = false; 224 goto break_out; 225 } 226 } 227 } 228 } 229 230 break_out: 231 232 if (good) 233 { 234 grid[y_cell*grid_width + x_cell].push_back(Point2f((float)c.x, (float)c.y)); 235 236 corners.push_back(Point2f((float)c.x, (float)c.y)); 237 ++ncorners; 238 239 if( maxCorners > 0 && (int)ncorners == maxCorners ) 240 break; 241 } 242 } 243 } 244 else 245 { 246 for( i = 0; i < total; i++ ) 247 { 248 const Corner & c = corner_ptr[i]; 249 250 corners.push_back(Point2f((float)c.x, (float)c.y)); 251 ++ncorners; 252 if( maxCorners > 0 && (int)ncorners == maxCorners ) 253 break; 254 } 255 } 256 257 Mat(corners).convertTo(_corners, _corners.fixedType() ? _corners.type() : CV_32F); 258 return true; 259} 260 261#endif 262 263} 264 265void cv::goodFeaturesToTrack( InputArray _image, OutputArray _corners, 266 int maxCorners, double qualityLevel, double minDistance, 267 InputArray _mask, int blockSize, 268 bool useHarrisDetector, double harrisK ) 269{ 270 CV_Assert( qualityLevel > 0 && minDistance >= 0 && maxCorners >= 0 ); 271 CV_Assert( _mask.empty() || (_mask.type() == CV_8UC1 && _mask.sameSize(_image)) ); 272 273 CV_OCL_RUN(_image.dims() <= 2 && _image.isUMat(), 274 ocl_goodFeaturesToTrack(_image, _corners, maxCorners, qualityLevel, minDistance, 275 _mask, blockSize, useHarrisDetector, harrisK)) 276 277 Mat image = _image.getMat(), eig, tmp; 278 if (image.empty()) 279 { 280 _corners.release(); 281 return; 282 } 283 284 if( useHarrisDetector ) 285 cornerHarris( image, eig, blockSize, 3, harrisK ); 286 else 287 cornerMinEigenVal( image, eig, blockSize, 3 ); 288 289 double maxVal = 0; 290 minMaxLoc( eig, 0, &maxVal, 0, 0, _mask ); 291 threshold( eig, eig, maxVal*qualityLevel, 0, THRESH_TOZERO ); 292 dilate( eig, tmp, Mat()); 293 294 Size imgsize = image.size(); 295 std::vector<const float*> tmpCorners; 296 297 // collect list of pointers to features - put them into temporary image 298 Mat mask = _mask.getMat(); 299 for( int y = 1; y < imgsize.height - 1; y++ ) 300 { 301 const float* eig_data = (const float*)eig.ptr(y); 302 const float* tmp_data = (const float*)tmp.ptr(y); 303 const uchar* mask_data = mask.data ? mask.ptr(y) : 0; 304 305 for( int x = 1; x < imgsize.width - 1; x++ ) 306 { 307 float val = eig_data[x]; 308 if( val != 0 && val == tmp_data[x] && (!mask_data || mask_data[x]) ) 309 tmpCorners.push_back(eig_data + x); 310 } 311 } 312 std::sort( tmpCorners.begin(), tmpCorners.end(), greaterThanPtr() ); 313 314 std::vector<Point2f> corners; 315 size_t i, j, total = tmpCorners.size(), ncorners = 0; 316 317 if (minDistance >= 1) 318 { 319 // Partition the image into larger grids 320 int w = image.cols; 321 int h = image.rows; 322 323 const int cell_size = cvRound(minDistance); 324 const int grid_width = (w + cell_size - 1) / cell_size; 325 const int grid_height = (h + cell_size - 1) / cell_size; 326 327 std::vector<std::vector<Point2f> > grid(grid_width*grid_height); 328 329 minDistance *= minDistance; 330 331 for( i = 0; i < total; i++ ) 332 { 333 int ofs = (int)((const uchar*)tmpCorners[i] - eig.ptr()); 334 int y = (int)(ofs / eig.step); 335 int x = (int)((ofs - y*eig.step)/sizeof(float)); 336 337 bool good = true; 338 339 int x_cell = x / cell_size; 340 int y_cell = y / cell_size; 341 342 int x1 = x_cell - 1; 343 int y1 = y_cell - 1; 344 int x2 = x_cell + 1; 345 int y2 = y_cell + 1; 346 347 // boundary check 348 x1 = std::max(0, x1); 349 y1 = std::max(0, y1); 350 x2 = std::min(grid_width-1, x2); 351 y2 = std::min(grid_height-1, y2); 352 353 for( int yy = y1; yy <= y2; yy++ ) 354 for( int xx = x1; xx <= x2; xx++ ) 355 { 356 std::vector <Point2f> &m = grid[yy*grid_width + xx]; 357 358 if( m.size() ) 359 { 360 for(j = 0; j < m.size(); j++) 361 { 362 float dx = x - m[j].x; 363 float dy = y - m[j].y; 364 365 if( dx*dx + dy*dy < minDistance ) 366 { 367 good = false; 368 goto break_out; 369 } 370 } 371 } 372 } 373 374 break_out: 375 376 if (good) 377 { 378 grid[y_cell*grid_width + x_cell].push_back(Point2f((float)x, (float)y)); 379 380 corners.push_back(Point2f((float)x, (float)y)); 381 ++ncorners; 382 383 if( maxCorners > 0 && (int)ncorners == maxCorners ) 384 break; 385 } 386 } 387 } 388 else 389 { 390 for( i = 0; i < total; i++ ) 391 { 392 int ofs = (int)((const uchar*)tmpCorners[i] - eig.ptr()); 393 int y = (int)(ofs / eig.step); 394 int x = (int)((ofs - y*eig.step)/sizeof(float)); 395 396 corners.push_back(Point2f((float)x, (float)y)); 397 ++ncorners; 398 if( maxCorners > 0 && (int)ncorners == maxCorners ) 399 break; 400 } 401 } 402 403 Mat(corners).convertTo(_corners, _corners.fixedType() ? _corners.type() : CV_32F); 404} 405 406CV_IMPL void 407cvGoodFeaturesToTrack( const void* _image, void*, void*, 408 CvPoint2D32f* _corners, int *_corner_count, 409 double quality_level, double min_distance, 410 const void* _maskImage, int block_size, 411 int use_harris, double harris_k ) 412{ 413 cv::Mat image = cv::cvarrToMat(_image), mask; 414 std::vector<cv::Point2f> corners; 415 416 if( _maskImage ) 417 mask = cv::cvarrToMat(_maskImage); 418 419 CV_Assert( _corners && _corner_count ); 420 cv::goodFeaturesToTrack( image, corners, *_corner_count, quality_level, 421 min_distance, mask, block_size, use_harris != 0, harris_k ); 422 423 size_t i, ncorners = corners.size(); 424 for( i = 0; i < ncorners; i++ ) 425 _corners[i] = corners[i]; 426 *_corner_count = (int)ncorners; 427} 428 429/* End of file. */ 430