}
std::vector<Point2f> corners;
+ std::vector<float> cornersQuality;
if (_image.isUMat())
{
ugrayImage = _image.getUMat();
goodFeaturesToTrack( ugrayImage, corners, nfeatures, qualityLevel, minDistance, _mask,
- blockSize, gradSize, useHarrisDetector, k );
+ cornersQuality, blockSize, gradSize, useHarrisDetector, k );
}
else
{
cvtColor( image, grayImage, COLOR_BGR2GRAY );
goodFeaturesToTrack( grayImage, corners, nfeatures, qualityLevel, minDistance, _mask,
- blockSize, gradSize, useHarrisDetector, k );
+ cornersQuality, blockSize, gradSize, useHarrisDetector, k );
}
+ CV_Assert(corners.size() == cornersQuality.size());
+
keypoints.resize(corners.size());
- std::vector<Point2f>::const_iterator corner_it = corners.begin();
- std::vector<KeyPoint>::iterator keypoint_it = keypoints.begin();
- for( ; corner_it != corners.end() && keypoint_it != keypoints.end(); ++corner_it, ++keypoint_it )
- *keypoint_it = KeyPoint( *corner_it, (float)blockSize );
+ for (size_t i = 0; i < corners.size(); i++)
+ keypoints[i] = KeyPoint(corners[i], (float)blockSize, -1, cornersQuality[i]);
}
InputArray mask, int blockSize,
int gradientSize, bool useHarrisDetector = false,
double k = 0.04 );
+
+/** @brief Same as above, but returns also quality measure of the detected corners.
+
+@param image Input 8-bit or floating-point 32-bit, single-channel image.
+@param corners Output vector of detected corners.
+@param maxCorners Maximum number of corners to return. If there are more corners than are found,
+the strongest of them is returned. `maxCorners <= 0` implies that no limit on the maximum is set
+and all detected corners are returned.
+@param qualityLevel Parameter characterizing the minimal accepted quality of image corners. The
+parameter value is multiplied by the best corner quality measure, which is the minimal eigenvalue
+(see #cornerMinEigenVal ) or the Harris function response (see #cornerHarris ). The corners with the
+quality measure less than the product are rejected. For example, if the best corner has the
+quality measure = 1500, and the qualityLevel=0.01 , then all the corners with the quality measure
+less than 15 are rejected.
+@param minDistance Minimum possible Euclidean distance between the returned corners.
+@param mask Region of interest. If the image is not empty (it needs to have the type
+CV_8UC1 and the same size as image ), it specifies the region in which the corners are detected.
+@param cornersQuality Output vector of quality measure of the detected corners.
+@param blockSize Size of an average block for computing a derivative covariation matrix over each
+pixel neighborhood. See cornerEigenValsAndVecs .
+@param gradientSize Aperture parameter for the Sobel operator used for derivatives computation.
+See cornerEigenValsAndVecs .
+@param useHarrisDetector Parameter indicating whether to use a Harris detector (see #cornerHarris)
+or #cornerMinEigenVal.
+@param k Free parameter of the Harris detector.
+ */
+CV_EXPORTS CV_WRAP_AS(goodFeaturesToTrackWithQuality) void goodFeaturesToTrack(
+ InputArray image, OutputArray corners,
+ int maxCorners, double qualityLevel, double minDistance,
+ InputArray mask, OutputArray cornersQuality, int blockSize = 3,
+ int gradientSize = 3, bool useHarrisDetector = false, double k = 0.04);
+
/** @example samples/cpp/tutorial_code/ImgTrans/houghlines.cpp
An example using the Hough line detector
![Sample input image](Hough_Lines_Tutorial_Original_Image.jpg) ![Output image](Hough_Lines_Tutorial_Result.jpg)
SANITY_CHECK(dst);
}
+OCL_PERF_TEST_P(GoodFeaturesToTrackFixture, GoodFeaturesToTrackWithQuality,
+ ::testing::Combine(OCL_PERF_ENUM(String("gpu/opticalflow/rubberwhale1.png")),
+ OCL_PERF_ENUM(3.0), Bool()))
+{
+ GoodFeaturesToTrackParams params = GetParam();
+ const String fileName = get<0>(params);
+ const double minDistance = get<1>(params), qualityLevel = 0.01;
+ const bool harrisDetector = get<2>(params);
+ const int maxCorners = 1000;
+
+ Mat img = imread(getDataPath(fileName), cv::IMREAD_GRAYSCALE);
+ ASSERT_FALSE(img.empty()) << "could not load " << fileName;
+
+ checkDeviceMaxMemoryAllocSize(img.size(), img.type());
+
+ UMat src(img.size(), img.type()), dst(1, maxCorners, CV_32FC2);
+ img.copyTo(src);
+
+ std::vector<float> cornersQuality;
+
+ declare.in(src, WARMUP_READ).out(dst);
+
+ OCL_TEST_CYCLE() cv::goodFeaturesToTrack(src, dst, maxCorners, qualityLevel, minDistance,
+ noArray(), cornersQuality, 3, 3, harrisDetector, 0.04);
+
+ SANITY_CHECK(dst);
+ SANITY_CHECK(cornersQuality, 1e-6);
+}
+
} } // namespace opencv_test::ocl
#endif
SANITY_CHECK(corners);
}
+PERF_TEST_P(Image_MaxCorners_QualityLevel_MinDistance_BlockSize_gradientSize_UseHarris, goodFeaturesToTrackWithQuality,
+ testing::Combine(
+ testing::Values( "stitching/a1.png", "cv/shared/pic5.png"),
+ testing::Values( 50 ),
+ testing::Values( 0.01 ),
+ testing::Values( 3 ),
+ testing::Values( 3 ),
+ testing::Bool()
+ )
+)
+{
+ string filename = getDataPath(get<0>(GetParam()));
+ int maxCorners = get<1>(GetParam());
+ double qualityLevel = get<2>(GetParam());
+ int blockSize = get<3>(GetParam());
+ int gradientSize = get<4>(GetParam());
+ bool useHarrisDetector = get<5>(GetParam());
+ double minDistance = 1;
+
+ Mat image = imread(filename, IMREAD_GRAYSCALE);
+ if (image.empty())
+ FAIL() << "Unable to load source image" << filename;
+
+ std::vector<Point2f> corners;
+ std::vector<float> cornersQuality;
+
+ TEST_CYCLE() goodFeaturesToTrack(image, corners, maxCorners, qualityLevel, minDistance, noArray(),
+ cornersQuality, blockSize, gradientSize, useHarrisDetector);
+
+ SANITY_CHECK(corners);
+ SANITY_CHECK(cornersQuality, 1e-6);
+}
+
} // namespace
static bool ocl_goodFeaturesToTrack( InputArray _image, OutputArray _corners,
int maxCorners, double qualityLevel, double minDistance,
- InputArray _mask, int blockSize, int gradientSize,
- bool useHarrisDetector, double harrisK )
+ InputArray _mask, OutputArray _cornersQuality, int blockSize, int gradientSize,
+ bool useHarrisDetector, double harrisK)
{
UMat eig, maxEigenValue;
if( useHarrisDetector )
std::sort(corner_ptr, corner_ptr + total);
std::vector<Point2f> corners;
+ std::vector<float> cornersQuality;
corners.reserve(total);
+ cornersQuality.reserve(total);
if (minDistance >= 1)
{
grid[y_cell*grid_width + x_cell].push_back(Point2f((float)c.x, (float)c.y));
corners.push_back(Point2f((float)c.x, (float)c.y));
+ cornersQuality.push_back(c.val);
++ncorners;
if( maxCorners > 0 && (int)ncorners == maxCorners )
const Corner & c = corner_ptr[i];
corners.push_back(Point2f((float)c.x, (float)c.y));
+ cornersQuality.push_back(c.val);
++ncorners;
+
if( maxCorners > 0 && (int)ncorners == maxCorners )
break;
}
}
Mat(corners).convertTo(_corners, _corners.fixedType() ? _corners.type() : CV_32F);
+ if (_cornersQuality.needed()) {
+ Mat(cornersQuality).convertTo(_cornersQuality, _cornersQuality.fixedType() ? _cornersQuality.type() : CV_32F);
+ }
+
return true;
}
}
+void cv::goodFeaturesToTrack( InputArray image, OutputArray corners,
+ int maxCorners, double qualityLevel, double minDistance,
+ InputArray mask, int blockSize, bool useHarrisDetector, double k )
+{
+ return goodFeaturesToTrack(image, corners, maxCorners, qualityLevel, minDistance,
+ mask, noArray(), blockSize, 3, useHarrisDetector, k);
+}
+
+void cv::goodFeaturesToTrack( InputArray image, OutputArray corners,
+ int maxCorners, double qualityLevel, double minDistance,
+ InputArray mask, int blockSize, int gradientSize, bool useHarrisDetector, double k )
+{
+ return goodFeaturesToTrack( image, corners, maxCorners, qualityLevel, minDistance,
+ mask, noArray(), blockSize, gradientSize, useHarrisDetector, k );
+}
+
void cv::goodFeaturesToTrack( InputArray _image, OutputArray _corners,
int maxCorners, double qualityLevel, double minDistance,
- InputArray _mask, int blockSize, int gradientSize,
+ InputArray _mask, OutputArray _cornersQuality, int blockSize, int gradientSize,
bool useHarrisDetector, double harrisK )
{
CV_INSTRUMENT_REGION();
CV_OCL_RUN(_image.dims() <= 2 && _image.isUMat(),
ocl_goodFeaturesToTrack(_image, _corners, maxCorners, qualityLevel, minDistance,
- _mask, blockSize, gradientSize, useHarrisDetector, harrisK))
+ _mask, _cornersQuality, blockSize, gradientSize, useHarrisDetector, harrisK))
Mat image = _image.getMat(), eig, tmp;
if (image.empty())
{
_corners.release();
+ _cornersQuality.release();
return;
}
}
std::vector<Point2f> corners;
+ std::vector<float> cornersQuality;
size_t i, j, total = tmpCorners.size(), ncorners = 0;
if (total == 0)
{
_corners.release();
+ _cornersQuality.release();
return;
}
{
grid[y_cell*grid_width + x_cell].push_back(Point2f((float)x, (float)y));
+ cornersQuality.push_back(*tmpCorners[i]);
+
corners.push_back(Point2f((float)x, (float)y));
++ncorners;
{
for( i = 0; i < total; i++ )
{
+ cornersQuality.push_back(*tmpCorners[i]);
+
int ofs = (int)((const uchar*)tmpCorners[i] - eig.ptr());
int y = (int)(ofs / eig.step);
int x = (int)((ofs - y*eig.step)/sizeof(float));
corners.push_back(Point2f((float)x, (float)y));
++ncorners;
+
if( maxCorners > 0 && (int)ncorners == maxCorners )
break;
}
}
Mat(corners).convertTo(_corners, _corners.fixedType() ? _corners.type() : CV_32F);
+ if (_cornersQuality.needed()) {
+ Mat(cornersQuality).convertTo(_cornersQuality, _cornersQuality.fixedType() ? _cornersQuality.type() : CV_32F);
+ }
}
CV_IMPL void
*_corner_count = (int)ncorners;
}
-void cv::goodFeaturesToTrack( InputArray _image, OutputArray _corners,
- int maxCorners, double qualityLevel, double minDistance,
- InputArray _mask, int blockSize,
- bool useHarrisDetector, double harrisK )
-{
- cv::goodFeaturesToTrack(_image, _corners, maxCorners, qualityLevel, minDistance,
- _mask, blockSize, 3, useHarrisDetector, harrisK );
-}
/* End of file. */
TEST_DECLARE_INPUT_PARAMETER(src);
UMat points, upoints;
+ std::vector<float> quality, uquality;
virtual void SetUp()
{
std::vector<Point2f> upts, pts;
- OCL_OFF(cv::goodFeaturesToTrack(src_roi, points, maxCorners, qualityLevel, minDistance, noArray()));
+ OCL_OFF(cv::goodFeaturesToTrack(src_roi, points, maxCorners, qualityLevel, minDistance, noArray(), quality));
ASSERT_FALSE(points.empty());
UMatToVector(points, pts);
- OCL_ON(cv::goodFeaturesToTrack(usrc_roi, upoints, maxCorners, qualityLevel, minDistance));
+ OCL_ON(cv::goodFeaturesToTrack(usrc_roi, upoints, maxCorners, qualityLevel, minDistance, noArray(), uquality));
ASSERT_FALSE(upoints.empty());
UMatToVector(upoints, upts);
+ ASSERT_EQ(pts.size(), quality.size());
+ ASSERT_EQ(upts.size(), uquality.size());
ASSERT_EQ(upts.size(), pts.size());
int mistmatch = 0;
{
Point2i a = upts[i], b = pts[i];
- bool eq = std::abs(a.x - b.x) < 1 && std::abs(a.y - b.y) < 1;
+ bool eq = std::abs(a.x - b.x) < 1 && std::abs(a.y - b.y) < 1 &&
+ std::abs(quality[i] - uquality[i]) <= 3.f * FLT_EPSILON * std::max(quality[i], uquality[i]);
if (!eq)
++mistmatch;
generateTestData();
usrc_roi.setTo(Scalar::all(0));
- OCL_ON(cv::goodFeaturesToTrack(usrc_roi, upoints, maxCorners, qualityLevel, minDistance));
+ OCL_ON(cv::goodFeaturesToTrack(usrc_roi, upoints, maxCorners, qualityLevel, minDistance, noArray(), uquality));
ASSERT_TRUE(upoints.empty());
+ ASSERT_TRUE(uquality.empty());
}
OCL_INSTANTIATE_TEST_CASE_P(Imgproc, GoodFeaturesToTrack,
cvtest::filter2D( src, dy2, ftype, kernel*kernel_scale, anchor, 0, borderType,borderValue );
double denom = (1 << (aperture_size-1))*block_size;
- denom = denom * denom;
if( _aperture_size < 0 )
- denom *= 4;
+ denom *= 2.;
if(type != ftype )
denom *= 255.;
- denom = 1./denom;
+ denom = 1. / (denom * denom);
for( i = 0; i < src.rows; i++ )
{
static void
test_goodFeaturesToTrack( InputArray _image, OutputArray _corners,
int maxCorners, double qualityLevel, double minDistance,
- InputArray _mask, int blockSize, int gradientSize,
- bool useHarrisDetector, double harrisK )
+ InputArray _mask, OutputArray _cornersQuality,
+ int blockSize, int gradientSize, bool useHarrisDetector, double harrisK)
{
CV_Assert( qualityLevel > 0 && minDistance >= 0 && maxCorners >= 0 );
}
vector<Point2f> corners;
+ vector<float> cornersQuality;
size_t i, j, total = tmpCorners.size(), ncorners = 0;
std::sort( tmpCorners.begin(), tmpCorners.end(), greaterThanPtr() );
{
grid[y_cell*grid_width + x_cell].push_back(Point2f((float)x, (float)y));
+ cornersQuality.push_back(*tmpCorners[i]);
+
corners.push_back(Point2f((float)x, (float)y));
++ncorners;
{
for( i = 0; i < total; i++ )
{
+ cornersQuality.push_back(*tmpCorners[i]);
+
int ofs = (int)((const uchar*)tmpCorners[i] - eig.data);
int y = (int)(ofs / eig.step);
int x = (int)((ofs - y*eig.step)/sizeof(float));
corners.push_back(Point2f((float)x, (float)y));
++ncorners;
+
if( maxCorners > 0 && (int)ncorners == maxCorners )
break;
}
}
Mat(corners).convertTo(_corners, _corners.fixedType() ? _corners.type() : CV_32F);
+ if (_cornersQuality.needed()) {
+ Mat(cornersQuality).convertTo(_cornersQuality, _cornersQuality.fixedType() ? _cornersQuality.type() : CV_32F);
+ }
}
int maxCorners;
vector<Point2f> corners;
vector<Point2f> Refcorners;
+ vector<float> cornersQuality;
+ vector<float> RefcornersQuality;
double qualityLevel;
double minDistance;
int blockSize;
qualityLevel,
minDistance,
Mat(),
+ cornersQuality,
blockSize,
gradientSize,
useHarrisDetector,
qualityLevel,
minDistance,
Mat(),
+ cornersQuality,
blockSize,
gradientSize,
useHarrisDetector,
qualityLevel,
minDistance,
Mat(),
+ RefcornersQuality,
blockSize,
gradientSize,
useHarrisDetector,
qualityLevel,
minDistance,
Mat(),
+ RefcornersQuality,
blockSize,
gradientSize,
useHarrisDetector,
TEST_MESSAGEL (" TestCorners = ", corners.size())
TEST_MESSAGE ("\n")
- ts->printf(cvtest::TS::CONSOLE, "actual error: %g, expected: %g", e, eps);
+ EXPECT_LE(e, eps); // never true
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
for(int i = 0; i < (int)std::min((unsigned int)(corners.size()), (unsigned int)(Refcorners.size())); i++){
ts->set_failed_test_info(cvtest::TS::OK);
}
+ e = cv::norm(cornersQuality, RefcornersQuality, NORM_RELATIVE | NORM_INF);
+
+ if (e > eps)
+ {
+ EXPECT_LE(e, eps); // never true
+ ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+
+ for(int i = 0; i < (int)std::min((unsigned int)(cornersQuality.size()), (unsigned int)(cornersQuality.size())); i++) {
+ if (std::abs(cornersQuality[i] - RefcornersQuality[i]) > eps * std::max(cornersQuality[i], RefcornersQuality[i]))
+ printf("i = %i Quality %2.6f Quality ref %2.6f\n", i, cornersQuality[i], RefcornersQuality[i]);
+ }
+ }
+
return BaseTest::validate_test_results(test_case_idx);
}