ArUco mark
First of all, what is the aruco mark?
Aruco markers are binary square fiducial markers that can be used for camera pose estimation. Its main advantages are that detection is simple, fast, and robust. An ArUco marker is a square marker consisting of a wide black border and an internal binary matrix that determines its identifier (id). The black border of the aruco marker facilitates its fast detection in images, and the internal binary code is used to identify the marker and provide error detection and correction. The size of the aruco mark determines the size of the internal matrix, for example, a mark with a size of 4x4 consists of 16 binary numbers.
In layman's terms, the aruco mark is actually a kind of code, which is similar to the QR code in our daily life, but due to the different coding methods, the way of storing information, capacity, etc. are different, so in There are also differences at the application level. Since a single aruco mark can provide sufficient correspondence, such as four distinct corners and internal binary codes, aruco marks are widely used to increase the amount of information when mapping from a two-dimensional world to a three-dimensional world, so that it is easy to find two The projection relationship between the three-dimensional world and the three-dimensional world, so as to realize pose estimation, camera correction and other applications.
The ArUco module in OpenCV includes the creation and detection of aruco markers, as well as related APIs for using aruco markers for applications such as pose estimation and camera correction, and also provides marker boards, etc. In this note, we mainly sort out the creation and detection of aruco marks.
First of all, when we create an aruco mark, we need to specify a dictionary first. This dictionary indicates the size, encoding, etc. of the created aruco mark. We use APIgetPredefinedDictionary() to declare the dictionary we use. In OpenCV, a variety of predefined dictionaries are provided. We can check which predefined dictionaries are available through PREDEFINED_DICTIONARY_NAME. And the dictionary name indicates the number and size of the aruco marks of the dictionary, for example, DICT_7X7_50 represents a dictionary containing 50 kinds of 7x7 bit marks.
ArUco Markup Generator
Online aruco marker generator: http://aruco.dgut.top/
(Alternate): https://chev.me/arucogen/
Generating ArUco markers in OpenCV
opencv-python generates aruco markers
After determining the dictionary we need, we can drawMarker()
draw the aruco mark through the API, and the meanings of its parameters are as follows:
import cv2
import numpy as np
# 生成aruco标记
# 加载预定义的字典
dictionary = cv2.aruco.Dictionary_get(cv2.aruco.DICT_6X6_250)
# 生成标记
markerImage = np.zeros((200, 200), dtype=np.uint8)
markerImage = cv2.aruco.drawMarker(dictionary, 22, 200, markerImage, 1)
cv2.imwrite("marker22.png", markerImage)
The aruco module of opencv has a total of 25 predefined tag dictionaries. All Aruco marks in each dictionary contain the same number of blocks or bits (e.g. 4×4, 5×5, 6×6 or 7×7), and the number of Aruco marks in each dictionary is fixed (e.g. 50, 100 , 250 or 1000).
cv2.aruco.Dictionary_get()
The function loads cv2.aruco.DICT_6X6_250
a dictionary of 250 tokens, where each token is a 6×6 bit binary pattern
cv2.aruco.drawMarker(dictionary, 22, 200, markerImage, 1)
The second parameter in 22
is the tag id of aruco (0~249), the third parameter determines the size of the generated tag, in the above example, it will generate a pixel 200×200
image, and the fourth parameter indicates that the aruco tag will be stored object (above markerImage
), and finally, the fifth parameter is the border width parameter, which determines how many bits (blocks) should be added as a border to the resulting binary pattern.
After execution, such tags will be generated: the tag ids are22
展开查看的内容;
DICT_4X4_50
Python: cv.aruco.DICT_4X4_50
DICT_4X4_100
Python: cv.aruco.DICT_4X4_100
DICT_4X4_250
Python: cv.aruco.DICT_4X4_250
DICT_4X4_1000
Python: cv.aruco.DICT_4X4_1000
DICT_5X5_50
Python: cv.aruco.DICT_5X5_50
DICT_5X5_100
Python: cv.aruco.DICT_5X5_100
DICT_5X5_250
Python: cv.aruco.DICT_5X5_250
DICT_5X5_1000
Python: cv.aruco.DICT_5X5_1000
DICT_6X6_50
Python: cv.aruco.DICT_6X6_50
DICT_6X6_100
Python: cv.aruco.DICT_6X6_100
DICT_6X6_250
Python: cv.aruco.DICT_6X6_250
DICT_6X6_1000
Python: cv.aruco.DICT_6X6_1000
DICT_7X7_50
Python: cv.aruco.DICT_7X7_50
DICT_7X7_100
Python: cv.aruco.DICT_7X7_100
DICT_7X7_250
Python: cv.aruco.DICT_7X7_250
DICT_7X7_1000
Python: cv.aruco.DICT_7X7_1000
DICT_ARUCO_ORIGINAL
Python: cv.aruco.DICT_ARUCO_ORIGINAL
DICT_APRILTAG_16h5
Python: cv.aruco.DICT_APRILTAG_16h5
4x4 bits, minimum hamming distance between any two codes = 5, 30 codes
Generate aruco marks in batches
import cv2
import numpy as np
# 生成aruco标记
# 加载预定义的字典
dictionary = cv2.aruco.Dictionary_get(cv2.aruco.DICT_6X6_250)
# 生成标记
markerImage = np.zeros((200, 200), dtype=np.uint8)
for i in range(30):
markerImage = cv2.aruco.drawMarker(dictionary, i, 200, markerImage, 1);
firename='armark/'+str(i)+'.png'
cv2.imwrite(firename, markerImage);
A series of 6*6 will be generated under the armark folderaruco标记
Detection and localization of Aruco markers
static detection
Image detection Aruco markers in environment with 7 markers in environment
import numpy as np
import time
import cv2
import cv2.aruco as aruco
#读取图片
frame=cv2.imread('IMG_3739.jpg')
#调整图片大小
frame=cv2.resize(frame,None,fx=0.2,fy=0.2,interpolation=cv2.INTER_CUBIC)
#灰度话
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#设置预定义的字典
aruco_dict = aruco.Dictionary_get(aruco.DICT_6X6_250)
#使用默认值初始化检测器参数
parameters = aruco.DetectorParameters_create()
#使用aruco.detectMarkers()函数可以检测到marker,返回ID和标志板的4个角点坐标
corners, ids, rejectedImgPoints = aruco.detectMarkers(gray,aruco_dict,parameters=parameters)
#画出标志位置
aruco.drawDetectedMarkers(frame, corners,ids)
cv2.imshow("frame",frame)
cv2.waitKey(0)
cv2.destroyAllWindows()
For each successful detection of a marker, the four corners of the marker will be detected in the order from top left, top right, bottom right and bottom left. In C++, store these 4 detected corners as a point vector, and store multiple markers in the image together in a point vector container. In Python, they are stored as Numpy arrays.
detectMarkers()
Function to detect and determine the position of the marker corners.
- The first argument
image
is an image of the scene with markers.- The second parameter
dictionary
is a dictionary used to generate tokens. Successfully detected markers will be stored in markerCorners and their IDs in markerIds. A previously initialized DetectorParameters object is passed as a parameter.- The third parameter
parameters
:DetectionParameters
the object of the class, which includes all parameters that can be customized during the detection process;- Return parameter
corners
: list of corners of the detected aruco markers, for each marker its four corners are returned in their original order (clockwise starting from the upper right corner), the first corner is the upper right corner, then the right Bottom, bottom left and top left.- Return
ids
: the id of each detected tag, it should be noted that the third parameter and the fourth parameter have the same size;- Return parameter
rejectedImgPoints
: list of discarded candidate markers, i.e. squares that were detected but did not provide a valid encoding. Each candidate token is also defined by its four corners, and its format is the same as the third parameter, which can be omitted if there is no special requirement.
corners, ids, rejectedImgPoints = aruco.detectMarkers(gray,aruco_dict,parameters=parameters)
When we detect the aruco tag, in order to facilitate observation, we need to perform visualization operations and mark the tag: use drawDetectedMarkers()
this API to draw the detected aruco tag, and the meanings of its parameters are as follows:
- Parameter image: is the input/output image that will draw the marker (usually the image where the marker is detected)
- Parameter corners: list of corners detected by aruco markers
- Parameter ids: Each detected marker corresponds to the id in the dictionary to which it belongs, optional (if not provided) the ID will not be drawn.
- Parameter borderColor: The color of the border of the marker, and the rest of the colors (text color and first corner color) will be calculated based on this color to improve the visualization effect.
- no return value
aruco.drawDetectedMarkers(image, corners,ids,borderColor)
Effect demonstration:
dynamic detection
Use the camera to perform a real-time dynamic monitoring of aruco markers and estimate the pose. The internal parameters of the camera need to be calibrated in advance. For how to calibrate, please see my other article
import numpy as np
import time
import cv2
import cv2.aruco as aruco
# mtx = np.array([
# [2946.48, 0, 1980.53],
# [ 0, 2945.41, 1129.25],
# [ 0, 0, 1],
# ])
# #我的手机拍棋盘的时候图片大小是 4000 x 2250
# #ip摄像头拍视频的时候设置的是 1920 x 1080,长宽比是一样的,
# #ip摄像头设置分辨率的时候注意一下
#
#
# dist = np.array( [0.226317, -1.21478, 0.00170689, -0.000334551, 1.9892] )
#相机纠正参数
# dist=np.array(([[-0.51328742, 0.33232725 , 0.01683581 ,-0.00078608, -0.1159959]]))
#
# mtx=np.array([[464.73554153, 0.00000000e+00 ,323.989155],
# [ 0., 476.72971528 ,210.92028],
# [ 0., 0., 1. ]])
dist=np.array(([[-0.58650416 , 0.59103816, -0.00443272 , 0.00357844 ,-0.27203275]]))
newcameramtx=np.array([[189.076828 , 0. , 361.20126638]
,[ 0 ,2.01627296e+04 ,4.52759577e+02]
,[0, 0, 1]])
mtx=np.array([[398.12724231 , 0. , 304.35638757],
[ 0. , 345.38259888, 282.49861858],
[ 0., 0., 1. ]])
cap = cv2.VideoCapture(0)
font = cv2.FONT_HERSHEY_SIMPLEX #font for displaying text (below)
#num = 0
while True:
ret, frame = cap.read()
h1, w1 = frame.shape[:2]
# 读取摄像头画面
# 纠正畸变
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (h1, w1), 0, (h1, w1))
dst1 = cv2.undistort(frame, mtx, dist, None, newcameramtx)
x, y, w1, h1 = roi
dst1 = dst1[y:y + h1, x:x + w1]
frame=dst1
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
aruco_dict = aruco.Dictionary_get(aruco.DICT_6X6_250)
parameters = aruco.DetectorParameters_create()
dst1 = cv2.undistort(frame, mtx, dist, None, newcameramtx)
'''
detectMarkers(...)
detectMarkers(image, dictionary[, corners[, ids[, parameters[, rejectedI
mgPoints]]]]) -> corners, ids, rejectedImgPoints
'''
#使用aruco.detectMarkers()函数可以检测到marker,返回ID和标志板的4个角点坐标
corners, ids, rejectedImgPoints = aruco.detectMarkers(gray,aruco_dict,parameters=parameters)
# 如果找不打id
if ids is not None:
rvec, tvec, _ = aruco.estimatePoseSingleMarkers(corners, 0.05, mtx, dist)
# 估计每个标记的姿态并返回值rvet和tvec ---不同
# from camera coeficcients
(rvec-tvec).any() # get rid of that nasty numpy value array error
# aruco.drawAxis(frame, mtx, dist, rvec, tvec, 0.1) #绘制轴
# aruco.drawDetectedMarkers(frame, corners) #在标记周围画一个正方形
for i in range(rvec.shape[0]):
aruco.drawAxis(frame, mtx, dist, rvec[i, :, :], tvec[i, :, :], 0.03)
aruco.drawDetectedMarkers(frame, corners)
###### DRAW ID #####
cv2.putText(frame, "Id: " + str(ids), (0,64), font, 1, (0,255,0),2,cv2.LINE_AA)
else:
##### DRAW "NO IDS" #####
cv2.putText(frame, "No Ids", (0,64), font, 1, (0,255,0),2,cv2.LINE_AA)
# 显示结果框架
cv2.imshow("frame",frame)
key = cv2.waitKey(1)
if key == 27: # 按esc键退出
print('esc break...')
cap.release()
cv2.destroyAllWindows()
break
if key == ord(' '): # 按空格键保存
# num = num + 1
# filename = "frames_%s.jpg" % num # 保存一张图像
filename = str(time.time())[:10] + ".jpg"
cv2.imwrite(filename, frame)
Effect
Blog address: https://blog.dgut.top/2020/07/15/python-aruco/
References in this article:
1.https://blog.csdn.net/sinat_17456165/article/details/105649131
2.https://www.learnopencv.com/augmented-reality-using-aruco-markers-in-opencv-c-python/