mirror of
https://github.com/opencv/opencv.git
synced 2026-07-31 00:03:03 +04:00
Merge branch '4.x' into '5.x'
This commit is contained in:
@@ -60,7 +60,7 @@ map<string, BarcodeResult> testResults {
|
||||
{ "single/book.jpg", {"EAN_13", "9787115279460"} },
|
||||
{ "single/bottle_1.jpg", {"EAN_13", "6922255451427"} },
|
||||
{ "single/bottle_2.jpg", {"EAN_13", "6921168509256"} },
|
||||
{ "multiple/4_barcodes.jpg", {"EAN_13;EAN_13;EAN_13;EAN_13", "9787564350840;9783319200064;9787118081473;9787122276124"} }
|
||||
{ "multiple/4_barcodes.jpg", {"EAN_13;EAN_13;EAN_13;EAN_13", "9787564350840;9783319200064;9787118081473;9787122276124"} },
|
||||
};
|
||||
|
||||
typedef testing::TestWithParam< string > BarcodeDetector_main;
|
||||
@@ -144,4 +144,87 @@ TEST(BarcodeDetector_base, invalid)
|
||||
EXPECT_ANY_THROW(bardet.decodeMulti(zero_image, corners, decoded_info));
|
||||
}
|
||||
|
||||
struct ParamStruct
|
||||
{
|
||||
double down_thresh;
|
||||
vector<float> scales;
|
||||
double grad_thresh;
|
||||
unsigned res_count;
|
||||
};
|
||||
|
||||
inline static std::ostream &operator<<(std::ostream &out, const ParamStruct &p)
|
||||
{
|
||||
out << "(" << p.down_thresh << ", ";
|
||||
for(float val : p.scales)
|
||||
out << val << ", ";
|
||||
out << p.grad_thresh << ")";
|
||||
return out;
|
||||
}
|
||||
|
||||
ParamStruct param_list[] = {
|
||||
{ 512, {0.01f, 0.03f, 0.06f, 0.08f}, 64, 4 }, // default values -> 4 codes
|
||||
{ 512, {0.01f, 0.03f, 0.06f, 0.08f}, 1024, 2 },
|
||||
{ 512, {0.01f, 0.03f, 0.06f, 0.08f}, 2048, 0 },
|
||||
{ 128, {0.01f, 0.03f, 0.06f, 0.08f}, 64, 3 },
|
||||
{ 64, {0.01f, 0.03f, 0.06f, 0.08f}, 64, 2 },
|
||||
{ 128, {0.0000001f}, 64, 1 },
|
||||
{ 128, {0.0000001f, 0.0001f}, 64, 1 },
|
||||
{ 128, {0.0000001f, 0.1f}, 64, 1 },
|
||||
{ 512, {0.1f}, 64, 0 },
|
||||
};
|
||||
|
||||
typedef testing::TestWithParam<ParamStruct> BarcodeDetector_parameters_tune;
|
||||
|
||||
TEST_P(BarcodeDetector_parameters_tune, accuracy)
|
||||
{
|
||||
const ParamStruct param = GetParam();
|
||||
|
||||
const string fname = "multiple/4_barcodes.jpg";
|
||||
const string image_path = findDataFile(string("barcode/") + fname);
|
||||
|
||||
const Mat img = imread(image_path);
|
||||
ASSERT_FALSE(img.empty()) << "Can't read image: " << image_path;
|
||||
|
||||
auto bardet = barcode::BarcodeDetector();
|
||||
bardet.setDownsamplingThreshold(param.down_thresh);
|
||||
bardet.setDetectorScales(param.scales);
|
||||
bardet.setGradientThreshold(param.grad_thresh);
|
||||
vector<Point2f> points;
|
||||
bardet.detectMulti(img, points);
|
||||
EXPECT_EQ(points.size() / 4, param.res_count);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, BarcodeDetector_parameters_tune, testing::ValuesIn(param_list));
|
||||
|
||||
TEST(BarcodeDetector_parameters, regression)
|
||||
{
|
||||
const double expected_dt = 1024, expected_gt = 256;
|
||||
const vector<float> expected_ds = {0.1f};
|
||||
vector<float> ds_value = {0.0f};
|
||||
|
||||
auto bardet = barcode::BarcodeDetector();
|
||||
|
||||
bardet.setDownsamplingThreshold(expected_dt).setDetectorScales(expected_ds).setGradientThreshold(expected_gt);
|
||||
|
||||
double dt_value = bardet.getDownsamplingThreshold();
|
||||
bardet.getDetectorScales(ds_value);
|
||||
double gt_value = bardet.getGradientThreshold();
|
||||
|
||||
EXPECT_EQ(expected_dt, dt_value);
|
||||
EXPECT_EQ(expected_ds, ds_value);
|
||||
EXPECT_EQ(expected_gt, gt_value);
|
||||
}
|
||||
|
||||
TEST(BarcodeDetector_parameters, invalid)
|
||||
{
|
||||
auto bardet = barcode::BarcodeDetector();
|
||||
|
||||
EXPECT_ANY_THROW(bardet.setDownsamplingThreshold(-1));
|
||||
EXPECT_ANY_THROW(bardet.setDetectorScales(vector<float> {}));
|
||||
EXPECT_ANY_THROW(bardet.setDetectorScales(vector<float> {-1}));
|
||||
EXPECT_ANY_THROW(bardet.setDetectorScales(vector<float> {1.5}));
|
||||
EXPECT_ANY_THROW(bardet.setDetectorScales(vector<float> (17, 0.5)));
|
||||
EXPECT_ANY_THROW(bardet.setGradientThreshold(-0.1));
|
||||
}
|
||||
|
||||
}} // opencv_test::<anonymous>::
|
||||
|
||||
@@ -81,6 +81,18 @@ static Mat projectCharucoBoard(aruco::CharucoBoard& board, Mat cameraMatrix, dou
|
||||
return img;
|
||||
}
|
||||
|
||||
static bool borderPixelsHaveSameColor(const Mat& image, uint8_t color) {
|
||||
for (int j = 0; j < image.cols; j++) {
|
||||
if (image.at<uint8_t>(0, j) != color || image.at<uint8_t>(image.rows-1, j) != color)
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < image.rows; i++) {
|
||||
if (image.at<uint8_t>(i, 0) != color || image.at<uint8_t>(i, image.cols-1) != color)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check Charuco detection
|
||||
*/
|
||||
@@ -771,17 +783,24 @@ TEST_P(CharucoBoard, testWrongSizeDetection)
|
||||
ASSERT_TRUE(detectedCharucoIds.empty());
|
||||
}
|
||||
|
||||
TEST(CharucoBoardGenerate, issue_24806)
|
||||
|
||||
typedef testing::TestWithParam<std::tuple<cv::Size, float, cv::Size, int>> CharucoBoardGenerate;
|
||||
INSTANTIATE_TEST_CASE_P(/**/, CharucoBoardGenerate, testing::Values(make_tuple(Size(7, 4), 13.f, Size(400, 300), 24),
|
||||
make_tuple(Size(12, 2), 13.f, Size(200, 150), 1),
|
||||
make_tuple(Size(12, 2), 13.1f, Size(400, 300), 1)));
|
||||
TEST_P(CharucoBoardGenerate, issue_24806)
|
||||
{
|
||||
aruco::Dictionary dict = aruco::getPredefinedDictionary(aruco::DICT_4X4_1000);
|
||||
const float squareLength = 13.f, markerLength = 10.f;
|
||||
const Size boardSize(7ull, 4ull);
|
||||
auto params = GetParam();
|
||||
const Size boardSize = std::get<0>(params);
|
||||
const float squareLength = std::get<1>(params), markerLength = 10.f;
|
||||
Size imgSize = std::get<2>(params);
|
||||
const aruco::CharucoBoard board(boardSize, squareLength, markerLength, dict);
|
||||
const int marginSize = 24;
|
||||
const int marginSize = std::get<3>(params);
|
||||
Mat boardImg;
|
||||
|
||||
// generate chessboard image
|
||||
board.generateImage(Size(400, 300), boardImg, marginSize);
|
||||
board.generateImage(imgSize, boardImg, marginSize);
|
||||
// This condition checks that the width of the image determines the dimensions of the chessboard in this test
|
||||
CV_Assert((float)(boardImg.cols) / (float)boardSize.width <=
|
||||
(float)(boardImg.rows) / (float)boardSize.height);
|
||||
@@ -819,7 +838,54 @@ TEST(CharucoBoardGenerate, issue_24806)
|
||||
bool eq = (cv::countNonZero(goldCorner1 != winCorner) == 0) || (cv::countNonZero(goldCorner2 != winCorner) == 0);
|
||||
ASSERT_TRUE(eq);
|
||||
}
|
||||
// TODO: fix aruco generateImage and add test aruco corners for generated image
|
||||
|
||||
// marker size in pixels
|
||||
const float pixInMarker = markerLength/squareLength*pixInSquare;
|
||||
// the size of the marker margin in pixels
|
||||
const float pixInMarginMarker = 0.5f*(pixInSquare - pixInMarker);
|
||||
|
||||
// determine the zone where the aruco markers are located
|
||||
int endArucoX = cvRound(pixInSquare*(boardSize.width-1)+pixInMarginMarker+pixInMarker);
|
||||
int endArucoY = cvRound(pixInSquare*(boardSize.height-1)+pixInMarginMarker+pixInMarker);
|
||||
Mat arucoZone = chessboardZoneImg(Range(cvRound(pixInMarginMarker), endArucoY), Range(cvRound(pixInMarginMarker), endArucoX));
|
||||
|
||||
const auto& markerCorners = board.getObjPoints();
|
||||
float minX, maxX, minY, maxY;
|
||||
minX = maxX = markerCorners[0][0].x;
|
||||
minY = maxY = markerCorners[0][0].y;
|
||||
for (const auto& marker : markerCorners) {
|
||||
for (const Point3f& objCorner : marker) {
|
||||
minX = min(minX, objCorner.x);
|
||||
maxX = max(maxX, objCorner.x);
|
||||
minY = min(minY, objCorner.y);
|
||||
maxY = max(maxY, objCorner.y);
|
||||
}
|
||||
}
|
||||
|
||||
Point2f outCorners[3];
|
||||
for (const auto& marker : markerCorners) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
outCorners[i] = Point2f(marker[i].x, marker[i].y) - Point2f(minX, minY);
|
||||
outCorners[i].x = outCorners[i].x / (maxX - minX) * float(arucoZone.cols);
|
||||
outCorners[i].y = outCorners[i].y / (maxY - minY) * float(arucoZone.rows);
|
||||
}
|
||||
Size dst_sz(outCorners[2] - outCorners[0]); // assuming CCW order
|
||||
dst_sz.width = dst_sz.height = std::min(dst_sz.width, dst_sz.height);
|
||||
Rect borderRect = Rect(outCorners[0], dst_sz);
|
||||
|
||||
//The test checks the inner and outer borders of the Aruco markers.
|
||||
//In the inner border of Aruco marker, all pixels should be black.
|
||||
//In the outer border of Aruco marker, all pixels should be white.
|
||||
|
||||
Mat markerImg = arucoZone(borderRect);
|
||||
bool markerBorderIsBlack = borderPixelsHaveSameColor(markerImg, 0);
|
||||
ASSERT_EQ(markerBorderIsBlack, true);
|
||||
|
||||
Mat markerOuterBorder = markerImg;
|
||||
markerOuterBorder.adjustROI(1, 1, 1, 1);
|
||||
bool markerOuterBorderIsWhite = borderPixelsHaveSameColor(markerOuterBorder, 255);
|
||||
ASSERT_EQ(markerOuterBorderIsWhite, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Temporary disabled in https://github.com/opencv/opencv/pull/24338
|
||||
@@ -870,12 +936,14 @@ TEST(Charuco, DISABLED_testSeveralBoardsWithCustomIds)
|
||||
detector2.detectBoard(gray, c_corners2, c_ids2, corners, ids);
|
||||
|
||||
ASSERT_EQ(ids.size(), size_t(16));
|
||||
ASSERT_EQ(c_corners1.rows, expected_corners.rows);
|
||||
EXPECT_NEAR(0, cvtest::norm(expected_corners, c_corners1.reshape(1), NORM_INF), 3e-1);
|
||||
// In 4.x detectBoard() returns the charuco corners in a 2D Mat with shape (N_corners, 1)
|
||||
// In 5.x, after PR #23473, detectBoard() returns the charuco corners in a 1D Mat with shape (1, N_corners)
|
||||
ASSERT_EQ(expected_corners.total(), c_corners1.total()*c_corners1.channels());
|
||||
EXPECT_NEAR(0., cvtest::norm(expected_corners.reshape(1, 1), c_corners1.reshape(1, 1), NORM_INF), 3e-1);
|
||||
|
||||
ASSERT_EQ(c_corners2.rows, expected_corners.rows);
|
||||
ASSERT_EQ(expected_corners.total(), c_corners2.total()*c_corners2.channels());
|
||||
expected_corners.col(0) += 500;
|
||||
EXPECT_NEAR(0, cvtest::norm(expected_corners, c_corners2.reshape(1), NORM_INF), 3e-1);
|
||||
EXPECT_NEAR(0., cvtest::norm(expected_corners.reshape(1, 1), c_corners2.reshape(1, 1), NORM_INF), 3e-1);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
Reference in New Issue
Block a user