二维码识别与定位-方法1-利用ar_track_alvar

Posted 步印

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二维码识别与定位-方法1-利用ar_track_alvar相关的知识,希望对你有一定的参考价值。

  二维码识别作为一种快捷准确的技术已经应用与生活中的购物支付、物体识别及工业AGV导航等领域,在OpenCV3.4.4版本上均提供了相应的函数cv::QRCodeDetector::detectAndDecode()用于二维码的检测和解析,但是在ROS kinetic中自带的版本是OpenCV3.3.1,不能使用API,幸运地是在ROS中有一个开源功能包ar_track_alvar用于二维码相关的操作。
其安装方式为:

   $ sudo apt-get install ros-melodic-ar-track-alvar

  本节主要讲在ROS中如何创建二维码以及如何利用相机识别二维码来获得有用的信息。并利用两个不同的二维码来表征不同的物体,进而通过识别二维码来完成物体的定位。

1. 二维码创建

  二维码的创建一般是离线进行的,是二维码识别的前提。制作好的二维码粘贴到地面、物体上后才可以实现实时定位。每一个二维码通常对应一个标签,如有的二维码代表一个网站,有的二维码代表一个坐标位置,有的二维码代表一个字符串等。

  在ROS中,ar_track_alvar功能包提供了创建二维码的节点,可以根据其定义的规则,创建不同标签的二维码。例如执行如下命令,就会在终端的当前路径下,创建一个命名为MarkerData_标签.png的二维码图像。其中标签可以为整数、字符串、网址等属性。例如执行如下命令,会在终端生成一个名为MarkerData_0.png的图像,如图7.16所示。

    $ rosrun ar_track_alvar createMarker 0

图 MarkerData_0.png图像
  执行如下命令可以查看创建二维码的规则:
  $ rosrun ar_track_alvar createMarker

图 创建二维码的一般规则

  可以看出使用-1 “string”的形式,可以创建字符串标签的二维码。在这里我们使用如下命令,创建多个不同的物体标签,包括cup、bottle、book、celephone,起二维码如图7.17所示。

    $ rosrun ar_track_alvar createMarker -1 “cup”
    $ rosrun  ar_track_alvar createMarker -1 “bottle”
    $ rosrun  ar_track_alvar createMarker -1 “book”
    $ rosrun  ar_track_alvar createMarker -1 “celphone

(a)标签为“cup”的二维码

(b)标签为“book”的二维码

(c)标签为“bottle”的二维码

(d)标签为“celephone”的二维码

  做好二维码后我们就可以将其用于物体识别和定位了。

2. 二维码识别

  ar_track_alvar功能包支持USB摄像头和RGB摄像头进行二维码识别,分别对应节点individualMarkersNoKinect适用于彩色摄像头,individualMarkers适用于深度相机。本节以astra mini相机为例进行二维码识别。
创建二维码识别的启动文件:

$ roscd cv_learn
<launch>
<node pkg="tf" type="static_transform_publisher" name="world_to_cam" 
args="0 0 0.5 0 1.57 0 world camera_rgb_optical_frame 10" />

<arg name="marker_size" default="4.7" />
<arg name="max_new_marker_error" default="0.2" />
<arg name="max_track_error" default="0.2" />

<arg name="cam_image_topic"   default="/camera/depth_registered/points" />
<arg name="cam_info_topic" default="/camera/rgb/camera_info" />
<arg name="output_frame" default="/camera_rgb_optical_frame" />

<node name="ar_track_alvar" pkg="ar_track_alvar" type="individualMarkers" respawn="false" output="screen">
<param name="marker_size" type="double" value="$(arg marker_size)" />
<param name="max_new_marker_error" type="double" value="$(arg max_new_marker_error)" />
<param name="max_track_error" type="double" value="$(arg max_track_error)" />
<param name="output_frame" type="string" value="$(arg output_frame)" />

<remap from="camera_image" to="$(arg cam_image_topic)" />
<remap from="camera_info" to="$(arg cam_info_topic)" />
</node>

<!-- rviz view /-->
<node pkg="rviz" type="rviz" name="rviz" args="-d $(find cv_learn)/config/ar_track_astra.rviz"/>

</launch> 

  启动文件由三部分组成,首先设置相机坐标系与世界坐标系之间的坐标变换;其次是设置individualMarkers节点所需要的参数,主要是订阅图像数据的话题,二维码的尺寸,最大尺寸误差等参数;最后是启动可视化插件rviz用于显示tf、marker及图像。
  下面启动相机与该启动文件进行测试,与之前的相机驱动程序不同,二维码的识别和定位需要相机的标定参数,又,在4.2节中已对astra mini相机进行了标定,直接使用即可,我们可以新建一个启动文件,并将标定参数加入到启动文件中,如astra_with_calibration.launch所示:

<launch>
<!-- Launch the freenect driver -->
<include file="$(find astra_launch)/launch/astra.launch">
<arg name="publish_tf" value="false" /> 

<!-- use device registration -->
<arg name="depth_registration" value="true" /> 

<arg name="rgb_processing" value="true" />
<arg name="ir_processing" value="false" />
<arg name="depth_processing" value="false" />
<arg name="depth_registered_processing" value="true" />
<arg name="disparity_processing" value="false" />
<arg name="disparity_registered_processing" value="false" />
<arg name="sw_registered_processing" value="false" />
<arg name="hw_registered_processing" value="true" />

<arg name="rgb_camera_info_url"
value="file://$(find cv_learn)/data/camera_calibration/astra_calib/rgb_calibration/astra_rgb_calibration.yaml" />
<arg name="depth_camera_info_url"
value="file://$(find cv_learn)/data/camera_calibration/astra_calib/depth_calibration/astra_depth_calibration.yaml" />
</include>
</launch>

