Skip to content

Commit 230b6c9

Browse files
author
AleksandrPanov
committed
add set/get/dictionary/objPoints, update tests
1 parent 1f003fe commit 230b6c9

11 files changed

+200
-121
lines changed

modules/aruco/include/opencv2/aruco/board.hpp

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,36 @@ class CV_EXPORTS_W Board {
4444
*/
4545
CV_WRAP void setIds(InputArray ids);
4646

47+
/** @brief change id for ids[index]
48+
* @param index - element index in ids
49+
* @param newId - new value for ids[index], should be less than Dictionary size
50+
*/
51+
CV_WRAP void changeId(int index, int newId);
52+
/** @brief return ids
53+
*/
54+
CV_WRAP const std::vector<int>& getIds() const;
55+
56+
/** @brief set dictionary
57+
*/
58+
CV_WRAP void setDictionary(const Ptr<Dictionary> &dictionary);
59+
60+
/** @brief return dictionary
61+
*/
62+
CV_WRAP Ptr<Dictionary> getDictionary() const;
63+
64+
/** @brief set objPoints
65+
*/
66+
CV_WRAP void setObjPoints(const std::vector<std::vector<Point3f> > &objPoints);
67+
68+
/** @brief get objPoints
69+
*/
70+
CV_WRAP const std::vector<std::vector<Point3f> >& getObjPoints() const;
71+
72+
/** @brief get rightBottomBorder
73+
*/
74+
CV_WRAP const Point3f& getRightBottomBorder() const;
75+
76+
protected:
4777
/** @brief array of object points of all the marker corners in the board each marker include its 4 corners in this order:
4878
* - objPoints[i][0] - left-top point of i-th marker
4979
* - objPoints[i][1] - right-top point of i-th marker
@@ -58,13 +88,13 @@ class CV_EXPORTS_W Board {
5888
/// the dictionary of markers employed for this board
5989
CV_PROP Ptr<Dictionary> dictionary;
6090

91+
/// coordinate of the bottom right corner of the board, is set when calling the function create()
92+
CV_PROP Point3f rightBottomBorder;
93+
6194
/** @brief vector of the identifiers of the markers in the board (same size than objPoints)
6295
* The identifiers refers to the board dictionary
6396
*/
6497
CV_PROP_RW std::vector<int> ids;
65-
66-
/// coordinate of the bottom right corner of the board, is set when calling the function create()
67-
CV_PROP Point3f rightBottomBorder;
6898
};
6999

