mirror of
https://github.com/opencv/opencv.git
synced 2025-01-18 06:03:15 +08:00
refactored GoodFeaturesToTrackDetector
This commit is contained in:
parent
d7ff3ad0cf
commit
70e6dc615a
@ -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<cv::gpu::CornersDetector> 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
|
||||
|
@ -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<CornersDetector> 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 //////////////////////////////
|
||||
|
||||
|
@ -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<cv::gpu::CornersDetector> 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);
|
||||
}
|
||||
|
@ -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<gpu::CornersDetector> cv::gpu::createGoodFeaturesToTrackDetector(int, int, double, double, int, bool, double) { throw_no_cuda(); return Ptr<gpu::CornersDetector>(); }
|
||||
|
||||
#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;
|
||||
|
||||
CV_Assert(qualityLevel > 0 && minDistance >= 0 && maxCorners >= 0);
|
||||
CV_Assert(mask.empty() || (mask.type() == CV_8UC1 && mask.size() == image.size()));
|
||||
|
||||
ensureSizeIsEnough(image.size(), CV_32F, eig_);
|
||||
|
||||
Ptr<gpu::CornernessCriteria> cornerCriteria =
|
||||
useHarrisDetector ?
|
||||
gpu::createHarrisCorner(image.type(), blockSize, 3, harrisK) :
|
||||
gpu::createMinEigenValCorner(image.type(), blockSize, 3);
|
||||
|
||||
cornerCriteria->compute(image, eig_);
|
||||
|
||||
double maxVal = 0;
|
||||
gpu::minMax(eig_, 0, &maxVal, GpuMat(), minMaxbuf_);
|
||||
|
||||
ensureSizeIsEnough(1, std::max(1000, static_cast<int>(image.size().area() * 0.05)), CV_32FC2, tmpCorners_);
|
||||
|
||||
int total = findCorners_gpu(eig_, static_cast<float>(maxVal * qualityLevel), mask, tmpCorners_.ptr<float2>(), tmpCorners_.cols);
|
||||
|
||||
if (total == 0)
|
||||
class GoodFeaturesToTrackDetector : public CornersDetector
|
||||
{
|
||||
corners.release();
|
||||
return;
|
||||
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<gpu::CornernessCriteria> 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 );
|
||||
|
||||
cornerCriteria_ = useHarrisDetector ?
|
||||
gpu::createHarrisCorner(srcType, blockSize, 3, harrisK) :
|
||||
gpu::createMinEigenValCorner(srcType, blockSize, 3);
|
||||
}
|
||||
|
||||
sortCorners_gpu(eig_, tmpCorners_.ptr<float2>(), total);
|
||||
|
||||
if (minDistance < 1)
|
||||
tmpCorners_.colRange(0, maxCorners > 0 ? std::min(maxCorners, total) : total).copyTo(corners);
|
||||
else
|
||||
void GoodFeaturesToTrackDetector::detect(InputArray _image, OutputArray _corners, InputArray _mask)
|
||||
{
|
||||
std::vector<Point2f> tmp(total);
|
||||
Mat tmpMat(1, total, CV_32FC2, (void*)&tmp[0]);
|
||||
tmpCorners_.colRange(0, total).download(tmpMat);
|
||||
using namespace cv::gpu::cudev::gfft;
|
||||
|
||||
std::vector<Point2f> tmp2;
|
||||
tmp2.reserve(total);
|
||||
GpuMat image = _image.getGpuMat();
|
||||
GpuMat mask = _mask.getGpuMat();
|
||||
|
||||
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;
|
||||
CV_Assert( mask.empty() || (mask.type() == CV_8UC1 && mask.size() == image.size()) );
|
||||
|
||||
std::vector< std::vector<Point2f> > grid(grid_width * grid_height);
|
||||
ensureSizeIsEnough(image.size(), CV_32FC1, eig_);
|
||||
cornerCriteria_->compute(image, eig_);
|
||||
|
||||
for (int i = 0; i < total; ++i)
|
||||
double maxVal = 0;
|
||||
gpu::minMax(eig_, 0, &maxVal, noArray(), minMaxbuf_);
|
||||
|
||||
ensureSizeIsEnough(1, std::max(1000, static_cast<int>(image.size().area() * 0.05)), CV_32FC2, tmpCorners_);
|
||||
|
||||
int total = findCorners_gpu(eig_, static_cast<float>(maxVal * qualityLevel_), mask, tmpCorners_.ptr<float2>(), tmpCorners_.cols);
|
||||
|
||||
if (total == 0)
|
||||
{
|
||||
Point2f p = tmp[i];
|
||||
_corners.release();
|
||||
return;
|
||||
}
|
||||
|
||||
bool good = true;
|
||||
sortCorners_gpu(eig_, tmpCorners_.ptr<float2>(), total);
|
||||
|
||||
int x_cell = static_cast<int>(p.x / cell_size);
|
||||
int y_cell = static_cast<int>(p.y / cell_size);
|
||||
if (minDistance_ < 1)
|
||||
{
|
||||
tmpCorners_.colRange(0, maxCorners_ > 0 ? std::min(maxCorners_, total) : total).copyTo(_corners);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<Point2f> tmp(total);
|
||||
Mat tmpMat(1, total, CV_32FC2, (void*)&tmp[0]);
|
||||
tmpCorners_.colRange(0, total).download(tmpMat);
|
||||
|
||||
int x1 = x_cell - 1;
|
||||
int y1 = y_cell - 1;
|
||||
int x2 = x_cell + 1;
|
||||
int y2 = y_cell + 1;
|
||||
std::vector<Point2f> tmp2;
|
||||
tmp2.reserve(total);
|
||||
|
||||
// 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);
|
||||
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 yy = y1; yy <= y2; yy++)
|
||||
std::vector< std::vector<Point2f> > grid(grid_width * grid_height);
|
||||
|
||||
for (int i = 0; i < total; ++i)
|
||||
{
|
||||
for (int xx = x1; xx <= x2; xx++)
|
||||
Point2f p = tmp[i];
|
||||
|
||||
bool good = true;
|
||||
|
||||
int x_cell = static_cast<int>(p.x / cell_size);
|
||||
int y_cell = static_cast<int>(p.y / cell_size);
|
||||
|
||||
int x1 = x_cell - 1;
|
||||
int y1 = y_cell - 1;
|
||||
int x2 = x_cell + 1;
|
||||
int y2 = y_cell + 1;
|
||||
|
||||
// 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);
|
||||
|
||||
for (int yy = y1; yy <= y2; yy++)
|
||||
{
|
||||
std::vector<Point2f>& m = grid[yy * grid_width + xx];
|
||||
|
||||
if (!m.empty())
|
||||
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<Point2f>& 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:
|
||||
|
||||
if(good)
|
||||
{
|
||||
grid[y_cell * grid_width + x_cell].push_back(p);
|
||||
|
||||
tmp2.push_back(p);
|
||||
|
||||
if (maxCorners_ > 0 && tmp2.size() == static_cast<size_t>(maxCorners_))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break_out:
|
||||
_corners.create(1, static_cast<int>(tmp2.size()), CV_32FC2);
|
||||
GpuMat corners = _corners.getGpuMat();
|
||||
|
||||
if(good)
|
||||
{
|
||||
grid[y_cell * grid_width + x_cell].push_back(p);
|
||||
|
||||
tmp2.push_back(p);
|
||||
|
||||
if (maxCorners > 0 && tmp2.size() == static_cast<size_t>(maxCorners))
|
||||
break;
|
||||
}
|
||||
corners.upload(Mat(1, static_cast<int>(tmp2.size()), CV_32FC2, &tmp2[0]));
|
||||
}
|
||||
|
||||
corners.upload(Mat(1, static_cast<int>(tmp2.size()), CV_32FC2, &tmp2[0]));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Ptr<gpu::CornersDetector> 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) */
|
||||
|
@ -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<cv::gpu::CornersDetector> 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<cv::gpu::CornersDetector> detector = cv::gpu::createGoodFeaturesToTrackDetector(src.type(), maxCorners, qualityLevel, minDistance);
|
||||
|
||||
detector->detect(src, corners);
|
||||
|
||||
ASSERT_TRUE(corners.empty());
|
||||
}
|
||||
|
@ -217,7 +217,7 @@ public:
|
||||
|
||||
private:
|
||||
Ptr<MotionEstimatorBase> motionEstimator_;
|
||||
gpu::GoodFeaturesToTrackDetector_GPU detector_;
|
||||
Ptr<gpu::CornersDetector> detector_;
|
||||
SparsePyrLkOptFlowEstimatorGpu optFlowEstimator_;
|
||||
Ptr<IOutlierRejector> outlierRejector_;
|
||||
|
||||
|
@ -742,6 +742,8 @@ Mat KeypointBasedMotionEstimator::estimate(const Mat &frame0, const Mat &frame1,
|
||||
KeypointBasedMotionEstimatorGpu::KeypointBasedMotionEstimatorGpu(Ptr<MotionEstimatorBase> 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_);
|
||||
|
@ -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<gpu::CornersDetector> 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;
|
||||
}
|
||||
|
||||
|
@ -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<gpu::CornersDetector> detector = gpu::createGoodFeaturesToTrackDetector(d_frame0Gray.type(), points, 0.01, minDist);
|
||||
|
||||
detector->detect(d_frame0Gray, d_prevPts);
|
||||
|
||||
// Sparse
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user