按如下命令依次启动相机和二维码识别节点:

$ roslaunch  cv_learn astra_with_calibration.launch
$ roslaunch  cv_learn ar_track_astra.launch

  拿起打印好的二维码,放置在摄像头前面,如图所示。可以在rviz看到已识别出了每个二维码,且包括其相对与摄像头的位置和姿态。

图4.40 二维码检测结果

3 基于二维码的物体检测与识别

  我们可以将二维码粘贴在物体的表面,这样当相机检测到二维码的位置和姿态时,可以间接计算出物体当前的位置和姿态通过运行如下命令:

$ rostopic echo /ar_pose_marker 

如图所示,可以查看当前二维码所处的位置和姿态,变换位置后,位姿有相应的变化.

图 位置1处的物体检测结果

图 位置2处的物体检测结果

OpenCV二维码检测与定位

在如今流行扫描的年代,应用程序实现二维码扫描检测与识别已经是应用程序的标配、特别是在移动端、如果你的应用程序不能自动发现检测二维码,自动定位二维码你都不好意思跟别人打招呼,二维码识别与解析基于ZXing包即可。难点就在于如何从画面中快速而准确的找到二维码区域,寻找到二维码三个匹配模式点。

 

一:二维码的结构与基本原理

标准的二维码结构如下:

特别要关注的是图中三个黑色正方形区域,它们就是用来定位一个二维码的最重要的三个区域,我们二维码扫描与检测首先要做的就是要发现这三个区域,如果找到这个三个区域,我们就成功的发现一个二维码了,就可以对它定位与识别了。二维码其它各个部分的说明如下:

OpenCV二维码检测与定位

三个角上的正方形区域从左到右,从上到下黑白比例为1:1:3:1:1。

OpenCV二维码检测与定位


不管角度如何变化,这个是最显著的特征,通过这个特征我们就可以实现二维码扫描检测与定位。

 

二:算法各部与输出

1. 首先把输入图像转换为灰度图像(cvtColor)

OpenCV二维码检测与定位


2. 通过OTSU转换为二值图像(threshold)

 

OpenCV二维码检测与定位


3. 对二值图像使用轮廓发现得到轮廓(findContours)

 

OpenCV二维码检测与定位


4. 根据二维码三个区域的特征,对轮廓进行面积与比例过滤得到最终结果显示如下:

 

OpenCV二维码检测与定位


三:程序运行结果演示

 上述程序运行的最终结果,左侧为原图,右侧为检测结果

OpenCV二维码检测与定位

OpenCV二维码检测与定位


四:各个步骤代码实现

 
   
   
 
  1. #include <opencv2/opencv.hpp>

  2. #include <math.h>

  3. #include <iostream>

  4. using namespace cv;

  5. using namespace std;

  6. bool isCorner(Mat &image);

  7. Mat transformCorner(Mat &image, RotatedRect &rect);

  8. int main(int argc, char** argv) {

  9.    Mat src = imread("D:/gloomyfish/qrcode_05.jpg");

  10.    if (src.empty()) {

  11.        printf("could not load image...\n");

  12.        return -1;

  13.    }

  14.    namedWindow("input image", CV_WINDOW_AUTOSIZE);

  15.    imshow("input image", src);

  16.    Mat gray, binary;

  17.    cvtColor(src, gray, COLOR_BGR2GRAY);

  18.    imwrite("D:/gloomyfish/outimage/qrcode_gray.jpg", gray);

  19.    threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);

  20.    imwrite("D:/gloomyfish/outimage/qrcode_binary.jpg", binary);

  21.    // detect rectangle now

  22.    vector<vector<Point>> contours;

  23.    vector<Vec4i> hireachy;

  24.    Moments monents;

  25.    findContours(binary.clone(), contours, hireachy, RETR_LIST, CHAIN_APPROX_SIMPLE, Point());

  26.    Mat result = Mat::zeros(src.size(), CV_8UC3);

  27.    for (size_t t = 0; t < contours.size(); t++) {

  28.        double area = contourArea(contours[t]);

  29.        if (area < 100) continue;

  30.        RotatedRect rect = minAreaRect(contours[t]);

  31.        // 根据矩形特征进行几何分析

  32.        float w = rect.size.width;

  33.        float h = rect.size.height;

  34.        float rate = min(w, h) / max(w, h);

  35.        if (rate > 0.85 && w < src.cols/4 && h<src.rows/4) {

  36.            printf("angle : %.2f\n", rect.angle);

  37.            Mat qr_roi = transformCorner(src, rect);

  38.            if (isCorner(qr_roi)) {

  39.                drawContours(src, contours, static_cast<int>(t), Scalar(255, 0, 0), 2, 8);

  40.                imwrite(format("D:/gloomyfish/outimage/contour_%d.jpg", static_cast<int>(t)), qr_roi);

  41.                drawContours(result, contours, static_cast<int>(t), Scalar(255, 0, 0), 2, 8);

  42.            }

  43.        }

  44.    }

  45.    imshow("result", src);

  46.    imwrite("D:/gloomyfish/outimage/qrcode_patters.jpg", result);

  47.    waitKey(0);

  48.    return 0;

  49. }


功崇惟志,业广惟勤!


关注【OpenCV学堂】

长按或者扫码下面二维码即可关注

+OpenCV学习群 376281510

进群暗号:OpenCV


以上是关于二维码识别与定位-方法1-利用ar_track_alvar的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV二维码检测与定位

基于opencv 识别定位二维码 (c++版)

如何利用Halcon进行二维码QR码的识别

车标识别基于SIFT算子的车标识别算法matlab仿真

《移动项目实践》实验报告——Android设备操作

《移动项目实践》实验报告——Android设备操作