Skip to content

Commit 5a16063

Browse files
Alexander PanovSajjad Ali
authored andcommitted
Merge pull request opencv#22368 from AleksandrPanov:move_contrib_aruco_to_main_objdetect
Megre together with opencv/opencv_contrib#3325 1. Move aruco_detector, aruco_board, aruco_dictionary, aruco_utils to objdetect 1.1 add virtual Board::draw(), virtual ~Board() 1.2 move `testCharucoCornersCollinear` to Board classes (and rename to `checkCharucoCornersCollinear`) 1.3 add wrappers to keep the old api working 3. Reduce inludes 4. Fix java tests (add objdetect import) 5. Refactoring ### 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 ``` **WIP** force_builders=linux,win64,docs,Linux x64 Debug,Custom Xbuild_contrib:Docs=OFF build_image:Custom=ubuntu:22.04 build_worker:Custom=linux-1 ```
1 parent 4e02f0d commit 5a16063

27 files changed

+41433
-11
lines changed

apps/interactive-calibration/frameProcessor.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ bool CalibProcessor::detectAndParseChAruco(const cv::Mat &frame)
7979

8080
std::vector<std::vector<cv::Point2f> > corners, rejected;
8181
std::vector<int> ids;
82-
cv::aruco::detectMarkers(frame, mArucoDictionary, corners, ids, cv::aruco::DetectorParameters::create(), rejected);
82+
cv::aruco::detectMarkers(frame, cv::makePtr<cv::aruco::Dictionary>(mArucoDictionary), corners, ids, cv::makePtr<cv::aruco::DetectorParameters>(), rejected);
8383
cv::aruco::refineDetectedMarkers(frame, board, corners, ids, rejected);
8484
cv::Mat currentCharucoCorners, currentCharucoIds;
8585
if(ids.size() > 0)
@@ -266,8 +266,8 @@ bool CalibProcessor::checkLastFrame()
266266
allObjPoints.reserve(mCurrentCharucoIds.total());
267267
for(size_t i = 0; i < mCurrentCharucoIds.total(); i++) {
268268
int pointID = mCurrentCharucoIds.at<int>((int)i);
269-
CV_Assert(pointID >= 0 && pointID < (int)mCharucoBoard->chessboardCorners.size());
270-
allObjPoints.push_back(mCharucoBoard->chessboardCorners[pointID]);
269+
CV_Assert(pointID >= 0 && pointID < (int)mCharucoBoard->getChessboardCorners().size());
270+
allObjPoints.push_back(mCharucoBoard->getChessboardCorners()[pointID]);
271271
}
272272

