二维码识别作为一种快捷准确的技术已经应用与生活中的购物支付、物体识别及工业AGV导航等领域,典型的二维码识别开源库有arcuo,alvar以及OpenCV中的二维码检测API如QRCodeDetector,在本节中我们将使用aruco库来进行二维码的识别,该库已集成在opencv的contrib集中。
本节主要讲在ROS中如何创建二维码以及如何利用相机识别二维码来获得有用的信息。并利用两个不同的二维码来表征不同的物体,进而通过识别二维码来完成物体的定位。
二维码的创建一般是离线进行的,是二维码识别的前提。制作好的二维码粘贴到地面、物体上后才可以实现实时定位。每一个二维码通常对应一个标签,如有的二维码代表一个网站,有的二维码代表一个坐标位置,有的二维码代表一个字符串等。
在aruco模块包含了一些预定义的字典,如下表所示,每个字典实际上是常用的一些二维码集合,这些字典涵盖了一系列的字典大小和Marker尺寸,marker可以有不同的规格.根据每个marker我们还可以生成不同像素大小的图像.
序号 | 字典 | 字典 | 字典 | 字典 |
---|---|---|---|---|
1 | DICT_4x4_50 | DICT_4x4_100 | DICT_4x4_250 | DICT_4x4_1000 |
2 | DICT_5x5_50 | DICT_5x5_100 | DICT_5x5_250 | DICT_5x5_1000 |
3 | DICT_6x6_50 | DICT_6x6_100 | DICT_6x6_250 | DICT_6x6_1000 |
4 | DICT_7x7_50 | DICT_7x7_100 | DICT_7x7_250 | DICT_7x7_1000 |
在本节中我们选择字典DICT_6x6_250,其marker大小为6x6bits,字典的大小为250,即该字典中有250个大小为6*6bit的二维码.下面我们编写节点来使用该字典中的某一个二维码来生成二维码图像.
执行如下命令,会在终端生成一个名为marker_6X6_250_31.jpg的图像,它是aruco预定义的字典DICT_6X6_250中第31个二维码,其像素大小为500*500,即宽高都为500pixels.如图所示。
$ gedit generate_marker.py
其内容如下:
import numpy as np
import cv2
import cv2.aruco as aruco
import math
aruco_dict = aruco.Dictionary_get(aruco.DICT_6X6_250)
marker_id = 31
marker_img = aruco.drawMarker(aruco_dict, marker_id,500)
pic_name = "marker_6X6_250_" + str(marker_id) + ".jpg"
cv2.imwrite(pic_name,marker_img)
下面对上述代码的关键内容进行解析,aruco.Dictionary_get(aruco.DICT_6X6_250) 表示获取字典DICT_6X6_250;marker_id = 31,表示我们要生成的二维码在字典中的编号是31;aruco.drawMarker表示绘制该二维码,大小为500*500.
得到了上述的二维码之后,我们就可以使用aruco来编写识别二维码的程序了.执行如下命令来创建二维码识别程序:
$ gedit marker_detect.py
你可在目录/cv_learn目录下看到文件qrcode_detect_demo.py.下面仅对其主要代码进行解释:
rospy.init_node('qcode_detect', anonymous=True)
detection_pub = rospy.Publisher("qcode_detect_result", Twist, queue_size=1) # 发布图像话题名称上述代码声明了本节点的名称”qcode_detect”,且本节点检测到的物体结果信息将通过话题”qcode_detect_result”进行发布.
corners, ids, rejectedImgPoints = aruco.detectMarkers(image=gray, dictionary=aruco_dict, parameters=parameters, cameraMatrix=camera_matrix,distCoeff=camera_distortion)# 该代码用于检测图像中的二维码,其输入为经过灰度化处理的图像,要检测对象归属的二维码字典以及相机的内参。输出为检测到的二维码的四个角点的像素坐标,已检测的二维码在字典中的id编号。
ret = aruco.estimatePoseSingleMarkers(corners, marer_size, camera_matrix, camera_distortion)#该代码使用aruco中的estimatePoseSingleMarkers函数,其输入为检测到的二维码角点信息以及二维码实际打印后的尺寸(mm)。其输出为二维码在相机坐标系下的位置和姿态。此过程实际是通过PNP解算得到的。
result = Twist()
result.linear.x = tvec[0]
result.linear.y = tvec[1]
result.linear.z = tvec[2]
result.angular.x = r
result.angular.y = p
result.angular.z = y
detection_pub.publish(result)#用于发布检测到的结果,其类型采用的是Twist,包括二维码在相机坐标系x,y,z下的直角坐标,以及绕x,y,z轴的欧拉角。
将打印好的二维码放在相机视野下,然后执行如下命令启动二维码识别节点:
$ python marker_detect.py
其检测结果如下,可以看到二维码区域已经被框选出来,且坐标轴也已标注出,其中红色表示x轴,绿色表示y轴,蓝色表示z轴。