diff --git a/modules/gpu/perf4au/main.cpp b/modules/gpu/perf4au/main.cpp index df8a793ac5d7dbc43d60db1ca72f8d9675b45f3e..5e39c3d1e6f8423d33663d20770ea69c2cc4ec22 100644 --- a/modules/gpu/perf4au/main.cpp +++ b/modules/gpu/perf4au/main.cpp @@ -148,17 +148,17 @@ PERF_TEST_P(Image_Depth, GoodFeaturesToTrack, if (PERF_RUN_GPU()) { - cv::gpu::GoodFeaturesToTrackDetector_GPU d_detector(maxCorners, qualityLevel, minDistance, blockSize, useHarrisDetector, k); + cv::Ptr detector = cv::gpu::createGoodFeaturesToTrackDetector(src.type(), maxCorners, qualityLevel, minDistance, blockSize, useHarrisDetector, k); cv::gpu::GpuMat d_src(src); cv::gpu::GpuMat d_mask(mask); cv::gpu::GpuMat d_pts; - d_detector(d_src, d_pts, d_mask); + detector->detect(d_src, d_pts, d_mask); TEST_CYCLE() { - d_detector(d_src, d_pts, d_mask); + detector->detect(d_src, d_pts, d_mask); } } else diff --git a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp index adb9a8e06b0995900ee476ec5e115ee171c81f6e..2fd17d9b355f4964c345b8c5cbc62acc7db5ba49 100644 --- a/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp +++ b/modules/gpuimgproc/include/opencv2/gpuimgproc.hpp @@ -394,54 +394,17 @@ inline void cornerMinEigenVal(InputArray src, OutputArray dst, int blockSize, in gpu::createMinEigenValCorner(src.type(), blockSize, ksize, borderType)->compute(src, dst, stream); } -////////////////////////// Feature Detection /////////////////////////// +////////////////////////// Corners Detection /////////////////////////// -class CV_EXPORTS GoodFeaturesToTrackDetector_GPU +class CV_EXPORTS CornersDetector : public Algorithm { public: - explicit GoodFeaturesToTrackDetector_GPU(int maxCorners = 1000, double qualityLevel = 0.01, double minDistance = 0.0, - int blockSize = 3, bool useHarrisDetector = false, double harrisK = 0.04); - //! return 1 rows matrix with CV_32FC2 type - void operator ()(const GpuMat& image, GpuMat& corners, const GpuMat& mask = GpuMat()); - - int maxCorners; - double qualityLevel; - double minDistance; - - int blockSize; - bool useHarrisDetector; - double harrisK; - - void releaseMemory() - { - Dx_.release(); - Dy_.release(); - buf_.release(); - eig_.release(); - minMaxbuf_.release(); - tmpCorners_.release(); - } - -private: - GpuMat Dx_; - GpuMat Dy_; - GpuMat buf_; - GpuMat eig_; - GpuMat minMaxbuf_; - GpuMat tmpCorners_; + virtual void detect(InputArray image, OutputArray corners, InputArray mask = noArray()) = 0; }; -inline GoodFeaturesToTrackDetector_GPU::GoodFeaturesToTrackDetector_GPU(int maxCorners_, double qualityLevel_, double minDistance_, - int blockSize_, bool useHarrisDetector_, double harrisK_) -{ - maxCorners = maxCorners_; - qualityLevel = qualityLevel_; - minDistance = minDistance_; - blockSize = blockSize_; - useHarrisDetector = useHarrisDetector_; - harrisK = harrisK_; -} +CV_EXPORTS Ptr createGoodFeaturesToTrackDetector(int srcType, int maxCorners = 1000, double qualityLevel = 0.01, double minDistance = 0.0, + int blockSize = 3, bool useHarrisDetector = false, double harrisK = 0.04); ///////////////////////////// Mean Shift ////////////////////////////// diff --git a/modules/gpuimgproc/perf/perf_gftt.cpp b/modules/gpuimgproc/perf/perf_gftt.cpp index 982182d17e74a2b1860cad39ac7f16f880f59da5..ed8d6ac16d515354e90f66ea1232cf8dc9c4836b 100644 --- a/modules/gpuimgproc/perf/perf_gftt.cpp +++ b/modules/gpuimgproc/perf/perf_gftt.cpp @@ -66,12 +66,12 @@ PERF_TEST_P(Image_MinDistance, GoodFeaturesToTrack, if (PERF_RUN_GPU()) { - cv::gpu::GoodFeaturesToTrackDetector_GPU d_detector(maxCorners, qualityLevel, minDistance); + cv::Ptr d_detector = cv::gpu::createGoodFeaturesToTrackDetector(image.type(), maxCorners, qualityLevel, minDistance); const cv::gpu::GpuMat d_image(image); cv::gpu::GpuMat pts; - TEST_CYCLE() d_detector(d_image, pts); + TEST_CYCLE() d_detector->detect(d_image, pts); GPU_SANITY_CHECK(pts); } diff --git a/modules/gpuimgproc/src/gftt.cpp b/modules/gpuimgproc/src/gftt.cpp index c441069d318d149be3aa535311dbf714e9701672..ff197d84c2fdd34e01117ef0338dd0eed607f009 100644 --- a/modules/gpuimgproc/src/gftt.cpp +++ b/modules/gpuimgproc/src/gftt.cpp @@ -45,9 +45,9 @@ using namespace cv; using namespace cv::gpu; -#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) +#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) || !defined(HAVE_OPENCV_GPUARITHM) -void cv::gpu::GoodFeaturesToTrackDetector_GPU::operator ()(const GpuMat&, GpuMat&, const GpuMat&) { throw_no_cuda(); } +Ptr cv::gpu::createGoodFeaturesToTrackDetector(int, int, double, double, int, bool, double) { throw_no_cuda(); return Ptr(); } #else /* !defined (HAVE_CUDA) */ @@ -60,119 +60,156 @@ namespace cv { namespace gpu { namespace cudev } }}} -void cv::gpu::GoodFeaturesToTrackDetector_GPU::operator ()(const GpuMat& image, GpuMat& corners, const GpuMat& mask) +namespace { -#ifndef HAVE_OPENCV_GPUARITHM - (void) image; - (void) corners; - (void) mask; - throw_no_cuda(); -#else - using namespace cv::gpu::cudev::gfft; + class GoodFeaturesToTrackDetector : public CornersDetector + { + public: + GoodFeaturesToTrackDetector(int srcType, int maxCorners, double qualityLevel, double minDistance, + int blockSize, bool useHarrisDetector, double harrisK); + + void detect(InputArray image, OutputArray corners, InputArray mask = noArray()); + + private: + int maxCorners_; + double qualityLevel_; + double minDistance_; + + Ptr cornerCriteria_; + + GpuMat Dx_; + GpuMat Dy_; + GpuMat buf_; + GpuMat eig_; + GpuMat minMaxbuf_; + GpuMat tmpCorners_; + }; + + GoodFeaturesToTrackDetector::GoodFeaturesToTrackDetector(int srcType, int maxCorners, double qualityLevel, double minDistance, + int blockSize, bool useHarrisDetector, double harrisK) : + maxCorners_(maxCorners), qualityLevel_(qualityLevel), minDistance_(minDistance) + { + CV_Assert( qualityLevel_ > 0 && minDistance_ >= 0 && maxCorners_ >= 0 ); - CV_Assert(qualityLevel > 0 && minDistance >= 0 && maxCorners >= 0); - CV_Assert(mask.empty() || (mask.type() == CV_8UC1 && mask.size() == image.size())); + cornerCriteria_ = useHarrisDetector ? + gpu::createHarrisCorner(srcType, blockSize, 3, harrisK) : + gpu::createMinEigenValCorner(srcType, blockSize, 3); + } - ensureSizeIsEnough(image.size(), CV_32F, eig_); + void GoodFeaturesToTrackDetector::detect(InputArray _image, OutputArray _corners, InputArray _mask) + { + using namespace cv::gpu::cudev::gfft; - Ptr cornerCriteria = - useHarrisDetector ? - gpu::createHarrisCorner(image.type(), blockSize, 3, harrisK) : - gpu::createMinEigenValCorner(image.type(), blockSize, 3); + GpuMat image = _image.getGpuMat(); + GpuMat mask = _mask.getGpuMat(); - cornerCriteria->compute(image, eig_); + CV_Assert( mask.empty() || (mask.type() == CV_8UC1 && mask.size() == image.size()) ); - double maxVal = 0; - gpu::minMax(eig_, 0, &maxVal, GpuMat(), minMaxbuf_); + ensureSizeIsEnough(image.size(), CV_32FC1, eig_); + cornerCriteria_->compute(image, eig_); - ensureSizeIsEnough(1, std::max(1000, static_cast(image.size().area() * 0.05)), CV_32FC2, tmpCorners_); + double maxVal = 0; + gpu::minMax(eig_, 0, &maxVal, noArray(), minMaxbuf_); - int total = findCorners_gpu(eig_, static_cast(maxVal * qualityLevel), mask, tmpCorners_.ptr(), tmpCorners_.cols); + ensureSizeIsEnough(1, std::max(1000, static_cast(image.size().area() * 0.05)), CV_32FC2, tmpCorners_); - if (total == 0) - { - corners.release(); - return; - } + int total = findCorners_gpu(eig_, static_cast(maxVal * qualityLevel_), mask, tmpCorners_.ptr(), tmpCorners_.cols); - sortCorners_gpu(eig_, tmpCorners_.ptr(), total); + if (total == 0) + { + _corners.release(); + return; + } - if (minDistance < 1) - tmpCorners_.colRange(0, maxCorners > 0 ? std::min(maxCorners, total) : total).copyTo(corners); - else - { - std::vector tmp(total); - Mat tmpMat(1, total, CV_32FC2, (void*)&tmp[0]); - tmpCorners_.colRange(0, total).download(tmpMat); + sortCorners_gpu(eig_, tmpCorners_.ptr(), total); - std::vector tmp2; - tmp2.reserve(total); + if (minDistance_ < 1) + { + tmpCorners_.colRange(0, maxCorners_ > 0 ? std::min(maxCorners_, total) : total).copyTo(_corners); + } + else + { + std::vector tmp(total); + Mat tmpMat(1, total, CV_32FC2, (void*)&tmp[0]); + tmpCorners_.colRange(0, total).download(tmpMat); - const int cell_size = cvRound(minDistance); - const int grid_width = (image.cols + cell_size - 1) / cell_size; - const int grid_height = (image.rows + cell_size - 1) / cell_size; + std::vector tmp2; + tmp2.reserve(total); - std::vector< std::vector > grid(grid_width * grid_height); + const int cell_size = cvRound(minDistance_); + const int grid_width = (image.cols + cell_size - 1) / cell_size; + const int grid_height = (image.rows + cell_size - 1) / cell_size; - for (int i = 0; i < total; ++i) - { - Point2f p = tmp[i]; + std::vector< std::vector > grid(grid_width * grid_height); - bool good = true; + for (int i = 0; i < total; ++i) + { + Point2f p = tmp[i]; - int x_cell = static_cast(p.x / cell_size); - int y_cell = static_cast(p.y / cell_size); + bool good = true; - int x1 = x_cell - 1; - int y1 = y_cell - 1; - int x2 = x_cell + 1; - int y2 = y_cell + 1; + int x_cell = static_cast(p.x / cell_size); + int y_cell = static_cast(p.y / cell_size); - // boundary check - x1 = std::max(0, x1); - y1 = std::max(0, y1); - x2 = std::min(grid_width - 1, x2); - y2 = std::min(grid_height - 1, y2); + int x1 = x_cell - 1; + int y1 = y_cell - 1; + int x2 = x_cell + 1; + int y2 = y_cell + 1; - for (int yy = y1; yy <= y2; yy++) - { - for (int xx = x1; xx <= x2; xx++) - { - std::vector& m = grid[yy * grid_width + xx]; + // boundary check + x1 = std::max(0, x1); + y1 = std::max(0, y1); + x2 = std::min(grid_width - 1, x2); + y2 = std::min(grid_height - 1, y2); - if (!m.empty()) + for (int yy = y1; yy <= y2; yy++) + { + for (int xx = x1; xx <= x2; xx++) { - for(size_t j = 0; j < m.size(); j++) - { - float dx = p.x - m[j].x; - float dy = p.y - m[j].y; + std::vector& m = grid[yy * grid_width + xx]; - if (dx * dx + dy * dy < minDistance * minDistance) + if (!m.empty()) + { + for(size_t j = 0; j < m.size(); j++) { - good = false; - goto break_out; + float dx = p.x - m[j].x; + float dy = p.y - m[j].y; + + if (dx * dx + dy * dy < minDistance_ * minDistance_) + { + good = false; + goto break_out; + } } } } } - } - break_out: + break_out: - if(good) - { - grid[y_cell * grid_width + x_cell].push_back(p); + if(good) + { + grid[y_cell * grid_width + x_cell].push_back(p); - tmp2.push_back(p); + tmp2.push_back(p); - if (maxCorners > 0 && tmp2.size() == static_cast(maxCorners)) - break; + if (maxCorners_ > 0 && tmp2.size() == static_cast(maxCorners_)) + break; + } } - } - corners.upload(Mat(1, static_cast(tmp2.size()), CV_32FC2, &tmp2[0])); + _corners.create(1, static_cast(tmp2.size()), CV_32FC2); + GpuMat corners = _corners.getGpuMat(); + + corners.upload(Mat(1, static_cast(tmp2.size()), CV_32FC2, &tmp2[0])); + } } -#endif +} + +Ptr cv::gpu::createGoodFeaturesToTrackDetector(int srcType, int maxCorners, double qualityLevel, double minDistance, + int blockSize, bool useHarrisDetector, double harrisK) +{ + return new GoodFeaturesToTrackDetector(srcType, maxCorners, qualityLevel, minDistance, blockSize, useHarrisDetector, harrisK); } #endif /* !defined (HAVE_CUDA) */ diff --git a/modules/gpuimgproc/test/test_gftt.cpp b/modules/gpuimgproc/test/test_gftt.cpp index b20df33ae5a64b9a37262a7c1e1cc715b6a0cffc..6ba6e0cfffc2a4dfa4f6cd5dcb246c366199d1b3 100644 --- a/modules/gpuimgproc/test/test_gftt.cpp +++ b/modules/gpuimgproc/test/test_gftt.cpp @@ -76,10 +76,10 @@ GPU_TEST_P(GoodFeaturesToTrack, Accuracy) int maxCorners = 1000; double qualityLevel = 0.01; - cv::gpu::GoodFeaturesToTrackDetector_GPU detector(maxCorners, qualityLevel, minDistance); + cv::Ptr detector = cv::gpu::createGoodFeaturesToTrackDetector(image.type(), maxCorners, qualityLevel, minDistance); cv::gpu::GpuMat d_pts; - detector(loadMat(image), d_pts); + detector->detect(loadMat(image), d_pts); ASSERT_FALSE(d_pts.empty()); @@ -114,12 +114,12 @@ GPU_TEST_P(GoodFeaturesToTrack, EmptyCorners) int maxCorners = 1000; double qualityLevel = 0.01; - cv::gpu::GoodFeaturesToTrackDetector_GPU detector(maxCorners, qualityLevel, minDistance); - cv::gpu::GpuMat src(100, 100, CV_8UC1, cv::Scalar::all(0)); cv::gpu::GpuMat corners(1, maxCorners, CV_32FC2); - detector(src, corners); + cv::Ptr detector = cv::gpu::createGoodFeaturesToTrackDetector(src.type(), maxCorners, qualityLevel, minDistance); + + detector->detect(src, corners); ASSERT_TRUE(corners.empty()); } diff --git a/modules/videostab/include/opencv2/videostab/global_motion.hpp b/modules/videostab/include/opencv2/videostab/global_motion.hpp index 58b831b372743c2a66c17b23fe850c2e2bfec3cd..8ccc067a38936199c70725d8334c1959c277d8b1 100644 --- a/modules/videostab/include/opencv2/videostab/global_motion.hpp +++ b/modules/videostab/include/opencv2/videostab/global_motion.hpp @@ -217,7 +217,7 @@ public: private: Ptr motionEstimator_; - gpu::GoodFeaturesToTrackDetector_GPU detector_; + Ptr detector_; SparsePyrLkOptFlowEstimatorGpu optFlowEstimator_; Ptr outlierRejector_; diff --git a/modules/videostab/src/global_motion.cpp b/modules/videostab/src/global_motion.cpp index d6c291ca70e9bc22c4c5168bed136e3a89ecfe9d..9a54b5ae648c89c2dc71d1d9181da2331b182c54 100644 --- a/modules/videostab/src/global_motion.cpp +++ b/modules/videostab/src/global_motion.cpp @@ -742,6 +742,8 @@ Mat KeypointBasedMotionEstimator::estimate(const Mat &frame0, const Mat &frame1, KeypointBasedMotionEstimatorGpu::KeypointBasedMotionEstimatorGpu(Ptr estimator) : ImageMotionEstimatorBase(estimator->motionModel()), motionEstimator_(estimator) { + detector_ = gpu::createGoodFeaturesToTrackDetector(CV_8UC1); + CV_Assert(gpu::getCudaEnabledDeviceCount() > 0); setOutlierRejector(new NullOutlierRejector()); } @@ -769,7 +771,7 @@ Mat KeypointBasedMotionEstimatorGpu::estimate(const gpu::GpuMat &frame0, const g } // find keypoints - detector_(grayFrame0, pointsPrev_); + detector_->detect(grayFrame0, pointsPrev_); // find correspondences optFlowEstimator_.run(frame0, frame1, pointsPrev_, points_, status_); diff --git a/samples/gpu/performance/tests.cpp b/samples/gpu/performance/tests.cpp index f95730e35119dd3f24492c42ebcf3b0bd67deb2a..da2d4e2263aa793bc9249dcda04e7eb6121647ac 100644 --- a/samples/gpu/performance/tests.cpp +++ b/samples/gpu/performance/tests.cpp @@ -1174,15 +1174,15 @@ TEST(GoodFeaturesToTrack) goodFeaturesToTrack(src, pts, 8000, 0.01, 0.0); CPU_OFF; - gpu::GoodFeaturesToTrackDetector_GPU detector(8000, 0.01, 0.0); + Ptr detector = gpu::createGoodFeaturesToTrackDetector(src.type(), 8000, 0.01, 0.0); gpu::GpuMat d_src(src); gpu::GpuMat d_pts; - detector(d_src, d_pts); + detector->detect(d_src, d_pts); GPU_ON; - detector(d_src, d_pts); + detector->detect(d_src, d_pts); GPU_OFF; } diff --git a/samples/gpu/pyrlk_optical_flow.cpp b/samples/gpu/pyrlk_optical_flow.cpp index 2edb9746c690679be09a5237250fdf482ab43c7b..08717292cd7266da1139b1f43575deefdb00646f 100644 --- a/samples/gpu/pyrlk_optical_flow.cpp +++ b/samples/gpu/pyrlk_optical_flow.cpp @@ -176,12 +176,12 @@ int main(int argc, const char* argv[]) // goodFeaturesToTrack - GoodFeaturesToTrackDetector_GPU detector(points, 0.01, minDist); - GpuMat d_frame0Gray(frame0Gray); GpuMat d_prevPts; - detector(d_frame0Gray, d_prevPts); + Ptr detector = gpu::createGoodFeaturesToTrackDetector(d_frame0Gray.type(), points, 0.01, minDist); + + detector->detect(d_frame0Gray, d_prevPts); // Sparse