273273
cv::solvePnP(allObjPoints, mCurrentCharucoCorners, tmpCamMatrix, mCalibData->distCoeffs, r, t);
@@ -300,8 +300,7 @@ CalibProcessor::CalibProcessor(cv::Ptr<calibrationData> data, captureParameters
300300
{
301301
case chAruco:
302302
#ifdef HAVE_OPENCV_ARUCO
303-
mArucoDictionary = cv::aruco::getPredefinedDictionary(
304-
cv::aruco::PREDEFINED_DICTIONARY_NAME(capParams.charucoDictName));
303+
mArucoDictionary = cv::aruco::getPredefinedDictionary(cv::aruco::PredefinedDictionaryType(capParams.charucoDictName));
305304
mCharucoBoard = cv::aruco::CharucoBoard::create(mBoardSize.width, mBoardSize.height, capParams.charucoSquareLength,
306305
capParams.charucoMarkerSize, mArucoDictionary);
307306
#endif

apps/interactive-calibration/frameProcessor.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class CalibProcessor : public FrameProcessor
4040

4141
cv::Ptr<cv::SimpleBlobDetector> mBlobDetectorPtr;
4242
#ifdef HAVE_OPENCV_ARUCO
43-
cv::Ptr<cv::aruco::Dictionary> mArucoDictionary;
43+
cv::aruco::Dictionary mArucoDictionary;
4444
cv::Ptr<cv::aruco::CharucoBoard> mCharucoBoard;
4545
#endif
4646

apps/interactive-calibration/main.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,8 @@ int main(int argc, char** argv)
180180
}
181181
else {
182182
#ifdef HAVE_OPENCV_ARUCO
183-
cv::Ptr<cv::aruco::Dictionary> dictionary =
184-
cv::aruco::getPredefinedDictionary(cv::aruco::PREDEFINED_DICTIONARY_NAME(capParams.charucoDictName));
183+
cv::aruco::Dictionary dictionary =
184+
cv::aruco::getPredefinedDictionary(cv::aruco::PredefinedDictionaryType(capParams.charucoDictName));
185185
cv::Ptr<cv::aruco::CharucoBoard> charucoboard =
186186
cv::aruco::CharucoBoard::create(capParams.boardSize.width, capParams.boardSize.height,
187187
capParams.charucoSquareLength, capParams.charucoMarkerSize, dictionary);

doc/py_tutorials/py_calib3d/py_pose/py_pose.markdown

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ pixels. Then to calculate the rotation and translation, we use the function,
5959
**cv.solvePnPRansac()**. Once we those transformation matrices, we use them to project our **axis
6060
points** to the image plane. In simple words, we find the points on image plane corresponding to
6161
each of (3,0,0),(0,3,0),(0,0,3) in 3D space. Once we get them, we draw lines from the first corner
62-
to each of these points using our draw() function. Done !!!
62+
to each of these points using our generateImage() function. Done !!!
6363
@code{.py}
6464
for fname in glob.glob('left*.jpg'):
6565
img = cv.imread(fname)
@@ -89,9 +89,9 @@ See some results below. Notice that each axis is 3 squares long.:
8989

9090
### Render a Cube
9191

92-
If you want to draw a cube, modify the draw() function and axis points as follows.
92+
If you want to draw a cube, modify the generateImage() function and axis points as follows.
9393

94-
Modified draw() function:
94+
Modified generateImage() function:
9595
@code{.py}
9696
def draw(img, corners, imgpts):
9797
imgpts = np.int32(imgpts).reshape(-1,2)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
@article{Aruco2014,
2+
author = {S. Garrido-Jurado and R. Mu\~noz-Salinas and F.J. Madrid-Cuevas and M.J. Mar\'in-Jim\'enez}
3+
title = {Automatic generation and detection of highly reliable fiducial markers under occlusion},
4+
year = {2014},
5+
pages = {2280 - 2292},
6+
journal = {Pattern Recognition},
7+
volume = {47},
8+
number = {6},
9+
issn = {0031-3203},
10+
doi = {http://dx.doi.org/10.1016/j.patcog.2014.01.005},
11+
url = {http://www.sciencedirect.com/science/article/pii/S0031320314000235}
12+
}
13+
14+
@inproceedings{wang2016iros,
15+
author = {John Wang and Edwin Olson},
16+
title = {{AprilTag} 2: Efficient and robust fiducial detection},
17+
booktitle = {Proceedings of the {IEEE/RSJ} International Conference on Intelligent Robots and Systems {(IROS)}},
18+
year = {2016},
19+
month = {October}
20+
}

modules/objdetect/include/opencv2/objdetect.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,5 +911,6 @@ CV_EXPORTS bool decodeCurvedQRCode(InputArray in, InputArray points, std::string
911911

912912
#include "opencv2/objdetect/detection_based_tracker.hpp"
913913
#include "opencv2/objdetect/face.hpp"
914+
#include "opencv2/objdetect/aruco_detector.hpp"
914915

915916
#endif
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
// This file is part of OpenCV project.
2+
// It is subject to the license terms in the LICENSE file found in the top-level directory
3+
// of this distribution and at http://opencv.org/license.html
4+
#ifndef OPENCV_OBJDETECT_ARUCO_BOARD_HPP
5+
#define OPENCV_OBJDETECT_ARUCO_BOARD_HPP
6+
7+
#include <opencv2/core.hpp>
8+
9+
namespace cv {
10+
namespace aruco {
11+
//! @addtogroup aruco
12+
//! @{
13+
14+
class Dictionary;
15+
16+
/** @brief Board of ArUco markers
17+
*
18+
* A board is a set of markers in the 3D space with a common coordinate system.
19+
* The common form of a board of marker is a planar (2D) board, however any 3D layout can be used.
20+
* A Board object is composed by:
21+
* - The object points of the marker corners, i.e. their coordinates respect to the board system.
22+
* - The dictionary which indicates the type of markers of the board
23+
* - The identifier of all the markers in the board.
24+
*/
25+
class CV_EXPORTS_W Board {
26+
protected:
27+
Board(); // use ::create()
28+
public:
29+
/** @brief Draw a planar board
30+
*
31+
* @param outSize size of the output image in pixels.
32+
* @param img output image with the board. The size of this image will be outSize
33+
* and the board will be on the center, keeping the board proportions.
34+
* @param marginSize minimum margins (in pixels) of the board in the output image
35+
* @param borderBits width of the marker borders.
36+
*
37+
* This function return the image of the GridBoard, ready to be printed.
38+
*/
39+
CV_WRAP virtual void generateImage(Size outSize, OutputArray img, int marginSize = 0, int borderBits = 1) const;
40+
41+
/** @brief Provide way to create Board by passing necessary data. Specially needed in Python.
42+
*
43+
* @param objPoints array of object points of all the marker corners in the board
44+
* @param dictionary the dictionary of markers employed for this board
45+
* @param ids vector of the identifiers of the markers in the board
46+
*/
47+
CV_WRAP static Ptr<Board> create(InputArrayOfArrays objPoints, const Dictionary &dictionary, InputArray ids);
48+
49+
/** @brief return the Dictionary of markers employed for this board
50+
*/
51+
CV_WRAP const Dictionary& getDictionary() const;
52+
53+
/** @brief return array of object points of all the marker corners in the board.
54+
*
55+
* Each marker include its 4 corners in this order:
56+
* - objPoints[i][0] - left-top point of i-th marker
57+
* - objPoints[i][1] - right-top point of i-th marker
58+
* - objPoints[i][2] - right-bottom point of i-th marker
59+
* - objPoints[i][3] - left-bottom point of i-th marker
60+
*
61+
* Markers are placed in a certain order - row by row, left to right in every row. For M markers, the size is Mx4.
62+
*/
63+
CV_WRAP const std::vector<std::vector<Point3f> >& getObjPoints() const;
64+
65+
/** @brief vector of the identifiers of the markers in the board (should be the same size as objPoints)
66+
* @return vector of the identifiers of the markers
67+
*/
68+
CV_WRAP const std::vector<int>& getIds() const;
69+
70+
/** @brief get coordinate of the bottom right corner of the board, is set when calling the function create()
71+
*/
72+
CV_WRAP const Point3f& getRightBottomCorner() const;
73+
74+
/** @brief Given a board configuration and a set of detected markers, returns the corresponding
75+
* image points and object points to call solvePnP
76+
*
77+
* @param detectedCorners List of detected marker corners of the board.
78+
* @param detectedIds List of identifiers for each marker.
79+
* @param objPoints Vector of vectors of board marker points in the board coordinate space.
80+
* @param imgPoints Vector of vectors of the projections of board marker corner points.
81+
*/
82+
CV_WRAP void matchImagePoints(InputArrayOfArrays detectedCorners, InputArray detectedIds,
83+
OutputArray objPoints, OutputArray imgPoints) const;
84+
virtual ~Board();
85+
protected:
86+
struct BoardImpl;
87+
Ptr<BoardImpl> boardImpl;
88+
};
89+
90+
/** @brief Planar board with grid arrangement of markers
91+
*
92+
* More common type of board. All markers are placed in the same plane in a grid arrangement.
93+
* The board image can be drawn using generateImage() method.
94+
*/
95+
class CV_EXPORTS_W GridBoard : public Board {
96+
protected:
97+
GridBoard();
98+
public:
99+
/** @brief Draw a GridBoard
100+
*
101+
* @param outSize size of the output image in pixels.
102+
* @param img output image with the board. The size of this image will be outSize
103+
* and the board will be on the center, keeping the board proportions.
104+
* @param marginSize minimum margins (in pixels) of the board in the output image
105+
* @param borderBits width of the marker borders.
106+
*
107+
* This function return the image of the GridBoard, ready to be printed.
108+
*/
109+
CV_WRAP void generateImage(Size outSize, OutputArray img, int marginSize = 0, int borderBits = 1) const CV_OVERRIDE;
110+
111+
/**
112+
* @brief Create a GridBoard object
113+
*
114+
* @param markersX number of markers in X direction
115+
* @param markersY number of markers in Y direction
116+
* @param markerLength marker side length (normally in meters)
117+
* @param markerSeparation separation between two markers (same unit as markerLength)
118+
* @param dictionary dictionary of markers indicating the type of markers
119+
* @param ids set marker ids in dictionary to use on board.
120+
* @return the output GridBoard object
121+
*
122+
* This functions creates a GridBoard object given the number of markers in each direction and
123+
* the marker size and marker separation.
124+
*/
125+
CV_WRAP static Ptr<GridBoard> create(int markersX, int markersY, float markerLength, float markerSeparation,
126+
const Dictionary &dictionary, InputArray ids);
127+
128+
/**
129+
* @overload
130+
* @brief Create a GridBoard object
131+
*
132+
* @param markersX number of markers in X direction
133+
* @param markersY number of markers in Y direction
134+
* @param markerLength marker side length (normally in meters)
135+
* @param markerSeparation separation between two markers (same unit as markerLength)
136+
* @param dictionary dictionary of markers indicating the type of markers
137+
* @param firstMarker id of first marker in dictionary to use on board.
138+
* @return the output GridBoard object
139+
*/
140+
CV_WRAP static Ptr<GridBoard> create(int markersX, int markersY, float markerLength, float markerSeparation,
141+
const Dictionary &dictionary, int firstMarker = 0);
142+
143+
CV_WRAP Size getGridSize() const;
144+
CV_WRAP float getMarkerLength() const;
145+
CV_WRAP float getMarkerSeparation() const;
146+
147+
protected:
148+
struct GridImpl;
149+
Ptr<GridImpl> gridImpl;
150+
friend class CharucoBoard;
151+
};
152+
153+
/**
154+
* @brief ChArUco board is a planar chessboard where the markers are placed inside the white squares of a chessboard.
155+
*
156+
* The benefits of ChArUco boards is that they provide both, ArUco markers versatility and chessboard corner precision,
157+
* which is important for calibration and pose estimation. The board image can be drawn using generateImage() method.
158+
*/
159+
class CV_EXPORTS_W CharucoBoard : public Board {
160+
protected:
161+
CharucoBoard();
162+
public:
163+
164+
/** @brief Draw a ChArUco board
165+
*
166+
* @param outSize size of the output image in pixels.
167+
* @param img output image with the board. The size of this image will be outSize
168+
* and the board will be on the center, keeping the board proportions.
169+
* @param marginSize minimum margins (in pixels) of the board in the output image
170+
* @param borderBits width of the marker borders.
171+
*
172+
* This function return the image of the ChArUco board, ready to be printed.
173+
*/
174+
CV_WRAP void generateImage(Size outSize, OutputArray img, int marginSize = 0, int borderBits = 1) const CV_OVERRIDE;
175+
176+
177+
/** @brief Create a CharucoBoard object
178+
*
179+
* @param squaresX number of chessboard squares in X direction
180+
* @param squaresY number of chessboard squares in Y direction
181+
* @param squareLength chessboard square side length (normally in meters)
182+
* @param markerLength marker side length (same unit than squareLength)
183+
* @param dictionary dictionary of markers indicating the type of markers.
184+
* @param ids array of id used markers
185+
* The first markers in the dictionary are used to fill the white chessboard squares.
186+
* @return the output CharucoBoard object
187+
*
188+
* This functions creates a CharucoBoard object given the number of squares in each direction
189+
* and the size of the markers and chessboard squares.
190+
*/
191+
CV_WRAP static Ptr<CharucoBoard> create(int squaresX, int squaresY, float squareLength, float markerLength,
192+
const Dictionary &dictionary, InputArray ids = noArray());
193+
194+
CV_WRAP Size getChessboardSize() const;
195+
CV_WRAP float getSquareLength() const;
196+
CV_WRAP float getMarkerLength() const;
197+
198+
/** @brief get CharucoBoard::chessboardCorners
199+
*/
200+
CV_WRAP std::vector<Point3f> getChessboardCorners() const;
201+
202+
/** @brief get CharucoBoard::nearestMarkerIdx
203+
*/
204+
CV_PROP std::vector<std::vector<int> > getNearestMarkerIdx() const;
205+
206+
/** @brief get CharucoBoard::nearestMarkerCorners
207+
*/
208+
CV_PROP std::vector<std::vector<int> > getNearestMarkerCorners() const;
209+
210+
/** @brief check whether the ChArUco markers are collinear
211+
*
212+
* @param charucoIds list of identifiers for each corner in charucoCorners per frame.
213+
* @return bool value, 1 (true) if detected corners form a line, 0 (false) if they do not.
214+
* solvePnP, calibration functions will fail if the corners are collinear (true).
215+
*
216+
* The number of ids in charucoIDs should be <= the number of chessboard corners in the board.
217+
* This functions checks whether the charuco corners are on a straight line (returns true, if so), or not (false).
218+
* Axis parallel, as well as diagonal and other straight lines detected. Degenerate cases:
219+
* for number of charucoIDs <= 2,the function returns true.
220+
*/
221+
CV_WRAP bool checkCharucoCornersCollinear(InputArray charucoIds) const;
222+
223+
protected:
224+
struct CharucoImpl;
225+
friend struct CharucoImpl;
226+
Ptr<CharucoImpl> charucoImpl;
227+
};
228+
229+
//! @}
230+
231+
}
232+
}
233+
234+
#endif

0 commit comments

Comments
 (0)