70100
/**
@@ -196,7 +226,7 @@ class CV_EXPORTS_W CharucoBoard : public Board {
196226
* @param board layout of ChArUco board.
197227
* @param charucoIds list of identifiers for each corner in charucoCorners per frame.
198228
* @return bool value, 1 (true) if detected corners form a line, 0 (false) if they do not.
199-
solvePnP, calibration functions will fail if the corners are collinear (true).
229+
* solvePnP, calibration functions will fail if the corners are collinear (true).
200230
*
201231
* The number of ids in charucoIDs should be <= the number of chessboard corners in the board.
202232
* This functions checks whether the charuco corners are on a straight line (returns true, if so), or not (false).

modules/aruco/misc/python/test/test_aruco.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ def test_idsAccessibility(self):
1919
aruco_dict = cv.aruco.Dictionary_get(cv.aruco.DICT_5X5_250)
2020
board = cv.aruco.CharucoBoard_create(7, 5, 1, 0.5, aruco_dict)
2121

22-
np.testing.assert_array_equal(board.ids.squeeze(), ids)
22+
np.testing.assert_array_equal(board.getIds().squeeze(), ids)
2323

24-
board.ids = rev_ids
25-
np.testing.assert_array_equal(board.ids.squeeze(), rev_ids)
24+
board.setIds(rev_ids)
25+
np.testing.assert_array_equal(board.getIds().squeeze(), rev_ids)
2626

2727
board.setIds(ids)
28-
np.testing.assert_array_equal(board.ids.squeeze(), ids)
28+
np.testing.assert_array_equal(board.getIds().squeeze(), ids)
2929

3030
with self.assertRaises(cv.error):
3131
board.setIds(np.array([0]))

modules/aruco/samples/tutorial_charuco_create_detect.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ static inline void detectCharucoBoardWithCalibrationPose()
5050
//! [midcornerdet]
5151
std::vector<int> markerIds;
5252
std::vector<std::vector<cv::Point2f> > markerCorners;
53-
cv::aruco::detectMarkers(image, board->dictionary, markerCorners, markerIds, params);
53+
cv::aruco::detectMarkers(image, board->getDictionary(), markerCorners, markerIds, params);
5454
//! [midcornerdet]
5555
// if at least one marker detected
5656
if (markerIds.size() > 0) {
@@ -100,7 +100,7 @@ static inline void detectCharucoBoardWithoutCalibration()
100100
image.copyTo(imageCopy);
101101
std::vector<int> markerIds;
102102
std::vector<std::vector<cv::Point2f> > markerCorners;
103-
cv::aruco::detectMarkers(image, board->dictionary, markerCorners, markerIds, params);
103+
cv::aruco::detectMarkers(image, board->getDictionary(), markerCorners, markerIds, params);
104104
//or
105105
//cv::aruco::detectMarkers(image, dictionary, markerCorners, markerIds, params);
106106
// if at least one marker detected

modules/aruco/src/aruco.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ void refineDetectedMarkers(InputArray _image, const Ptr<Board> &_board,
2323
bool checkAllOrders, OutputArray _recoveredIdxs,
2424
const Ptr<DetectorParameters> &_params) {
2525
Ptr<RefineParameters> refineParams = RefineParameters::create(minRepDistance, errorCorrectionRate, checkAllOrders);
26-
ArucoDetector detector(_board->dictionary, _params, refineParams);
26+
ArucoDetector detector(_board->getDictionary(), _params, refineParams);
2727
detector.refineDetectedMarkers(_image, _board, _detectedCorners, _detectedIds, _rejectedCorners, _cameraMatrix,
2828
_distCoeffs, _recoveredIdxs);
2929
}

modules/aruco/src/aruco_calib_pose.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ using namespace std;
1010

1111
void getBoardObjectAndImagePoints(const Ptr<Board> &board, InputArrayOfArrays detectedCorners, InputArray detectedIds,
1212
OutputArray objPoints, OutputArray imgPoints) {
13-
CV_Assert(board->ids.size() == board->objPoints.size());
13+
CV_Assert(board->getIds().size() == board->getObjPoints().size());
1414
CV_Assert(detectedIds.total() == detectedCorners.total());
1515

1616
size_t nDetectedMarkers = detectedIds.total();
@@ -24,10 +24,10 @@ void getBoardObjectAndImagePoints(const Ptr<Board> &board, InputArrayOfArrays de
2424
// look for detected markers that belong to the board and get their information
2525
for(unsigned int i = 0; i < nDetectedMarkers; i++) {
2626
int currentId = detectedIds.getMat().ptr< int >(0)[i];
27-
for(unsigned int j = 0; j < board->ids.size(); j++) {
28-
if(currentId == board->ids[j]) {
27+
for(unsigned int j = 0; j < board->getIds().size(); j++) {
28+
if(currentId == board->getIds()[j]) {
2929
for(int p = 0; p < 4; p++) {
30-
objPnts.push_back(board->objPoints[j][p]);
30+
objPnts.push_back(board->getObjPoints()[j][p]);
3131
imgPnts.push_back(detectedCorners.getMat(i).ptr< Point2f >(0)[p]);
3232
}
3333
}

modules/aruco/src/aruco_detector.cpp

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -965,10 +965,10 @@ static void _projectUndetectedMarkers(const Ptr<Board> &_board, InputOutputArray
965965
// search undetected markers and project them using the previous pose
966966
vector<vector<Point2f> > undetectedCorners;
967967
vector<int> undetectedIds;
968-
for(unsigned int i = 0; i < _board->ids.size(); i++) {
968+
for(unsigned int i = 0; i < _board->getIds().size(); i++) {
969969
int foundIdx = -1;
970970
for(unsigned int j = 0; j < _detectedIds.total(); j++) {
971-
if(_board->ids[i] == _detectedIds.getMat().ptr< int >()[j]) {
971+
if(_board->getIds()[i] == _detectedIds.getMat().ptr< int >()[j]) {
972972
foundIdx = j;
973973
break;
974974
}
@@ -977,8 +977,8 @@ static void _projectUndetectedMarkers(const Ptr<Board> &_board, InputOutputArray
977977
// not detected
978978
if(foundIdx == -1) {
979979
undetectedCorners.push_back(vector<Point2f >());
980-
undetectedIds.push_back(_board->ids[i]);
981-
projectPoints(_board->objPoints[i], rvec, tvec, _cameraMatrix, _distCoeffs,
980+
undetectedIds.push_back(_board->getIds()[i]);
981+
projectPoints(_board->getObjPoints()[i], rvec, tvec, _cameraMatrix, _distCoeffs,
982982
undetectedCorners.back());
983983
}
984984
}
@@ -996,12 +996,12 @@ static void _projectUndetectedMarkers(const Ptr<Board> &_board, InputOutputArray
996996
vector<vector<Point2f > >& _undetectedMarkersProjectedCorners,
997997
OutputArray _undetectedMarkersIds) {
998998
// check board points are in the same plane, if not, global homography cannot be applied
999-
CV_Assert(_board->objPoints.size() > 0);
1000-
CV_Assert(_board->objPoints[0].size() > 0);
1001-
float boardZ = _board->objPoints[0][0].z;
1002-
for(unsigned int i = 0; i < _board->objPoints.size(); i++) {
1003-
for(unsigned int j = 0; j < _board->objPoints[i].size(); j++)
1004-
CV_Assert(boardZ == _board->objPoints[i][j].z);
999+
CV_Assert(_board->getObjPoints().size() > 0);
1000+
CV_Assert(_board->getObjPoints()[0].size() > 0);
1001+
float boardZ = _board->getObjPoints()[0][0].z;
1002+
for(unsigned int i = 0; i < _board->getObjPoints().size(); i++) {
1003+
for(unsigned int j = 0; j < _board->getObjPoints()[i].size(); j++)
1004+
CV_Assert(boardZ == _board->getObjPoints()[i][j].z);
10051005
}
10061006

10071007
vector<Point2f> detectedMarkersObj2DAll; // Object coordinates (without Z) of all the detected
@@ -1011,14 +1011,14 @@ static void _projectUndetectedMarkers(const Ptr<Board> &_board, InputOutputArray
10111011
// missing markers in different vectors
10121012
vector<int> undetectedMarkersIds; // ids of missing markers
10131013
// find markers included in board, and missing markers from board. Fill the previous vectors
1014-
for(unsigned int j = 0; j < _board->ids.size(); j++) {
1014+
for(unsigned int j = 0; j < _board->getIds().size(); j++) {
10151015
bool found = false;
10161016
for(unsigned int i = 0; i < _detectedIds.total(); i++) {
1017-
if(_detectedIds.getMat().ptr< int >()[i] == _board->ids[j]) {
1017+
if(_detectedIds.getMat().ptr< int >()[i] == _board->getIds()[j]) {
10181018
for(int c = 0; c < 4; c++) {
10191019
imageCornersAll.push_back(_detectedCorners.getMat(i).ptr< Point2f >()[c]);
10201020
detectedMarkersObj2DAll.push_back(
1021-
Point2f(_board->objPoints[j][c].x, _board->objPoints[j][c].y));
1021+
Point2f(_board->getObjPoints()[j][c].x, _board->getObjPoints()[j][c].y));
10221022
}
10231023
found = true;
10241024
break;
@@ -1028,9 +1028,9 @@ static void _projectUndetectedMarkers(const Ptr<Board> &_board, InputOutputArray
10281028
undetectedMarkersObj2D.push_back(vector<Point2f >());
10291029
for(int c = 0; c < 4; c++) {
10301030
undetectedMarkersObj2D.back().push_back(
1031-
Point2f(_board->objPoints[j][c].x, _board->objPoints[j][c].y));
1031+
Point2f(_board->getObjPoints()[j][c].x, _board->getObjPoints()[j][c].y));
10321032
}
1033-
undetectedMarkersIds.push_back(_board->ids[j]);
1033+
undetectedMarkersIds.push_back(_board->getIds()[j]);
10341034
}
10351035
}
10361036
if(imageCornersAll.size() == 0) return;

modules/aruco/src/board.cpp

Lines changed: 64 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,17 @@ static void _drawPlanarBoardImpl(Board *_board, Size outSize, OutputArray _img,
2222
out.adjustROI(-marginSize, -marginSize, -marginSize, -marginSize);
2323

2424
// calculate max and min values in XY plane
25-
CV_Assert(_board->objPoints.size() > 0);
25+
CV_Assert(_board->getObjPoints().size() > 0);
2626
float minX, maxX, minY, maxY;
27-
minX = maxX = _board->objPoints[0][0].x;
28-
minY = maxY = _board->objPoints[0][0].y;
27+
minX = maxX = _board->getObjPoints()[0][0].x;
28+
minY = maxY = _board->getObjPoints()[0][0].y;
2929

30-
for(unsigned int i = 0; i < _board->objPoints.size(); i++) {
30+
for(unsigned int i = 0; i < _board->getObjPoints().size(); i++) {
3131
for(int j = 0; j < 4; j++) {
32-
minX = min(minX, _board->objPoints[i][j].x);
33-
maxX = max(maxX, _board->objPoints[i][j].x);
34-
minY = min(minY, _board->objPoints[i][j].y);
35-
maxY = max(maxY, _board->objPoints[i][j].y);
32+
minX = min(minX, _board->getObjPoints()[i][j].x);
33+
maxX = max(maxX, _board->getObjPoints()[i][j].x);
34+
minY = min(minY, _board->getObjPoints()[i][j].y);
35+
maxY = max(maxY, _board->getObjPoints()[i][j].y);
3636
}
3737
}
3838

@@ -55,14 +55,14 @@ static void _drawPlanarBoardImpl(Board *_board, Size outSize, OutputArray _img,
5555
}
5656

5757
// now paint each marker
58-
Dictionary &dictionary = *(_board->dictionary);
58+
Dictionary &dictionary = *(_board->getDictionary());
5959
Mat marker;
6060
Point2f outCorners[3];
6161
Point2f inCorners[3];
62-
for(unsigned int m = 0; m < _board->objPoints.size(); m++) {
62+
for(unsigned int m = 0; m < _board->getObjPoints().size(); m++) {
6363
// transform corners to markerZone coordinates
6464
for(int j = 0; j < 3; j++) {
65-
Point2f pf = Point2f(_board->objPoints[m][j].x, _board->objPoints[m][j].y);
65+
Point2f pf = Point2f(_board->getObjPoints()[m][j].x, _board->getObjPoints()[m][j].y);
6666
// move top left to 0, 0
6767
pf -= Point2f(minX, minY);
6868
pf.x = pf.x / sizeX * float(out.cols);
@@ -73,7 +73,7 @@ static void _drawPlanarBoardImpl(Board *_board, Size outSize, OutputArray _img,
7373
// get marker
7474
Size dst_sz(outCorners[2] - outCorners[0]); // assuming CCW order
7575
dst_sz.width = dst_sz.height = std::min(dst_sz.width, dst_sz.height); //marker should be square
76-
dictionary.drawMarker(_board->ids[m], dst_sz.width, marker, borderBits);
76+
dictionary.drawMarker(_board->getIds()[m], dst_sz.width, marker, borderBits);
7777

7878
if((outCorners[0].y == outCorners[1].y) && (outCorners[1].x == outCorners[2].x)) {
7979
// marker is aligned to image axes
@@ -150,6 +150,46 @@ void Board::setIds(InputArray ids_) {
150150
ids_.copyTo(this->ids);
151151
}
152152

153+
Ptr<Dictionary> Board::getDictionary() const {
154+
return this->dictionary;
155+
}
156+
157+
void Board::setDictionary(const Ptr<Dictionary> &_dictionary) {
158+
this->dictionary = _dictionary;
159+
}
160+
161+
const std::vector<std::vector<Point3f> >& Board::getObjPoints() const {
162+
return this->objPoints;
163+
}
164+
165+
void Board::setObjPoints(const vector<std::vector<Point3f>> &_objPoints) {
166+
CV_Assert(!_objPoints.empty());
167+
this->objPoints = _objPoints;
168+
rightBottomBorder = _objPoints.front().front();
169+
for (size_t i = 0; i < this->objPoints.size(); i++) {
170+
for (int j = 0; j < 4; j++) {
171+
const Point3f &corner = this->objPoints[i][j];
172+
rightBottomBorder.x = std::max(rightBottomBorder.x, corner.x);
173+
rightBottomBorder.y = std::max(rightBottomBorder.y, corner.y);
174+
rightBottomBorder.z = std::max(rightBottomBorder.z, corner.z);
175+
}
176+
}
177+
}
178+
179+
const Point3f& Board::getRightBottomBorder() const {
180+
return this->rightBottomBorder;
181+
}
182+
183+
const std::vector<int>& Board::getIds() const {
184+
return this->ids;
185+
}
186+
187+
void Board::changeId(int index, int newId) {
188+
CV_Assert(index >= 0 && index < (int)ids.size());
189+
CV_Assert(newId >= 0 && newId < dictionary->bytesList.rows);
190+
this->ids[index] = newId;
191+
}
192+
153193
Ptr<GridBoard> GridBoard::create(int markersX, int markersY, float markerLength, float markerSeparation,
154194
const Ptr<Dictionary> &dictionary, int firstMarker) {
155195
CV_Assert(markersX > 0 && markersY > 0 && markerLength > 0 && markerSeparation > 0);
@@ -158,11 +198,12 @@ Ptr<GridBoard> GridBoard::create(int markersX, int markersY, float markerLength,
158198
res->gridImpl->sizeY = markersY;
159199
res->gridImpl->markerLength = markerLength;
160200
res->gridImpl->markerSeparation = markerSeparation;
161-
res->dictionary = dictionary;
201+
res->setDictionary(dictionary);
162202

163203
size_t totalMarkers = (size_t) markersX * markersY;
164204
res->ids.resize(totalMarkers);
165-
res->objPoints.reserve(totalMarkers);
205+
std::vector<std::vector<Point3f> > objPoints;
206+
objPoints.reserve(totalMarkers);
166207

167208
// fill ids with first identifiers
168209
for (unsigned int i = 0; i < totalMarkers; i++) {
@@ -178,9 +219,10 @@ Ptr<GridBoard> GridBoard::create(int markersX, int markersY, float markerLength,
178219
corners[1] = corners[0] + Point3f(markerLength, 0, 0);
179220
corners[2] = corners[0] + Point3f(markerLength, markerLength, 0);
180221
corners[3] = corners[0] + Point3f(0, markerLength, 0);
181-
res->objPoints.push_back(corners);
222+
objPoints.push_back(corners);
182223
}
183224
}
225+
res->setObjPoints(objPoints);
184226
res->rightBottomBorder = Point3f(markersX * markerLength + markerSeparation * (markersX - 1),
185227
markersY * markerLength + markerSeparation * (markersY - 1), 0.f);
186228
return res;
@@ -281,7 +323,7 @@ static inline void _getNearestMarkerCorners(CharucoBoard &board, float squareLen
281323
board.nearestMarkerIdx.resize(board.chessboardCorners.size());
282324
board.nearestMarkerCorners.resize(board.chessboardCorners.size());
283325

284-
unsigned int nMarkers = (unsigned int)board.ids.size();
326+
unsigned int nMarkers = (unsigned int)board.getIds().size();
285327
unsigned int nCharucoCorners = (unsigned int)board.chessboardCorners.size();
286328
for(unsigned int i = 0; i < nCharucoCorners; i++) {
287329
double minDist = -1; // distance of closest markers
@@ -290,7 +332,7 @@ static inline void _getNearestMarkerCorners(CharucoBoard &board, float squareLen
290332
// calculate distance from marker center to charuco corner
291333
Point3f center = Point3f(0, 0, 0);
292334
for(unsigned int k = 0; k < 4; k++)
293-
center += board.objPoints[j][k];
335+
center += board.getObjPoints()[j][k];
294336
center /= 4.;
295337
double sqDistance;
296338
Point3f distVector = charucoCorner - center;
@@ -313,7 +355,7 @@ static inline void _getNearestMarkerCorners(CharucoBoard &board, float squareLen
313355
double minDistCorner = -1;
314356
for(unsigned int k = 0; k < 4; k++) {
315357
double sqDistance;
316-
Point3f distVector = charucoCorner - board.objPoints[board.nearestMarkerIdx[i][j]][k];
358+
Point3f distVector = charucoCorner - board.getObjPoints()[board.nearestMarkerIdx[i][j]][k];
317359
sqDistance = distVector.x * distVector.x + distVector.y * distVector.y;
318360
if(k == 0 || sqDistance < minDistCorner) {
319361
// if this corner is closer to the charuco corner, assing its index
@@ -335,7 +377,8 @@ Ptr<CharucoBoard> CharucoBoard::create(int squaresX, int squaresY, float squareL
335377
res->charucoImpl->sizeY = squaresY;
336378
res->charucoImpl->squareLength = squareLength;
337379
res->charucoImpl->markerLength = markerLength;
338-
res->dictionary = dictionary;
380+
res->setDictionary(dictionary);
381+
std::vector<std::vector<Point3f> > objPoints;
339382

340383
float diffSquareMarkerLength = (squareLength - markerLength) / 2;
341384
// calculate Board objPoints
@@ -350,12 +393,13 @@ Ptr<CharucoBoard> CharucoBoard::create(int squaresX, int squaresY, float squareL
350393
corners[1] = corners[0] + Point3f(markerLength, 0, 0);
351394
corners[2] = corners[0] + Point3f(markerLength, markerLength, 0);
352395
corners[3] = corners[0] + Point3f(0, markerLength, 0);
353-
res->objPoints.push_back(corners);
396+
objPoints.push_back(corners);
354397
// first ids in dictionary
355398
int nextId = (int)res->ids.size();
356399
res->ids.push_back(nextId);
357400
}
358401
}
402+
res->setObjPoints(objPoints);
359403

360404
// now fill chessboardCorners
361405
for(int y = 0; y < squaresY - 1; y++) {

0 commit comments

Comments
 (0)