Skip to content

Commit 47426a8

Browse files
amirtuWisdomPillamir.tulegenov
authored
Merge pull request opencv#19392 from amirtu:OCV-165_finalize_goodFeaturesToTrack_returns_also_corner_value_PR
* goodFeaturesToTrack returns also corner value (cherry picked from commit 4a8f067) * Added response to GFTT Detector keypoints (cherry picked from commit b88fb40) * Moved corner values to another optional variable to preserve backward compatibility (cherry picked from commit 6137383) * Removed corners valus from perf tests and better unit tests for corners values (cherry picked from commit f3d0ef2) * Fixed detector gftt call (cherry picked from commit be29755) * Restored test_cornerEigenValsVecs (cherry picked from commit ea3e118) * scaling fixed; mineigen calculation rolled back; gftt function overload added (with quality parameter); perf tests were added for the new api function; external bindings were added for the function (with different alias); fixed issues with composition of the output array of the new function (e.g. as requested in comments) ; added sanity checks in the perf tests; removed C API changes. * minor change to GFTTDetector::detect * substitute ts->printf with EXPECT_LE * avoid re-allocations Co-authored-by: Anas <anas.el.amraoui@live.com> Co-authored-by: amir.tulegenov <amir.tulegenov@xperience.ai>
1 parent ad66b07 commit 47426a8

File tree

7 files changed

+183
-28
lines changed

7 files changed

+183
-28
lines changed

modules/features2d/src/gftt.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ class GFTTDetector_Impl CV_FINAL : public GFTTDetector
8787
}
8888

8989
std::vector<Point2f> corners;
90+
std::vector<float> cornersQuality;
9091

9192
if (_image.isUMat())
9293
{
@@ -97,7 +98,7 @@ class GFTTDetector_Impl CV_FINAL : public GFTTDetector
9798
ugrayImage = _image.getUMat();
9899

99100
goodFeaturesToTrack( ugrayImage, corners, nfeatures, qualityLevel, minDistance, _mask,
100-
blockSize, gradSize, useHarrisDetector, k );
101+
cornersQuality, blockSize, gradSize, useHarrisDetector, k );
101102
}
102103
else
103104
{
@@ -106,14 +107,14 @@ class GFTTDetector_Impl CV_FINAL : public GFTTDetector
106107
cvtColor( image, grayImage, COLOR_BGR2GRAY );
107108

108109
goodFeaturesToTrack( grayImage, corners, nfeatures, qualityLevel, minDistance, _mask,
109-
blockSize, gradSize, useHarrisDetector, k );
110+
cornersQuality, blockSize, gradSize, useHarrisDetector, k );
110111
}
111112

113+
CV_Assert(corners.size() == cornersQuality.size());
114+
112115
keypoints.resize(corners.size());
113-
std::vector<Point2f>::const_iterator corner_it = corners.begin();
114-
std::vector<KeyPoint>::iterator keypoint_it = keypoints.begin();
115-
for( ; corner_it != corners.end() && keypoint_it != keypoints.end(); ++corner_it, ++keypoint_it )
116-
*keypoint_it = KeyPoint( *corner_it, (float)blockSize );
116+
for (size_t i = 0; i < corners.size(); i++)
117+
keypoints[i] = KeyPoint(corners[i], (float)blockSize, -1, cornersQuality[i]);
117118

118119
}
119120

