1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 15:23:05 +04:00

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2026-04-23 11:00:34 +03:00
38 changed files with 3437 additions and 293 deletions
@@ -235,34 +235,30 @@ Mat Dictionary::getBitsFromByteList(const Mat &byteList, int markerSize, int rot
CV_Assert(byteList.channels() >= 4);
CV_Assert(rotationId >= 0 && rotationId < 4);
Mat bits(markerSize, markerSize, CV_8UC1, Scalar::all(0));
unsigned char base2List[] = { 128, 64, 32, 16, 8, 4, 2, 1 };
Mat bits = Mat::zeros(markerSize, markerSize, CV_8UC1);
unsigned char *bitsPtr = bits.ptr();
// Use a base offset for the selected rotation
int nbytes = (bits.cols * bits.rows + 8 - 1) / 8; // integer ceil
int base = rotationId * nbytes;
int currentByteIdx = 0;
unsigned char currentByte = byteList.ptr()[base + currentByteIdx];
int currentBit = 0;
const unsigned char *currentBytePtr = byteList.ptr() + base;
const unsigned char *currentBytePtrEnd = currentBytePtr + bits.total() / 8;
for(int row = 0; row < bits.rows; row++) {
for(int col = 0; col < bits.cols; col++) {
if(currentByte >= base2List[currentBit]) {
bits.at<unsigned char>(row, col) = 1;
currentByte -= base2List[currentBit];
}
currentBit++;
if(currentBit == 8) {
currentByteIdx++;
currentByte = byteList.ptr()[base + currentByteIdx];
// if not enough bits for one more byte, we are in the end
// update bit position accordingly
if(8 * (currentByteIdx + 1) > (int)bits.total())
currentBit = 8 * (currentByteIdx + 1) - (int)bits.total();
else
currentBit = 0; // ok, bits enough for next byte
}
for(;currentBytePtr < currentBytePtrEnd; ++currentBytePtr) {
unsigned char currentByte = *currentBytePtr;
for(int mask = 1 << 7; mask != 0; mask >>= 1) {
if (currentByte & mask) *bitsPtr = 1;
++bitsPtr;
}
}
// if not enough bits for one more byte, we are in the end
// update bit position accordingly
if (bits.total() % 8 != 0) {
unsigned char currentByte = *currentBytePtrEnd;
int mask = 1 << ((bits.total() % 8) - 1);
for(; mask != 0; mask >>= 1) {
if (currentByte & mask) *bitsPtr = 1;
++bitsPtr;
}
}
return bits;
@@ -414,7 +414,12 @@ void CharucoDetector::detectDiamonds(InputArray image, OutputArrayOfArrays _diam
// stores if the detected markers have been assigned or not to a diamond
vector<bool> assigned(_markerIds.total(), false);
if(_markerIds.total() < 4ull) return; // a diamond need at least 4 markers
if(_markerIds.total() < 4ull)
{
if (_diamondCorners.needed()) _diamondCorners.release();
if (_diamondIds.needed()) _diamondIds.release();
return; // a diamond need at least 4 markers
}
// convert input image to grey
Mat grey;
@@ -522,16 +527,27 @@ void CharucoDetector::detectDiamonds(InputArray image, OutputArrayOfArrays _diam
if(diamondIds.size() > 0ull) {
// parse output
Mat(diamondIds).copyTo(_diamondIds);
if (_diamondIds.needed())
{
Mat(diamondIds).copyTo(_diamondIds);
}
_diamondCorners.create((int)diamondCorners.size(), 1, CV_32FC2);
for(unsigned int i = 0; i < diamondCorners.size(); i++) {
_diamondCorners.create(4, 1, CV_32FC2, i, true);
for(int j = 0; j < 4; j++) {
_diamondCorners.getMat(i).at<Point2f>(j) = diamondCorners[i][j];
if (_diamondCorners.needed())
{
_diamondCorners.create((int)diamondCorners.size(), 1, CV_32FC2);
for(unsigned int i = 0; i < diamondCorners.size(); i++) {
_diamondCorners.create(4, 1, CV_32FC2, i, true);
for(int j = 0; j < 4; j++) {
_diamondCorners.getMat(i).at<Point2f>(j) = diamondCorners[i][j];
}
}
}
}
else
{
if (_diamondCorners.needed()) _diamondCorners.release();
if (_diamondIds.needed()) _diamondIds.release();
}
}
void drawDetectedCornersCharuco(InputOutputArray _image, InputArray _charucoCorners,
@@ -705,6 +705,27 @@ TEST(Charuco, testmatchImagePoints)
}
}
TEST(Charuco, detectDiamondsClearsOutputsWithLessThanFourMarkers)
{
aruco::CharucoBoard board(Size(3, 3), 1.f, 0.5f, aruco::getPredefinedDictionary(aruco::DICT_4X4_50));
aruco::CharucoDetector detector(board);
vector<vector<Point2f>> markerCorners = {
{Point2f(10.f, 10.f), Point2f(20.f, 10.f), Point2f(20.f, 20.f), Point2f(10.f, 20.f)},
{Point2f(30.f, 10.f), Point2f(40.f, 10.f), Point2f(40.f, 20.f), Point2f(30.f, 20.f)},
{Point2f(10.f, 30.f), Point2f(20.f, 30.f), Point2f(20.f, 40.f), Point2f(10.f, 40.f)}
};
vector<int> markerIds = {0, 1, 2};
vector<vector<Point2f>> diamondCorners = {{Point2f(1.f, 1.f), Point2f(2.f, 1.f), Point2f(2.f, 2.f), Point2f(1.f, 2.f)}};
vector<Vec4i> diamondIds = {Vec4i(0, 1, 2, 3)};
detector.detectDiamonds(Mat(), diamondCorners, diamondIds, markerCorners, markerIds);
EXPECT_TRUE(diamondCorners.empty());
EXPECT_TRUE(diamondIds.empty());
}
typedef testing::TestWithParam<int> CharucoDraw;
INSTANTIATE_TEST_CASE_P(/**/, CharucoDraw, testing::Values(CV_8UC2, CV_8SC2, CV_16UC2, CV_16SC2, CV_32SC2, CV_32FC2, CV_64FC2));
TEST_P(CharucoDraw, testDrawDetected) {