mirror of
https://github.com/opencv/opencv.git
synced 2026-09-12 13:23:03 -05:00
Merge pull request #29740 from varun-jaiswal17:imgproc_cleanup
Imgproc test cleanup - #29740 co-authored by: @Prasadayus ### Re-enabled as-is (stale disable reasons) - `FillPolyFully.fillpoly_fully` (`test_drawing.cpp:1142`) - `Resize_Bitexact` (`test_resize_bitexact.cpp:188`, 4 instantiations): `INTER_NEAREST` and `INTER_NEAREST_EXACT` agree exactly at integer upscale factors; measured 0.0 diff on all 4. ### Add assertions - **imgproc** — new `Imgproc_Watershed.regression`: `cv::watershed` had no working coverage at all. ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
@@ -1139,7 +1139,7 @@ PARAM_TEST_CASE(FillPolyFully, unsigned, unsigned, int, int, Point, cv::LineType
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(FillPolyFully, DISABLED_fillpoly_fully)
|
||||
TEST_P(FillPolyFully, fillpoly_fully)
|
||||
{
|
||||
int imageSizeOffset = 15;
|
||||
|
||||
|
||||
@@ -44,41 +44,30 @@
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
class CV_ImgprocUMatTest : public cvtest::BaseTest
|
||||
TEST(Imgproc_UMat, regression)
|
||||
{
|
||||
public:
|
||||
CV_ImgprocUMatTest() {}
|
||||
~CV_ImgprocUMatTest() {}
|
||||
protected:
|
||||
void run(int)
|
||||
{
|
||||
string imgpath = string(ts->get_data_path()) + "shared/lena.png";
|
||||
Mat img = imread(imgpath, IMREAD_COLOR), gray, smallimg, result;
|
||||
UMat uimg = img.getUMat(ACCESS_READ), ugray, usmallimg, uresult;
|
||||
const string imgpath = cvtest::findDataFile("shared/lena.png");
|
||||
Mat img = imread(imgpath, IMREAD_COLOR);
|
||||
ASSERT_FALSE(img.empty());
|
||||
|
||||
cvtColor(img, gray, COLOR_BGR2GRAY);
|
||||
resize(gray, smallimg, Size(), 0.75, 0.75, INTER_LINEAR_EXACT);
|
||||
equalizeHist(smallimg, result);
|
||||
Mat gray, smallimg, result;
|
||||
cvtColor(img, gray, COLOR_BGR2GRAY);
|
||||
resize(gray, smallimg, Size(), 0.75, 0.75, INTER_LINEAR_EXACT);
|
||||
equalizeHist(smallimg, result);
|
||||
|
||||
cvtColor(uimg, ugray, COLOR_BGR2GRAY);
|
||||
resize(ugray, usmallimg, Size(), 0.75, 0.75, INTER_LINEAR_EXACT);
|
||||
equalizeHist(usmallimg, uresult);
|
||||
// Deliberately getUMat() rather than copyTo(): the ocl/ tests always upload
|
||||
// by copy (UMAT_UPLOAD_INPUT_PARAMETER), so this is the only coverage of an
|
||||
// imgproc chain fed by a UMat view over a Mat that stays alive alongside it.
|
||||
UMat uimg = img.getUMat(ACCESS_READ), ugray, usmallimg, uresult;
|
||||
cvtColor(uimg, ugray, COLOR_BGR2GRAY);
|
||||
resize(ugray, usmallimg, Size(), 0.75, 0.75, INTER_LINEAR_EXACT);
|
||||
equalizeHist(usmallimg, uresult);
|
||||
|
||||
#if 0
|
||||
imshow("orig", uimg);
|
||||
imshow("small", usmallimg);
|
||||
imshow("equalized gray", uresult);
|
||||
waitKey();
|
||||
destroyWindow("orig");
|
||||
destroyWindow("small");
|
||||
destroyWindow("equalized gray");
|
||||
#endif
|
||||
ts->set_failed_test_info(cvtest::TS::OK);
|
||||
|
||||
(void)uresult.getMat(ACCESS_READ);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(Imgproc_UMat, regression) { CV_ImgprocUMatTest test; test.safe_run(); }
|
||||
// Measured identical here; the tolerance of 1 matches OCL_TEST_P(EqualizeHist, Mat),
|
||||
// since bit-exactness was only confirmed on one device.
|
||||
Mat uresult_host = uresult.getMat(ACCESS_READ);
|
||||
EXPECT_LE(cv::norm(result, uresult_host, NORM_INF), 1)
|
||||
<< "Mat and UMat imgproc pipelines disagree";
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -183,8 +183,9 @@ TEST_P(Resize_Bitexact, Nearest8U_vsNonExact)
|
||||
EXPECT_EQ(CountDiff(mat_gray), 0) << "gray, type: " << depth;
|
||||
}
|
||||
|
||||
// Now INTER_NEAREST's convention and INTER_NEAREST_EXACT's one are different.
|
||||
INSTANTIATE_TEST_CASE_P(DISABLED_Imgproc, Resize_Bitexact,
|
||||
// At an integer upscale INTER_NEAREST and INTER_NEAREST_EXACT both map dst i to src i/k, so they
|
||||
// agree here. They diverge on downscale and fractional factors, where EXACT follows Pillow.
|
||||
INSTANTIATE_TEST_CASE_P(Imgproc, Resize_Bitexact,
|
||||
testing::Values(CV_8U, CV_16U, CV_32F, CV_64F)
|
||||
);
|
||||
|
||||
|
||||
@@ -41,3 +41,70 @@
|
||||
//M*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
// Seeds are eroded copies of the stored reference regions, so watershed has to re-grow the
|
||||
// boundaries. The neighbouring watershed/comp.xml is not used: it is an
|
||||
// "opencv-sequence-tree" holding CvSeq contours and needs the removed C API to read.
|
||||
TEST(Imgproc_Watershed, regression)
|
||||
{
|
||||
const string folder = string(cvtest::TS::ptr()->get_data_path());
|
||||
const string expPath = folder + "watershed/wshed_exp.png";
|
||||
|
||||
Mat image = imread(folder + "inpaint/orig.png", IMREAD_COLOR);
|
||||
Mat expLabels8 = imread(expPath, IMREAD_GRAYSCALE);
|
||||
ASSERT_FALSE(image.empty()) << "Could not read " << folder << "inpaint/orig.png";
|
||||
ASSERT_FALSE(expLabels8.empty()) << "Could not read " << expPath;
|
||||
ASSERT_EQ(image.size(), expLabels8.size());
|
||||
|
||||
// wshed_exp.png stores the expected labels offset by +1, so that the -1 used for
|
||||
// watershed boundaries survives being written to an 8-bit PNG.
|
||||
Mat expected;
|
||||
expLabels8.convertTo(expected, CV_32S);
|
||||
expected -= 1; // -1 = boundary, 1..nLabels = regions
|
||||
|
||||
double maxLabel = 0;
|
||||
minMaxLoc(expected, 0, &maxLabel);
|
||||
const int nLabels = cvRound(maxLabel);
|
||||
ASSERT_GT(nLabels, 1) << "reference image does not contain several regions";
|
||||
|
||||
Mat markers = Mat::zeros(expected.size(), CV_32S);
|
||||
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(15, 15));
|
||||
for (int label = 1; label <= nLabels; label++)
|
||||
{
|
||||
Mat seed;
|
||||
erode(expected == label, seed, kernel);
|
||||
ASSERT_GT(countNonZero(seed), 0) << "region " << label << " vanished when eroded";
|
||||
markers.setTo(label, seed);
|
||||
}
|
||||
|
||||
Mat result = markers.clone();
|
||||
watershed(image, result);
|
||||
|
||||
ASSERT_EQ(expected.size(), result.size());
|
||||
ASSERT_EQ(CV_32S, result.type());
|
||||
|
||||
EXPECT_EQ(0, countNonZero(result == 0)) << "watershed left pixels unlabelled";
|
||||
|
||||
double minVal = 0, maxVal = 0;
|
||||
minMaxLoc(result, &minVal, &maxVal);
|
||||
EXPECT_GE(minVal, -1);
|
||||
EXPECT_LE(maxVal, nLabels) << "watershed produced a label that was never seeded";
|
||||
|
||||
// Measured: ~99.6% for a correct implementation, ~78.7% if watershed does nothing.
|
||||
Mat interior = expected > 0;
|
||||
const int totalPx = countNonZero(interior);
|
||||
ASSERT_GT(totalPx, 0);
|
||||
Mat agreeMask;
|
||||
bitwise_and(result == expected, interior, agreeMask);
|
||||
const double agreement = (double)countNonZero(agreeMask) / totalPx;
|
||||
EXPECT_GT(agreement, 0.95)
|
||||
<< "only " << agreement * 100 << "% of interior pixels match " << expPath;
|
||||
|
||||
Mat again = markers.clone();
|
||||
watershed(image, again);
|
||||
EXPECT_EQ(0, countNonZero(again != result)) << "watershed is not deterministic";
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -22,8 +22,17 @@ class watershed_test(NewOpenCVTests):
|
||||
if img is None or markers is None:
|
||||
self.assertEqual(0, 1, 'Missing test data')
|
||||
|
||||
# cv.watershed() writes into markers in place, so the CV_32S array must be bound
|
||||
# to a name: np.int32(markers) inline would hand over a temporary.
|
||||
markers = np.int32(markers)
|
||||
before = markers.copy()
|
||||
|
||||
colors = np.int32( list(np.ndindex(3, 3, 3)) ) * 122
|
||||
cv.watershed(img, np.int32(markers))
|
||||
cv.watershed(img, markers)
|
||||
|
||||
self.assertFalse(np.array_equal(before, markers),
|
||||
'cv.watershed() did not modify the markers in place')
|
||||
|
||||
segments = colors[np.maximum(markers, 0)]
|
||||
|
||||
if refSegments is None:
|
||||
|
||||
Reference in New Issue
Block a user