Skip to content

Commit 0c6b04a

Browse files
authored
Merge pull request #3396 from stopmosk:fix-aruco-tutorials
Fix aruco tutorials
2 parents f15e587 + 83cb56d commit 0c6b04a

File tree

5 files changed

+211
-209
lines changed

5 files changed

+211
-209
lines changed

modules/aruco/include/opencv2/aruco.hpp

Lines changed: 2 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -41,34 +41,7 @@ CV_EXPORTS_W void getBoardObjectAndImagePoints(const Ptr<Board> &board, InputArr
4141
InputArray detectedIds, OutputArray objPoints, OutputArray imgPoints);
4242

4343

44-
/**
45-
* @brief Pose estimation for a board of markers
46-
*
47-
* @param corners vector of already detected markers corners. For each marker, its four corners
48-
* are provided, (e.g std::vector<std::vector<cv::Point2f> > ). For N detected markers, the
49-
* dimensions of this array should be Nx4. The order of the corners should be clockwise.
50-
* @param ids list of identifiers for each marker in corners
51-
* @param board layout of markers in the board. The layout is composed by the marker identifiers
52-
* and the positions of each marker corner in the board reference system.
53-
* @param cameraMatrix input 3x3 floating-point camera matrix
54-
* \f$A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$
55-
* @param distCoeffs vector of distortion coefficients
56-
* \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f$ of 4, 5, 8 or 12 elements
57-
* @param rvec Output vector (e.g. cv::Mat) corresponding to the rotation vector of the board
58-
* (see cv::Rodrigues). Used as initial guess if not empty.
59-
* @param tvec Output vector (e.g. cv::Mat) corresponding to the translation vector of the board.
60-
* @param useExtrinsicGuess defines whether initial guess for \b rvec and \b tvec will be used or not.
61-
* Used as initial guess if not empty.
62-
*
63-
* This function receives the detected markers and returns the pose of a marker board composed
64-
* by those markers.
65-
* A Board of marker has a single world coordinate system which is defined by the board layout.
66-
* The returned transformation is the one that transforms points from the board coordinate system
67-
* to the camera coordinate system.
68-
* Input markers that are not included in the board layout are ignored.
69-
* The function returns the number of markers from the input employed for the board pose estimation.
70-
* Note that returning a 0 means the pose has not been estimated.
71-
* @sa use cv::drawFrameAxes to get world coordinate system axis for object points
44+
/** @deprecated Use cv::solvePnP
7245
*/
7346
CV_EXPORTS_W int estimatePoseBoard(InputArrayOfArrays corners, InputArray ids, const Ptr<Board> &board,
7447
InputArray cameraMatrix, InputArray distCoeffs, InputOutputArray rvec,
@@ -98,41 +71,7 @@ CV_EXPORTS_W bool estimatePoseCharucoBoard(InputArray charucoCorners, InputArray
9871
InputArray distCoeffs, InputOutputArray rvec,
9972
InputOutputArray tvec, bool useExtrinsicGuess = false);
10073

101-
/**
102-
* @brief Pose estimation for single markers
103-
*
104-
* @param corners vector of already detected markers corners. For each marker, its four corners
105-
* are provided, (e.g std::vector<std::vector<cv::Point2f> > ). For N detected markers,
106-
* the dimensions of this array should be Nx4. The order of the corners should be clockwise.
107-
* @sa detectMarkers
108-
* @param markerLength the length of the markers' side. The returning translation vectors will
109-
* be in the same unit. Normally, unit is meters.
110-
* @param cameraMatrix input 3x3 floating-point camera matrix
111-
* \f$A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$
112-
* @param distCoeffs vector of distortion coefficients
113-
* \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f$ of 4, 5, 8 or 12 elements
114-
* @param rvecs array of output rotation vectors (@sa Rodrigues) (e.g. std::vector<cv::Vec3d>).
115-
* Each element in rvecs corresponds to the specific marker in imgPoints.
116-
* @param tvecs array of output translation vectors (e.g. std::vector<cv::Vec3d>).
117-
* Each element in tvecs corresponds to the specific marker in imgPoints.
118-
* @param objPoints array of object points of all the marker corners
119-
* @param estimateParameters set the origin of coordinate system and the coordinates of the four corners of the marker
120-
* (default estimateParameters.pattern = PatternPositionType::ARUCO_CCW_CENTER, estimateParameters.useExtrinsicGuess = false,
121-
* estimateParameters.solvePnPMethod = SOLVEPNP_ITERATIVE).
122-
*
123-
* This function receives the detected markers and returns their pose estimation respect to
124-
* the camera individually. So for each marker, one rotation and translation vector is returned.
125-
* The returned transformation is the one that transforms points from each marker coordinate system
126-
* to the camera coordinate system.
127-
* The marker coordinate system is centered on the middle (by default) or on the top-left corner of the marker,
128-
* with the Z axis perpendicular to the marker plane.
129-
* estimateParameters defines the coordinates of the four corners of the marker in its own coordinate system (by default) are:
130-
* (-markerLength/2, markerLength/2, 0), (markerLength/2, markerLength/2, 0),
131-
* (markerLength/2, -markerLength/2, 0), (-markerLength/2, -markerLength/2, 0)
132-
* @sa use cv::drawFrameAxes to get world coordinate system axis for object points
133-
* @sa @ref tutorial_aruco_detection
134-
* @sa EstimateParameters
135-
* @sa PatternPositionType
74+
/** @deprecated Use cv::solvePnP
13675
*/
13776
CV_EXPORTS_W void estimatePoseSingleMarkers(InputArrayOfArrays corners, float markerLength,
13877
InputArray cameraMatrix, InputArray distCoeffs,

modules/aruco/samples/detect_board.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,16 @@ int main(int argc, char *argv[]) {
177177

178178
// estimate board pose
179179
int markersOfBoardDetected = 0;
180-
if(ids.size() > 0)
181-
markersOfBoardDetected = estimatePoseBoard(corners, ids, board, camMatrix, distCoeffs, rvec, tvec);
180+
if(!ids.empty()) {
181+
// Get object and image points for the solvePnP function
182+
cv::Mat objPoints, imgPoints;
183+
board->matchImagePoints(corners, ids, objPoints, imgPoints);
184+
185+
// Find pose
186+
cv::solvePnP(objPoints, imgPoints, camMatrix, distCoeffs, rvec, tvec);
187+
188+
markersOfBoardDetected = (int)objPoints.total() / 4;
189+
}
182190

183191
double currentTime = ((double)getTickCount() - tick) / getTickFrequency();
184192
totalTime += currentTime;
@@ -190,11 +198,11 @@ int main(int argc, char *argv[]) {
190198

191199
// draw results
192200
image.copyTo(imageCopy);
193-
if(ids.size() > 0) {
201+
if(!ids.empty()) {
194202
aruco::drawDetectedMarkers(imageCopy, corners, ids);
195203
}
196204

197-
if(showRejected && rejected.size() > 0)
205+
if(showRejected && !rejected.empty())
198206
aruco::drawDetectedMarkers(imageCopy, rejected, noArray(), Scalar(100, 0, 255));
199207

200208
if(markersOfBoardDetected > 0)

modules/aruco/samples/detect_markers.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,13 @@ int main(int argc, char *argv[]) {
148148
double totalTime = 0;
149149
int totalIterations = 0;
150150

151+
// Set coordinate system
152+
cv::Mat objPoints(4, 1, CV_32FC3);
153+
objPoints.ptr<Vec3f>(0)[0] = Vec3f(-markerLength/2.f, markerLength/2.f, 0);
154+
objPoints.ptr<Vec3f>(0)[1] = Vec3f(markerLength/2.f, markerLength/2.f, 0);
155+
objPoints.ptr<Vec3f>(0)[2] = Vec3f(markerLength/2.f, -markerLength/2.f, 0);
156+
objPoints.ptr<Vec3f>(0)[3] = Vec3f(-markerLength/2.f, -markerLength/2.f, 0);
157+
151158
while(inputVideo.grab()) {
152159
Mat image, imageCopy;
153160
inputVideo.retrieve(image);
@@ -156,13 +163,19 @@ int main(int argc, char *argv[]) {
156163

157164
vector< int > ids;
158165
vector< vector< Point2f > > corners, rejected;
159-
vector< Vec3d > rvecs, tvecs;
160166

161167
// detect markers and estimate pose
162168
detector.detectMarkers(image, corners, ids, rejected);
163-
if(estimatePose && ids.size() > 0)
164-
aruco::estimatePoseSingleMarkers(corners, markerLength, camMatrix, distCoeffs, rvecs,
165-
tvecs);
169+
170+
size_t nMarkers = corners.size();
171+
vector<Vec3d> rvecs(nMarkers), tvecs(nMarkers);
172+
173+
if(estimatePose && !ids.empty()) {
174+
// Calculate pose for each marker
175+
for (size_t i = 0; i < nMarkers; i++) {
176+
solvePnP(objPoints, corners.at(i), camMatrix, distCoeffs, rvecs.at(i), tvecs.at(i));
177+
}
178+
}
166179

167180
double currentTime = ((double)getTickCount() - tick) / getTickFrequency();
168181
totalTime += currentTime;
@@ -174,7 +187,7 @@ int main(int argc, char *argv[]) {
174187

175188
// draw results
176189
image.copyTo(imageCopy);
177-
if(ids.size() > 0) {
190+
if(!ids.empty()) {
178191
aruco::drawDetectedMarkers(imageCopy, corners, ids);
179192

180193
if(estimatePose) {
@@ -183,7 +196,7 @@ int main(int argc, char *argv[]) {
183196
}
184197
}
185198

186-
if(showRejected && rejected.size() > 0)
199+
if(showRejected && !rejected.empty())
187200
aruco::drawDetectedMarkers(imageCopy, rejected, noArray(), Scalar(100, 0, 255));
188201

189202
imshow("out", imageCopy);

modules/aruco/tutorials/aruco_board_detection/aruco_board_detection.markdown

Lines changed: 68 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -27,61 +27,57 @@ Thus, the pose can be calculated even in the presence of occlusions or partial v
2727
- The obtained pose is usually more accurate since a higher amount of point correspondences (marker
2828
corners) are employed.
2929

30-
The aruco module allows the use of Boards. The main class is the ```cv::aruco::Board``` class which defines the Board layout:
31-
32-
@code{.cpp}
33-
class Board {
34-
public:
35-
std::vector<std::vector<cv::Point3f> > objPoints;
36-
cv::Ptr<cv::aruco::Dictionary> dictionary;
37-
std::vector<int> ids;
38-
};
39-
@endcode
40-
41-
A object of type ```Board``` has three parameters:
42-
- The ```objPoints``` structure is the list of corner positions in the 3d Board reference system, i.e. its layout.
43-
For each marker, its four corners are stored in the standard order, i.e. in clockwise order and starting
44-
with the top left corner.
45-
- The ```dictionary``` parameter indicates to which marker dictionary the Board markers belong to.
46-
- Finally, the ```ids``` structure indicates the identifiers of each of the markers in ```objPoints``` respect to the specified ```dictionary```.
47-
48-
4930
Board Detection
5031
-----
5132

5233
A Board detection is similar to the standard marker detection. The only difference is in the pose estimation step.
5334
In fact, to use marker boards, a standard marker detection should be done before estimating the Board pose.
5435

55-
The aruco module provides a specific function, ```estimatePoseBoard()```, to perform pose estimation for boards:
36+
To perform pose estimation for boards, you should use ```#cv::solvePnP``` function, as shown below:
5637

5738
@code{.cpp}
58-
cv::Mat inputImage;
59-
// camera parameters are read from somewhere
60-
cv::Mat cameraMatrix, distCoeffs;
61-
// You can read camera parameters from tutorial_camera_params.yml
62-
readCameraParameters(filename, cameraMatrix, distCoeffs); // This function is located in detect_board.cpp
63-
// assume we have a function to create the board object
64-
cv::Ptr<cv::aruco::Board> board = cv::aruco::Board::create();
65-
...
66-
std::vector<int> markerIds;
67-
std::vector<std::vector<cv::Point2f>> markerCorners;
68-
cv::aruco::detectMarkers(inputImage, board.dictionary, markerCorners, markerIds);
69-
// if at least one marker detected
70-
if(markerIds.size() > 0) {
71-
cv::Vec3d rvec, tvec;
72-
int valid = cv::aruco::estimatePoseBoard(markerCorners, markerIds, board, cameraMatrix, distCoeffs, rvec, tvec);
73-
}
39+
cv::Mat inputImage;
40+
41+
// Camera parameters are read from somewhere
42+
cv::Mat cameraMatrix, distCoeffs;
43+
44+
// You can read camera parameters from tutorial_camera_params.yml
45+
readCameraParameters(filename, cameraMatrix, distCoeffs); // This function is implemented in aruco_samples_utility.hpp
46+
47+
// Assume we have a function to create the board object
48+
cv::Ptr<cv::aruco::Board> board = cv::aruco::Board::create();
49+
50+
...
51+
52+
std::vector<int> markerIds;
53+
std::vector<std::vector<cv::Point2f>> markerCorners;
54+
55+
cv::aruco::DetectorParameters detectorParams = cv::aruco::DetectorParameters();
56+
cv::aruco::ArucoDetector detector(board.dictionary, detectorParams);
57+
58+
detector.detectMarkers(inputImage, markerCorners, markerIds);
59+
60+
cv::Vec3d rvec, tvec;
61+
62+
// If at least one marker detected
63+
if(markerIds.size() > 0) {
64+
// Get object and image points for the solvePnP function
65+
cv::Mat objPoints, imgPoints;
66+
board->matchImagePoints(markerCorners, markerIds, objPoints, imgPoints);
67+
68+
// Find pose
69+
cv::solvePnP(objPoints, imgPoints, cameraMatrix, distCoeffs, rvec, tvec);
70+
}
71+
7472
@endcode
7573

76-
The parameters of estimatePoseBoard are:
74+
The parameters are:
7775

78-
- ```markerCorners``` and ```markerIds```: structures of detected markers from ```detectMarkers()``` function.
76+
- ```objPoints```, ```imgPoints```: object and image points, matched with ```matchImagePoints```, which, in turn, takes as input ```markerCorners``` and ```markerIds```: structures of detected markers from ```detectMarkers()``` function).
7977
- ```board```: the ```Board``` object that defines the board layout and its ids
8078
- ```cameraMatrix``` and ```distCoeffs```: camera calibration parameters necessary for pose estimation.
8179
- ```rvec``` and ```tvec```: estimated pose of the Board. If not empty then treated as initial guess.
82-
- The function returns the total number of markers employed for estimating the board pose. Note that not all the
83-
markers provided in ```markerCorners``` and ```markerIds``` should be used, since only the markers whose ids are
84-
listed in the ```Board::ids``` structure are considered.
80+
- The function returns the total number of markers employed for estimating the board pose.
8581

8682
The ```drawFrameAxes()``` function can be used to check the obtained pose. For instance:
8783

@@ -135,16 +131,15 @@ in any unit, having in mind that the estimated pose for this board will be measu
135131
- Finally, the dictionary of the markers is provided.
136132

137133
So, this board will be composed by 5x7=35 markers. The ids of each of the markers are assigned, by default, in ascending
138-
order starting on 0, so they will be 0, 1, 2, ..., 34. This can be easily customized by accessing to the ids vector
139-
through ```board.ids```, like in the ```Board``` parent class.
134+
order starting on 0, so they will be 0, 1, 2, ..., 34.
140135

141136
After creating a Grid Board, we probably want to print it and use it. A function to generate the image
142137
of a ```GridBoard``` is provided in ```cv::aruco::GridBoard::generateImage()```. For example:
143138

144139
@code{.cpp}
145140
cv::Ptr<cv::aruco::GridBoard> board = cv::aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary);
146141
cv::Mat boardImage;
147-
board->draw( cv::Size(600, 500), boardImage, 10, 1 );
142+
board->generateImage( cv::Size(600, 500), boardImage, 10, 1 );
148143
@endcode
149144

150145
- The first parameter is the size of the output image in pixels. In this case 600x500 pixels. If this is not proportional
@@ -173,31 +168,44 @@ Finally, a full example of board detection:
173168

174169
cv::Mat cameraMatrix, distCoeffs;
175170
// You can read camera parameters from tutorial_camera_params.yml
176-
readCameraParameters(filename, cameraMatrix, distCoeffs); // This function is located in detect_board.cpp
171+
readCameraParameters(filename, cameraMatrix, distCoeffs); // This function is implemented in aruco_samples_utility.hpp
177172

178-
cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
179-
// To use tutorial sample, you need read custome dictionaty from tutorial_dict.yml
180-
readDictionary(filename, dictionary); // This function is located in detect_board.cpp
173+
cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
174+
175+
// To use tutorial sample, you need read custom dictionaty from tutorial_dict.yml
176+
readDictionary(filename, dictionary); // This function is implemented in opencv/modules/objdetect/src/aruco/aruco_dictionary.cpp
181177
cv::Ptr<cv::aruco::GridBoard> board = cv::aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary);
182178

179+
cv::aruco::DetectorParameters detectorParams = cv::aruco::DetectorParameters();
180+
cv::aruco::ArucoDetector detector(dictionary, detectorParams);
181+
183182
while (inputVideo.grab()) {
184183
cv::Mat image, imageCopy;
185184
inputVideo.retrieve(image);
186185
image.copyTo(imageCopy);
187186

188187
std::vector<int> ids;
189188
std::vector<std::vector<cv::Point2f> > corners;
190-
cv::aruco::detectMarkers(image, dictionary, corners, ids);
191189

192-
// if at least one marker detected
190+
// Detect markers
191+
detector.detectMarkers(image, corners, ids);
192+
193+
// If at least one marker detected
193194
if (ids.size() > 0) {
194195
cv::aruco::drawDetectedMarkers(imageCopy, corners, ids);
195196

196197
cv::Vec3d rvec, tvec;
197-
int valid = estimatePoseBoard(corners, ids, board, cameraMatrix, distCoeffs, rvec, tvec);
198198

199-
// if at least one board marker detected
200-
if(valid > 0)
199+
// Get object and image points for the solvePnP function
200+
cv::Mat objPoints, imgPoints;
201+
board->matchImagePoints(corners, ids, objPoints, imgPoints);
202+
203+
// Find pose
204+
cv::solvePnP(objPoints, imgPoints, cameraMatrix, distCoeffs, rvec, tvec);
205+
206+
// If at least one board marker detected
207+
markersOfBoardDetected = (int)objPoints.total() / 4;
208+
if(markersOfBoardDetected > 0)
201209
cv::drawFrameAxes(imageCopy, cameraMatrix, distCoeffs, rvec, tvec, 0.1);
202210
}
203211

@@ -269,13 +277,17 @@ internal bits are not analyzed at all and only the corner distances are evaluate
269277
This is an example of using the ```refineDetectedMarkers()``` function:
270278

271279
@code{.cpp}
272-
cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
280+
281+
cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
273282
cv::Ptr<cv::aruco::GridBoard> board = cv::aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary);
283+
cv::aruco::DetectorParameters detectorParams = cv::aruco::DetectorParameters();
284+
cv::aruco::ArucoDetector detector(dictionary, detectorParams);
285+
274286
std::vector<int> markerIds;
275287
std::vector<std::vector<cv::Point2f>> markerCorners, rejectedCandidates;
276-
cv::aruco::detectMarkers(inputImage, dictionary, markerCorners, markerIds, cv::aruco::DetectorParameters(), rejectedCandidates);
288+
detector.detectMarkers(inputImage, markerCorners, markerIds, rejectedCandidates);
277289

278-
cv::aruco::refineDetectedMarkersinputImage, board, markerCorners, markerIds, rejectedCandidates);
290+
detector.refineDetectedMarkers(inputImage, board, markerCorners, markerIds, rejectedCandidates);
279291
// After calling this function, if any new marker has been detected it will be removed from rejectedCandidates and included
280292
// at the end of markerCorners and markerIds
281293
@endcode

0 commit comments

Comments
 (0)