0
# ArUco Marker Detection
1
2
ArUco markers are square fiducial markers used for camera pose estimation, augmented reality, and object tracking. The `cv2.aruco` module provides tools for detecting ArUco markers, estimating their poses, and using them for camera calibration.
3
4
## Overview
5
6
ArUco markers are binary square patterns with a unique identifier. They're commonly used in:
7
- Camera calibration
8
- Pose estimation for AR/VR applications
9
- Robot navigation and localization
10
- Object tracking
11
- Measurement and 3D reconstruction
12
13
## Capabilities
14
15
### Dictionary Management
16
17
ArUco dictionaries define the set of valid marker patterns. OpenCV provides predefined dictionaries with various marker sizes and counts.
18
19
```python { .api }
20
def aruco.getPredefinedDictionary(name: int) -> aruco.Dictionary:
21
"""
22
Get a predefined ArUco dictionary.
23
24
Args:
25
name: Dictionary identifier (e.g., cv2.aruco.DICT_4X4_50)
26
27
Returns: ArUco dictionary object
28
"""
29
...
30
31
class aruco.Dictionary:
32
"""
33
Dictionary of ArUco marker patterns.
34
Contains all valid marker codes for a specific marker configuration.
35
"""
36
bytesList: np.ndarray # Array of marker bit patterns
37
markerSize: int # Size of marker in bits (e.g., 4, 5, 6, 7)
38
maxCorrectionBits: int # Maximum number of bits that can be corrected
39
40
def __init__(self, bytesList, markerSize, maxCorrectionBits): ...
41
def getDistanceToId(self, bits, id, allRotations=True): ...
42
def identify(self, onlyBits, idx, rotation, maxCorrectionRate): ...
43
```
44
45
**Predefined Dictionary Constants:**
46
47
```python { .api }
48
# 4x4 bit markers
49
cv2.aruco.DICT_4X4_50: int # 50 markers, 4x4 bits
50
cv2.aruco.DICT_4X4_100: int # 100 markers, 4x4 bits
51
cv2.aruco.DICT_4X4_250: int # 250 markers, 4x4 bits
52
cv2.aruco.DICT_4X4_1000: int # 1000 markers, 4x4 bits
53
54
# 5x5 bit markers
55
cv2.aruco.DICT_5X5_50: int # 50 markers, 5x5 bits
56
cv2.aruco.DICT_5X5_100: int # 100 markers, 5x5 bits
57
cv2.aruco.DICT_5X5_250: int # 250 markers, 5x5 bits
58
cv2.aruco.DICT_5X5_1000: int # 1000 markers, 5x5 bits
59
60
# 6x6 bit markers
61
cv2.aruco.DICT_6X6_50: int # 50 markers, 6x6 bits
62
cv2.aruco.DICT_6X6_100: int # 100 markers, 6x6 bits
63
cv2.aruco.DICT_6X6_250: int # 250 markers, 6x6 bits
64
cv2.aruco.DICT_6X6_1000: int # 1000 markers, 6x6 bits
65
66
# 7x7 bit markers
67
cv2.aruco.DICT_7X7_50: int # 50 markers, 7x7 bits
68
cv2.aruco.DICT_7X7_100: int # 100 markers, 7x7 bits
69
cv2.aruco.DICT_7X7_250: int # 250 markers, 7x7 bits
70
cv2.aruco.DICT_7X7_1000: int # 1000 markers, 7x7 bits
71
72
# Original ArUco dictionary
73
cv2.aruco.DICT_ARUCO_ORIGINAL: int # Original ArUco dictionary (1024 markers, 5x5 bits)
74
```
75
76
### Marker Detection
77
78
Detect ArUco markers in images using the ArucoDetector class or legacy functions.
79
80
```python { .api }
81
class aruco.ArucoDetector:
82
"""
83
ArUco marker detector (recommended for OpenCV 4.7+).
84
Encapsulates dictionary and detection parameters.
85
"""
86
def __init__(self, dictionary: aruco.Dictionary, detectorParams: aruco.DetectorParameters = None): ...
87
88
def detectMarkers(self, image: np.ndarray, corners=None, ids=None, rejectedImgPoints=None):
89
"""
90
Detect ArUco markers in an image.
91
92
Args:
93
image: Input image (grayscale or color)
94
corners: Output vector of detected marker corners
95
ids: Output vector of detected marker identifiers
96
rejectedImgPoints: Output vector of rejected candidate markers
97
98
Returns: Tuple of (corners, ids, rejected)
99
- corners: List of marker corners (list of 4x2 arrays)
100
- ids: Array of marker IDs
101
- rejected: List of rejected marker corner candidates
102
"""
103
...
104
105
class aruco.DetectorParameters:
106
"""
107
Parameters for ArUco marker detection.
108
Controls detection sensitivity, accuracy, and performance.
109
"""
110
def __init__(self): ...
111
112
# Adaptive thresholding parameters
113
adaptiveThreshWinSizeMin: int # Minimum window size for adaptive thresholding
114
adaptiveThreshWinSizeMax: int # Maximum window size for adaptive thresholding
115
adaptiveThreshWinSizeStep: int # Step size for window size search
116
adaptiveThreshConstant: float # Constant subtracted from mean in adaptive thresholding
117
118
# Contour filtering
119
minMarkerPerimeterRate: float # Minimum perimeter as ratio of image diagonal
120
maxMarkerPerimeterRate: float # Maximum perimeter as ratio of image diagonal
121
polygonalApproxAccuracyRate: float # Accuracy for polygon approximation
122
123
# Marker identification
124
minCornerDistanceRate: float # Minimum distance between corners
125
minDistanceToBorder: int # Minimum distance from image border
126
minMarkerDistanceRate: float # Minimum distance between markers
127
128
# Bit extraction
129
markerBorderBits: int # Width of marker border (usually 1)
130
perspectiveRemovePixelPerCell: int # Number of pixels per cell for perspective removal
131
perspectiveRemoveIgnoredMarginPerCell: float # Margin to ignore in each cell
132
133
# Error correction
134
maxErroneousBitsInBorderRate: float # Maximum allowed erroneous bits in border
135
minOtsuStdDev: float # Minimum standard deviation for Otsu threshold
136
errorCorrectionRate: float # Error correction rate (0.0-1.0)
137
138
# Corner refinement
139
cornerRefinementMethod: int # Corner refinement method
140
cornerRefinementWinSize: int # Window size for corner refinement
141
cornerRefinementMaxIterations: int # Max iterations for corner refinement
142
cornerRefinementMinAccuracy: float # Minimum accuracy for corner refinement
143
```
144
145
**Legacy Detection Function:**
146
147
```python { .api }
148
def aruco.detectMarkers(image, dictionary, parameters=None, corners=None, ids=None, rejectedImgPoints=None):
149
"""
150
Detect ArUco markers (legacy function, use ArucoDetector for new code).
151
152
Args:
153
image: Input image
154
dictionary: ArUco dictionary
155
parameters: Detector parameters
156
corners: Output marker corners
157
ids: Output marker IDs
158
rejectedImgPoints: Output rejected candidates
159
160
Returns: Tuple of (corners, ids, rejected)
161
"""
162
...
163
```
164
165
**Usage Example:**
166
167
```python
168
import cv2
169
import numpy as np
170
171
# Load ArUco dictionary
172
aruco_dict = cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_6X6_250)
173
174
# Create detector parameters
175
parameters = cv2.aruco.DetectorParameters()
176
parameters.adaptiveThreshConstant = 7
177
178
# Create detector
179
detector = cv2.aruco.ArucoDetector(aruco_dict, parameters)
180
181
# Read image
182
image = cv2.imread('markers.jpg')
183
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
184
185
# Detect markers
186
corners, ids, rejected = detector.detectMarkers(gray)
187
188
print(f"Detected {len(corners)} markers")
189
if ids is not None:
190
print(f"Marker IDs: {ids.flatten()}")
191
```
192
193
### Marker Visualization
194
195
Draw detected markers and marker axes on images.
196
197
```python { .api }
198
def aruco.drawDetectedMarkers(image, corners, ids=None, borderColor=(0, 255, 0)):
199
"""
200
Draw detected markers on an image.
201
202
Args:
203
image: Input/output image
204
corners: Detected marker corners (from detectMarkers)
205
ids: Detected marker IDs (optional)
206
borderColor: Color for marker borders (B, G, R)
207
208
Returns: Image with drawn markers
209
"""
210
...
211
212
def aruco.drawMarker(dictionary, id, sidePixels, img=None, borderBits=1):
213
"""
214
Generate an ArUco marker image.
215
216
Args:
217
dictionary: ArUco dictionary
218
id: Marker ID to generate (0 to dictionary size - 1)
219
sidePixels: Size of output image in pixels
220
img: Output image (if None, creates new image)
221
borderBits: Width of marker border in bits (usually 1)
222
223
Returns: Marker image
224
"""
225
...
226
227
def aruco.drawAxis(image, cameraMatrix, distCoeffs, rvec, tvec, length):
228
"""
229
Draw coordinate system axes for a marker pose.
230
231
Args:
232
image: Input/output image
233
cameraMatrix: Camera intrinsic matrix (3x3)
234
distCoeffs: Camera distortion coefficients
235
rvec: Rotation vector for marker pose
236
tvec: Translation vector for marker pose
237
length: Length of axes in same units as tvec
238
239
Returns: Image with drawn axes (X=red, Y=green, Z=blue)
240
"""
241
...
242
```
243
244
**Usage Example:**
245
246
```python
247
# Draw detected markers
248
if ids is not None:
249
cv2.aruco.drawDetectedMarkers(image, corners, ids)
250
251
# Generate a marker for printing
252
marker_image = cv2.aruco.drawMarker(aruco_dict, id=42, sidePixels=200)
253
cv2.imwrite('marker_42.png', marker_image)
254
```
255
256
### Pose Estimation
257
258
Estimate the 3D pose (position and orientation) of markers relative to the camera.
259
260
```python { .api }
261
def aruco.estimatePoseSingleMarkers(corners, markerLength, cameraMatrix, distCoeffs, rvecs=None, tvecs=None):
262
"""
263
Estimate pose of single ArUco markers.
264
265
Args:
266
corners: Detected marker corners (from detectMarkers)
267
markerLength: Physical marker side length in meters
268
cameraMatrix: Camera intrinsic matrix (3x3)
269
distCoeffs: Camera distortion coefficients
270
rvecs: Output rotation vectors for each marker
271
tvecs: Output translation vectors for each marker
272
273
Returns: Tuple of (rvecs, tvecs, objPoints)
274
- rvecs: Rotation vectors (axis-angle representation)
275
- tvecs: Translation vectors (camera to marker center)
276
- objPoints: 3D corner points in marker coordinate system
277
"""
278
...
279
```
280
281
**Usage Example:**
282
283
```python
284
# Estimate marker poses
285
if ids is not None:
286
# Camera calibration parameters
287
camera_matrix = np.array([[800, 0, 320], [0, 800, 240], [0, 0, 1]], dtype=float)
288
dist_coeffs = np.zeros(5)
289
marker_length = 0.05 # 5 cm markers
290
291
# Estimate poses
292
rvecs, tvecs, _ = cv2.aruco.estimatePoseSingleMarkers(
293
corners, marker_length, camera_matrix, dist_coeffs
294
)
295
296
# Draw axes on each marker
297
for i in range(len(ids)):
298
cv2.aruco.drawAxis(image, camera_matrix, dist_coeffs,
299
rvecs[i], tvecs[i], marker_length * 0.5)
300
301
# Print distance to first marker
302
distance = np.linalg.norm(tvecs[0])
303
print(f"Marker 0 distance: {distance:.3f} meters")
304
```
305
306
### Board Detection
307
308
ArUco boards are collections of markers with known spatial arrangement, useful for camera calibration and more robust pose estimation.
309
310
```python { .api }
311
class aruco.Board:
312
"""
313
Base class for ArUco marker boards.
314
"""
315
dictionary: aruco.Dictionary # Dictionary used by the board
316
ids: np.ndarray # Marker IDs in the board
317
objPoints: list # 3D positions of marker corners
318
319
class aruco.GridBoard(aruco.Board):
320
"""
321
Grid board of ArUco markers.
322
"""
323
@staticmethod
324
def create(markersX, markersY, markerLength, markerSeparation, dictionary, firstMarker=0):
325
"""
326
Create a grid board.
327
328
Args:
329
markersX: Number of markers in X direction
330
markersY: Number of markers in Y direction
331
markerLength: Marker side length (same units as markerSeparation)
332
markerSeparation: Separation between markers
333
dictionary: ArUco dictionary
334
firstMarker: ID of first marker in board
335
336
Returns: GridBoard object
337
"""
338
...
339
340
def aruco.estimatePoseBoard(corners, ids, board, cameraMatrix, distCoeffs, rvec=None, tvec=None):
341
"""
342
Estimate pose of an ArUco board.
343
344
Args:
345
corners: Detected marker corners
346
ids: Detected marker IDs
347
board: Board object
348
cameraMatrix: Camera intrinsic matrix
349
distCoeffs: Camera distortion coefficients
350
rvec: Initial/output rotation vector
351
tvec: Initial/output translation vector
352
353
Returns: Tuple of (num_markers, rvec, tvec)
354
- num_markers: Number of markers used for pose estimation
355
- rvec: Rotation vector
356
- tvec: Translation vector
357
"""
358
...
359
```
360
361
### ChArUco Boards
362
363
ChArUco boards combine a chessboard pattern with ArUco markers, providing benefits of both (corner accuracy + robust detection).
364
365
```python { .api }
366
class aruco.CharucoBoard(aruco.Board):
367
"""
368
ChArUco board - chessboard + ArUco markers.
369
Provides accurate corners from chessboard and robust detection from markers.
370
"""
371
@staticmethod
372
def create(squaresX, squaresY, squareLength, markerLength, dictionary):
373
"""
374
Create a ChArUco board.
375
376
Args:
377
squaresX: Number of chessboard squares in X direction
378
squaresY: Number of chessboard squares in Y direction
379
squareLength: Chessboard square side length
380
markerLength: ArUco marker side length
381
dictionary: ArUco dictionary
382
383
Returns: CharucoBoard object
384
"""
385
...
386
387
class aruco.CharucoDetector:
388
"""
389
ChArUco pattern detector.
390
"""
391
def __init__(self, board, charucoParams=None, detectorParams=None, refineParams=None): ...
392
393
def detectBoard(self, image, charucoCorners=None, charucoIds=None, markerCorners=None, markerIds=None):
394
"""
395
Detect ChArUco board corners.
396
397
Args:
398
image: Input image
399
charucoCorners: Output chessboard corner coordinates
400
charucoIds: Output chessboard corner IDs
401
markerCorners: Output ArUco marker corners
402
markerIds: Output ArUco marker IDs
403
404
Returns: Tuple of (charucoCorners, charucoIds, markerCorners, markerIds)
405
"""
406
...
407
408
def aruco.interpolateCornersCharuco(markerCorners, markerIds, image, board, charucoCorners=None, charucoIds=None, cameraMatrix=None, distCoeffs=None, minMarkers=2):
409
"""
410
Interpolate ChArUco corners from detected ArUco markers.
411
412
Args:
413
markerCorners: Detected ArUco marker corners
414
markerIds: Detected ArUco marker IDs
415
image: Input image
416
board: ChArUco board
417
charucoCorners: Output ChArUco corner coordinates
418
charucoIds: Output ChArUco corner IDs
419
cameraMatrix: Optional camera matrix for refinement
420
distCoeffs: Optional distortion coefficients
421
minMarkers: Minimum number of adjacent markers for corner interpolation
422
423
Returns: Tuple of (num_corners, charucoCorners, charucoIds)
424
"""
425
...
426
427
def aruco.drawDetectedCornersCharuco(image, charucoCorners, charucoIds=None, cornerColor=(255, 0, 0)):
428
"""
429
Draw detected ChArUco corners.
430
431
Args:
432
image: Input/output image
433
charucoCorners: Detected ChArUco corners
434
charucoIds: Detected ChArUco corner IDs
435
cornerColor: Color for corners
436
437
Returns: Image with drawn corners
438
"""
439
...
440
```
441
442
### Camera Calibration with ArUco
443
444
Use ArUco markers or ChArUco boards for camera calibration.
445
446
```python { .api }
447
def aruco.calibrateCameraAruco(corners, ids, counter, board, imageSize, cameraMatrix, distCoeffs, rvecs=None, tvecs=None, flags=0, criteria=None):
448
"""
449
Calibrate camera using ArUco board.
450
451
Args:
452
corners: Vector of detected marker corners for each image
453
ids: Vector of detected marker IDs for each image
454
counter: Number of markers detected in each image
455
board: ArUco board
456
imageSize: Image size
457
cameraMatrix: Input/output camera matrix
458
distCoeffs: Input/output distortion coefficients
459
rvecs: Output rotation vectors for each image
460
tvecs: Output translation vectors for each image
461
flags: Calibration flags (same as cv2.calibrateCamera)
462
criteria: Termination criteria
463
464
Returns: Tuple of (reprojection_error, cameraMatrix, distCoeffs, rvecs, tvecs)
465
"""
466
...
467
468
def aruco.calibrateCameraCharuco(charucoCorners, charucoIds, board, imageSize, cameraMatrix, distCoeffs, rvecs=None, tvecs=None, flags=0, criteria=None):
469
"""
470
Calibrate camera using ChArUco board (more accurate than ArUco-only).
471
472
Args:
473
charucoCorners: Vector of detected ChArUco corners for each image
474
charucoIds: Vector of detected ChArUco corner IDs for each image
475
board: ChArUco board
476
imageSize: Image size
477
cameraMatrix: Input/output camera matrix
478
distCoeffs: Input/output distortion coefficients
479
rvecs: Output rotation vectors for each image
480
tvecs: Output translation vectors for each image
481
flags: Calibration flags
482
criteria: Termination criteria
483
484
Returns: Tuple of (reprojection_error, cameraMatrix, distCoeffs, rvecs, tvecs)
485
"""
486
...
487
```
488
489
## Complete Workflow Example
490
491
```python
492
import cv2
493
import numpy as np
494
495
# 1. Create and print markers
496
aruco_dict = cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_6X6_250)
497
498
# Generate markers for printing
499
for marker_id in range(4):
500
marker_img = cv2.aruco.drawMarker(aruco_dict, marker_id, 200)
501
cv2.imwrite(f'marker_{marker_id}.png', marker_img)
502
503
# 2. Detect markers in video
504
detector = cv2.aruco.ArucoDetector(aruco_dict)
505
cap = cv2.VideoCapture(0)
506
507
# Camera calibration (replace with your calibrated values)
508
camera_matrix = np.array([[800, 0, 320], [0, 800, 240], [0, 0, 1]], dtype=float)
509
dist_coeffs = np.zeros(5)
510
marker_length = 0.05 # 5 cm
511
512
while True:
513
ret, frame = cap.read()
514
if not ret:
515
break
516
517
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
518
519
# Detect markers
520
corners, ids, rejected = detector.detectMarkers(gray)
521
522
if ids is not None:
523
# Draw detected markers
524
cv2.aruco.drawDetectedMarkers(frame, corners, ids)
525
526
# Estimate poses
527
rvecs, tvecs, _ = cv2.aruco.estimatePoseSingleMarkers(
528
corners, marker_length, camera_matrix, dist_coeffs
529
)
530
531
# Draw axes for each marker
532
for i in range(len(ids)):
533
cv2.aruco.drawAxis(frame, camera_matrix, dist_coeffs,
534
rvecs[i], tvecs[i], marker_length * 0.5)
535
536
cv2.imshow('ArUco Detection', frame)
537
if cv2.waitKey(1) & 0xFF == ord('q'):
538
break
539
540
cap.release()
541
cv2.destroyAllWindows()
542
```
543