modules/imgproc/include/opencv2/imgproc.hpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,6 +1999,38 @@ CV_EXPORTS_W void goodFeaturesToTrack( InputArray image, OutputArray corners,
19991999
InputArray mask, int blockSize,
20002000
int gradientSize, bool useHarrisDetector = false,
20012001
double k = 0.04 );
2002+
2003+
/** @brief Same as above, but returns also quality measure of the detected corners.
2004+
2005+
@param image Input 8-bit or floating-point 32-bit, single-channel image.
2006+
@param corners Output vector of detected corners.
2007+
@param maxCorners Maximum number of corners to return. If there are more corners than are found,
2008+
the strongest of them is returned. `maxCorners <= 0` implies that no limit on the maximum is set
2009+
and all detected corners are returned.
2010+
@param qualityLevel Parameter characterizing the minimal accepted quality of image corners. The
2011+
parameter value is multiplied by the best corner quality measure, which is the minimal eigenvalue
2012+
(see #cornerMinEigenVal ) or the Harris function response (see #cornerHarris ). The corners with the
2013+
quality measure less than the product are rejected. For example, if the best corner has the
2014+
quality measure = 1500, and the qualityLevel=0.01 , then all the corners with the quality measure
2015+
less than 15 are rejected.
2016+
@param minDistance Minimum possible Euclidean distance between the returned corners.
2017+
@param mask Region of interest. If the image is not empty (it needs to have the type
2018+
CV_8UC1 and the same size as image ), it specifies the region in which the corners are detected.
2019+
@param cornersQuality Output vector of quality measure of the detected corners.
2020+
@param blockSize Size of an average block for computing a derivative covariation matrix over each
2021+
pixel neighborhood. See cornerEigenValsAndVecs .
2022+
@param gradientSize Aperture parameter for the Sobel operator used for derivatives computation.
2023+
See cornerEigenValsAndVecs .
2024+
@param useHarrisDetector Parameter indicating whether to use a Harris detector (see #cornerHarris)
2025+
or #cornerMinEigenVal.
2026+
@param k Free parameter of the Harris detector.
2027+
*/
2028+
CV_EXPORTS CV_WRAP_AS(goodFeaturesToTrackWithQuality) void goodFeaturesToTrack(
2029+
InputArray image, OutputArray corners,
2030+
int maxCorners, double qualityLevel, double minDistance,
2031+
InputArray mask, OutputArray cornersQuality, int blockSize = 3,
2032+
int gradientSize = 3, bool useHarrisDetector = false, double k = 0.04);
2033+
20022034
/** @example samples/cpp/tutorial_code/ImgTrans/houghlines.cpp
20032035
An example using the Hough line detector
20042036
![Sample input image](Hough_Lines_Tutorial_Original_Image.jpg) ![Output image](Hough_Lines_Tutorial_Result.jpg)

modules/imgproc/perf/opencl/perf_gftt.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,35 @@ OCL_PERF_TEST_P(GoodFeaturesToTrackFixture, GoodFeaturesToTrack,
8282
SANITY_CHECK(dst);
8383
}
8484

85+
OCL_PERF_TEST_P(GoodFeaturesToTrackFixture, GoodFeaturesToTrackWithQuality,
86+
::testing::Combine(OCL_PERF_ENUM(String("gpu/opticalflow/rubberwhale1.png")),
87+
OCL_PERF_ENUM(3.0), Bool()))
88+
{
89+
GoodFeaturesToTrackParams params = GetParam();
90+
const String fileName = get<0>(params);
91+
const double minDistance = get<1>(params), qualityLevel = 0.01;
92+
const bool harrisDetector = get<2>(params);
93+
const int maxCorners = 1000;
94+
95+
Mat img = imread(getDataPath(fileName), cv::IMREAD_GRAYSCALE);
96+
ASSERT_FALSE(img.empty()) << "could not load " << fileName;
97+
98+
checkDeviceMaxMemoryAllocSize(img.size(), img.type());
99+
100+
UMat src(img.size(), img.type()), dst(1, maxCorners, CV_32FC2);
101+
img.copyTo(src);
102+
103+
std::vector<float> cornersQuality;
104+
105+
declare.in(src, WARMUP_READ).out(dst);
106+
107+
OCL_TEST_CYCLE() cv::goodFeaturesToTrack(src, dst, maxCorners, qualityLevel, minDistance,
108+
noArray(), cornersQuality, 3, 3, harrisDetector, 0.04);
109+
110+
SANITY_CHECK(dst);
111+
SANITY_CHECK(cornersQuality, 1e-6);
112+
}
113+
85114
} } // namespace opencv_test::ocl
86115

87116
#endif

modules/imgproc/perf/perf_goodFeaturesToTrack.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,37 @@ PERF_TEST_P(Image_MaxCorners_QualityLevel_MinDistance_BlockSize_gradientSize_Use
4141
SANITY_CHECK(corners);
4242
}
4343

44+
PERF_TEST_P(Image_MaxCorners_QualityLevel_MinDistance_BlockSize_gradientSize_UseHarris, goodFeaturesToTrackWithQuality,
45+
testing::Combine(
46+
testing::Values( "stitching/a1.png", "cv/shared/pic5.png"),
47+
testing::Values( 50 ),
48+
testing::Values( 0.01 ),
49+
testing::Values( 3 ),
50+
testing::Values( 3 ),
51+
testing::Bool()
52+
)
53+
)
54+
{
55+
string filename = getDataPath(get<0>(GetParam()));
56+
int maxCorners = get<1>(GetParam());
57+
double qualityLevel = get<2>(GetParam());
58+
int blockSize = get<3>(GetParam());
59+
int gradientSize = get<4>(GetParam());
60+
bool useHarrisDetector = get<5>(GetParam());
61+
double minDistance = 1;
62+
63+
Mat image = imread(filename, IMREAD_GRAYSCALE);
64+
if (image.empty())
65+
FAIL() << "Unable to load source image" << filename;
66+
67+
std::vector<Point2f> corners;
68+
std::vector<float> cornersQuality;
69+
70+
TEST_CYCLE() goodFeaturesToTrack(image, corners, maxCorners, qualityLevel, minDistance, noArray(),
71+
cornersQuality, blockSize, gradientSize, useHarrisDetector);
72+
73+
SANITY_CHECK(corners);
74+
SANITY_CHECK(cornersQuality, 1e-6);
75+
}
76+
4477
} // namespace

modules/imgproc/src/featureselect.cpp

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ struct Corner
7474

7575
static bool ocl_goodFeaturesToTrack( InputArray _image, OutputArray _corners,
7676
int maxCorners, double qualityLevel, double minDistance,
77-
InputArray _mask, int blockSize, int gradientSize,
78-
bool useHarrisDetector, double harrisK )
77+
InputArray _mask, OutputArray _cornersQuality, int blockSize, int gradientSize,
78+
bool useHarrisDetector, double harrisK)
7979
{
8080
UMat eig, maxEigenValue;
8181
if( useHarrisDetector )
@@ -176,7 +176,9 @@ static bool ocl_goodFeaturesToTrack( InputArray _image, OutputArray _corners,
176176
std::sort(corner_ptr, corner_ptr + total);
177177

178178
std::vector<Point2f> corners;
179+
std::vector<float> cornersQuality;
179180
corners.reserve(total);
181+
cornersQuality.reserve(total);
180182

181183
if (minDistance >= 1)
182184
{
@@ -237,6 +239,7 @@ static bool ocl_goodFeaturesToTrack( InputArray _image, OutputArray _corners,
237239
grid[y_cell*grid_width + x_cell].push_back(Point2f((float)c.x, (float)c.y));
238240

239241
corners.push_back(Point2f((float)c.x, (float)c.y));
242+
cornersQuality.push_back(c.val);
240243
++ncorners;
241244

242245
if( maxCorners > 0 && (int)ncorners == maxCorners )
@@ -251,13 +254,19 @@ static bool ocl_goodFeaturesToTrack( InputArray _image, OutputArray _corners,
251254
const Corner & c = corner_ptr[i];
252255

253256
corners.push_back(Point2f((float)c.x, (float)c.y));
257+
cornersQuality.push_back(c.val);
254258
++ncorners;
259+
255260
if( maxCorners > 0 && (int)ncorners == maxCorners )
256261
break;
257262
}
258263
}
259264

260265
Mat(corners).convertTo(_corners, _corners.fixedType() ? _corners.type() : CV_32F);
266+
if (_cornersQuality.needed()) {
267+
Mat(cornersQuality).convertTo(_cornersQuality, _cornersQuality.fixedType() ? _cornersQuality.type() : CV_32F);
268+
}
269+
261270
return true;
262271
}
263272

@@ -354,9 +363,25 @@ static bool openvx_harris(Mat image, OutputArray _corners,
354363

355364
}
356365

366+
void cv::goodFeaturesToTrack( InputArray image, OutputArray corners,
367+
int maxCorners, double qualityLevel, double minDistance,
368+
InputArray mask, int blockSize, bool useHarrisDetector, double k )
369+
{
370+
return goodFeaturesToTrack(image, corners, maxCorners, qualityLevel, minDistance,
371+
mask, noArray(), blockSize, 3, useHarrisDetector, k);
372+
}
373+
374+
void cv::goodFeaturesToTrack( InputArray image, OutputArray corners,
375+
int maxCorners, double qualityLevel, double minDistance,
376+
InputArray mask, int blockSize, int gradientSize, bool useHarrisDetector, double k )
377+
{
378+
return goodFeaturesToTrack( image, corners, maxCorners, qualityLevel, minDistance,
379+
mask, noArray(), blockSize, gradientSize, useHarrisDetector, k );
380+
}
381+
357382
void cv::goodFeaturesToTrack( InputArray _image, OutputArray _corners,
358383
int maxCorners, double qualityLevel, double minDistance,
359-
InputArray _mask, int blockSize, int gradientSize,
384+
InputArray _mask, OutputArray _cornersQuality, int blockSize, int gradientSize,
360385
bool useHarrisDetector, double harrisK )
361386
{
362387
CV_INSTRUMENT_REGION();
@@ -366,12 +391,13 @@ void cv::goodFeaturesToTrack( InputArray _image, OutputArray _corners,
366391

367392
CV_OCL_RUN(_image.dims() <= 2 && _image.isUMat(),
368393
ocl_goodFeaturesToTrack(_image, _corners, maxCorners, qualityLevel, minDistance,
369-
_mask, blockSize, gradientSize, useHarrisDetector, harrisK))
394+
_mask, _cornersQuality, blockSize, gradientSize, useHarrisDetector, harrisK))
370395

371396
Mat image = _image.getMat(), eig, tmp;
372397
if (image.empty())
373398
{
374399
_corners.release();
400+
_cornersQuality.release();
375401
return;
376402
}
377403

@@ -410,11 +436,13 @@ void cv::goodFeaturesToTrack( InputArray _image, OutputArray _corners,
410436
}
411437

412438
std::vector<Point2f> corners;
439+
std::vector<float> cornersQuality;
413440
size_t i, j, total = tmpCorners.size(), ncorners = 0;
414441

415442
if (total == 0)
416443
{
417444
_corners.release();
445+
_cornersQuality.release();
418446
return;
419447
}
420448

@@ -485,6 +513,8 @@ void cv::goodFeaturesToTrack( InputArray _image, OutputArray _corners,
485513
{
486514
grid[y_cell*grid_width + x_cell].push_back(Point2f((float)x, (float)y));
487515

516+
cornersQuality.push_back(*tmpCorners[i]);
517+
488518
corners.push_back(Point2f((float)x, (float)y));
489519
++ncorners;
490520

@@ -497,18 +527,24 @@ void cv::goodFeaturesToTrack( InputArray _image, OutputArray _corners,
497527
{
498528
for( i = 0; i < total; i++ )
499529
{
530+
cornersQuality.push_back(*tmpCorners[i]);
531+
500532
int ofs = (int)((const uchar*)tmpCorners[i] - eig.ptr());
501533
int y = (int)(ofs / eig.step);
502534
int x = (int)((ofs - y*eig.step)/sizeof(float));
503535

504536
corners.push_back(Point2f((float)x, (float)y));
505537
++ncorners;
538+
506539
if( maxCorners > 0 && (int)ncorners == maxCorners )
507540
break;
508541
}
509542
}
510543

511544
Mat(corners).convertTo(_corners, _corners.fixedType() ? _corners.type() : CV_32F);
545+
if (_cornersQuality.needed()) {
546+
Mat(cornersQuality).convertTo(_cornersQuality, _cornersQuality.fixedType() ? _cornersQuality.type() : CV_32F);
547+
}
512548
}
513549

514550
CV_IMPL void
@@ -534,12 +570,4 @@ cvGoodFeaturesToTrack( const void* _image, void*, void*,
534570
*_corner_count = (int)ncorners;
535571
}
536572

537-
void cv::goodFeaturesToTrack( InputArray _image, OutputArray _corners,
538-
int maxCorners, double qualityLevel, double minDistance,
539-
InputArray _mask, int blockSize,
540-
bool useHarrisDetector, double harrisK )
541-
{
542-
cv::goodFeaturesToTrack(_image, _corners, maxCorners, qualityLevel, minDistance,
543-
_mask, blockSize, 3, useHarrisDetector, harrisK );
544-
}
545573
/* End of file. */

