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 //                        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 
     50 namespace cv
     51 {
     52 
     53 struct 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 
     62 struct 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 
     72 static 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 
    265 void 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 
    406 CV_IMPL void
    407 cvGoodFeaturesToTrack( 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