modules/imgproc/test/ocl/test_gftt.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ PARAM_TEST_CASE(GoodFeaturesToTrack, double, bool)
6262

6363
TEST_DECLARE_INPUT_PARAMETER(src);
6464
UMat points, upoints;
65+
std::vector<float> quality, uquality;
6566

6667
virtual void SetUp()
6768
{
@@ -100,22 +101,25 @@ OCL_TEST_P(GoodFeaturesToTrack, Accuracy)
100101

101102
std::vector<Point2f> upts, pts;
102103

103-
OCL_OFF(cv::goodFeaturesToTrack(src_roi, points, maxCorners, qualityLevel, minDistance, noArray()));
104+
OCL_OFF(cv::goodFeaturesToTrack(src_roi, points, maxCorners, qualityLevel, minDistance, noArray(), quality));
104105
ASSERT_FALSE(points.empty());
105106
UMatToVector(points, pts);
106107

107-
OCL_ON(cv::goodFeaturesToTrack(usrc_roi, upoints, maxCorners, qualityLevel, minDistance));
108+
OCL_ON(cv::goodFeaturesToTrack(usrc_roi, upoints, maxCorners, qualityLevel, minDistance, noArray(), uquality));
108109
ASSERT_FALSE(upoints.empty());
109110
UMatToVector(upoints, upts);
110111

112+
ASSERT_EQ(pts.size(), quality.size());
113+
ASSERT_EQ(upts.size(), uquality.size());
111114
ASSERT_EQ(upts.size(), pts.size());
112115

113116
int mistmatch = 0;
114117
for (size_t i = 0; i < pts.size(); ++i)
115118
{
116119
Point2i a = upts[i], b = pts[i];
117120

118-
bool eq = std::abs(a.x - b.x) < 1 && std::abs(a.y - b.y) < 1;
121+
bool eq = std::abs(a.x - b.x) < 1 && std::abs(a.y - b.y) < 1 &&
122+
std::abs(quality[i] - uquality[i]) <= 3.f * FLT_EPSILON * std::max(quality[i], uquality[i]);
119123

120124
if (!eq)
121125
++mistmatch;
@@ -131,9 +135,10 @@ OCL_TEST_P(GoodFeaturesToTrack, EmptyCorners)
131135
generateTestData();
132136
usrc_roi.setTo(Scalar::all(0));
133137

134-
OCL_ON(cv::goodFeaturesToTrack(usrc_roi, upoints, maxCorners, qualityLevel, minDistance));
138+
OCL_ON(cv::goodFeaturesToTrack(usrc_roi, upoints, maxCorners, qualityLevel, minDistance, noArray(), uquality));
135139

136140
ASSERT_TRUE(upoints.empty());
141+
ASSERT_TRUE(uquality.empty());
137142
}
138143

139144
OCL_INSTANTIATE_TEST_CASE_P(Imgproc, GoodFeaturesToTrack,

0 commit comments

Comments
 (0)