二维码的特征定位和信息识别

2023-05-16

二维码的特征定位和信息识别

背景介绍

视觉的方法可以用来估计位置和姿态。最容易想到的是在目标上布置多个容易识别的特征,这样使用opencv相机标定和、相机畸变矫正、轮廓提取、solvepnp来获取目标相对于相机的位姿。在实际使用中只要相机和目标一方是估计的,那就可以得到全局坐标。如果相机和靶标都在移动,那只能获取到相对坐标。但是受限于相机视角和景深,这样多个特征的识别虽然精度可以很高,但是范围却很小。

对于如何扩大范围,使用二维码是一个很好的思路。首先,二维码本身具有多个特征,单个二维码可以用来实现上述方法的功能。其次,二维码本身带有信息,如果二维码的布置事先已知,那么位置和姿态估计的范围将只受限于二维码的数量。

本文主要是二维码的特征识别和信息识别。

二维码的的生成

二维码是在一个网站上生成的,经过手机的测试,生成的二维码没有问题。http://www.liantu.com/,该网站是免费的,生成的图片及二维码各种参数可以自定义。
本文的测试图片有20张,是数字1到5,每个数字隔90度旋转各一张。
这里写图片描述

二维码的特征识别

二维码特征识别的思路是:第一步,寻找二维码的三个角的定位角点,需要对图片进行平滑滤波,二值化,寻找轮廓,筛选轮廓中有两个子轮廓的特征,从筛选后的轮廓中找到面积最接近的3个即是二维码的定位角点。第二步:判断3个角点处于什么位置,主要用来对图片进行透视校正(相机拍到的图片)或者仿射校正(对网站上生成的图片进行缩放拉伸旋转等操作后得到的图片)。需要判断三个角点围成的三角形的最大的角就是二维码左上角的点。然后根据这个角的两个边的角度差确定另外两个角点的左下和右上位置。第三步,根据这些特征识别二维码的范围。
具体的代码:

        Mat src = imread( "pic\\456.jpg", 1 );
        if(src.empty())  
        {  
            fprintf(stderr, "Can not load image!\n");  
            return 0;  
        }  

        Mat src_all=src.clone();  

        //彩色图转灰度图  
        Mat src_gray;
        cvtColor( src, src_gray, CV_BGR2GRAY );  

        //对图像进行平滑处理  
        blur( src_gray, src_gray, Size(3,3) );  

        //使灰度图象直方图均衡化  
        equalizeHist( src_gray, src_gray );  

        namedWindow("src_gray");  
        imshow("src_gray",src_gray);         //灰度图

        //指定112阀值进行二值化
        Mat threshold_output;
        threshold( src_gray, threshold_output, 112, 255, THRESH_BINARY ); 

#ifdef DEBUG
        namedWindow("二值化后输出");  
        imshow("二值化后输出",threshold_output);   //二值化后输出
#endif

        //需要的变量定义
        Scalar color = Scalar(1,1,255 );  
        vector<vector<Point>> contours,contours2;  
        vector<Vec4i> hierarchy;  
        Mat drawing = Mat::zeros( src.size(), CV_8UC3 );  
        //Mat drawing2 = Mat::zeros( src.size(), CV_8UC3 );  
        Mat drawingAllContours = Mat::zeros( src.size(), CV_8UC3 ); 

        //利用二值化输出寻找轮廓
        findContours(threshold_output, contours, hierarchy,  CV_RETR_TREE, CHAIN_APPROX_NONE, Point(0, 0) );  

        //寻找轮廓的方法
        int tempindex1 = 0;
        int tempindex2 = 0;

        for(int i = 0;i<contours.size();i++)
        {
            if(hierarchy[i][2] == -1)
                continue;
            else
                tempindex1 = hierarchy[i][2];                //第一个子轮廓的索引

            if(hierarchy[tempindex1][2] == -1)
                continue;
            else
            {
                tempindex2 = hierarchy[tempindex1][2];        //第二个子轮廓的索引
                //记录搜索到的有两个子轮廓的轮廓并把他们的编号存储
                in.a1 = i;
                in.a2 = tempindex1;
                in.a3 = tempindex2;
                vin.push_back(in);
            }
        }

        //按面积比例搜索
        vector<index>::iterator it;
        for(it = vin.begin();it != vin.end();)
        {
            vector<Point> out1Contours = contours[it->a1];
            vector<Point> out2Contours = contours[it->a2];
            double lenth1 = arcLength(out1Contours,1);
            double lenth2 = arcLength(out2Contours,1);
            if(abs(lenth1/lenth2-2)>1)
            {
                it = vin.erase(it);
            }
            else
            {
                drawContours( drawing, contours, it->a1,  CV_RGB(255,255,255) , CV_FILLED, 8); 
                it++;
            }
        }

        //获取三个定位角的中心坐标  
        Point point[3];
        int i = 0;
        vector<Point> pointthree;
        for(it = vin.begin(),i = 0;it != vin.end();i++,it++)
        {
            point[i] = Center_cal( contours, it->a1 );
            pointthree.push_back(point[i]);
        }

        if(pointthree.size() <3)
        {
            cout << "找到的定位角点不足3个"<<endl;
            return 0;  
        }

        //计算轮廓的面积,计算定位角的面积,从而计算出边长
        double area = contourArea(contours[vin[0].a1]);
        int area_side = cvRound (sqrt (double(area)));  
        for(int i=0; i<3; i++)  
        {  
            //画出三个定位角的中心连线  
            line(drawing,point[i%3],point[(i+1)%3],color,area_side/10,8);  
        }  

        //清除找到的3个点,以便处理下一幅图片使用
        vin.clear();

        //由3个定位角校正图片
        //=========================================
        //找到角度最大的点
        double ca[2];
        double cb[2];

        ca[0] =  pointthree[1].x - pointthree[0].x;
        ca[1] =  pointthree[1].y - pointthree[0].y;
        cb[0] =  pointthree[2].x - pointthree[0].x;
        cb[1] =  pointthree[2].y - pointthree[0].y;
        double angle1 = 180/3.1415*acos((ca[0]*cb[0]+ca[1]*cb[1])/(sqrt(ca[0]*ca[0]+ca[1]*ca[1])*sqrt(cb[0]*cb[0]+cb[1]*cb[1])));
        double ccw1;
        if(ca[0]*cb[1] - ca[1]*cb[0] > 0) ccw1 = 0;
        else ccw1 = 1;

        ca[0] =  pointthree[0].x - pointthree[1].x;
        ca[1] =  pointthree[0].y - pointthree[1].y;
        cb[0] =  pointthree[2].x - pointthree[1].x;
        cb[1] =  pointthree[2].y - pointthree[1].y;
        double angle2 = 180/3.1415*acos((ca[0]*cb[0]+ca[1]*cb[1])/(sqrt(ca[0]*ca[0]+ca[1]*ca[1])*sqrt(cb[0]*cb[0]+cb[1]*cb[1])));
        double ccw2;
        if(ca[0]*cb[1] - ca[1]*cb[0] > 0) ccw2 = 0;
        else ccw2 = 1;

        ca[0] =  pointthree[1].x - pointthree[2].x;
        ca[1] =  pointthree[1].y - pointthree[2].y;
        cb[0] =  pointthree[0].x - pointthree[2].x;
        cb[1] =  pointthree[0].y - pointthree[2].y;
        double angle3 = 180/3.1415*acos((ca[0]*cb[0]+ca[1]*cb[1])/(sqrt(ca[0]*ca[0]+ca[1]*ca[1])*sqrt(cb[0]*cb[0]+cb[1]*cb[1])));
        double ccw3;
        if(ca[0]*cb[1] - ca[1]*cb[0] > 0) ccw3 = 0;
        else ccw3 = 1;

        CvPoint2D32f poly[4];
        if(angle3>angle2 && angle3>angle1)
        {
            if(ccw3)
            {
                poly[1] = pointthree[1];
                poly[3] = pointthree[0];
            }
            else
            {
                poly[1] = pointthree[0];
                poly[3] = pointthree[1];
            }
            poly[0] = pointthree[2];
            Point temp(pointthree[0].x + pointthree[1].x - pointthree[2].x , pointthree[0].y + pointthree[1].y - pointthree[2].y );
            poly[2] = temp;
        }
        else if(angle2>angle1 && angle2>angle3)
        {
            if(ccw2)
            {
                poly[1] = pointthree[0];
                poly[3] = pointthree[2];
            }
            else
            {
                poly[1] = pointthree[2];
                poly[3] = pointthree[0];
            }
            poly[0] = pointthree[1];
            Point temp(pointthree[0].x + pointthree[2].x - pointthree[1].x , pointthree[0].y + pointthree[2].y - pointthree[1].y );
            poly[2] = temp;
        }
        else if(angle1>angle2 && angle1 > angle3)
        {
            if(ccw1)
            {
                poly[1] = pointthree[1];
                poly[3] = pointthree[2];
            }
            else
            {
                poly[1] = pointthree[2];
                poly[3] = pointthree[1];
            }
            poly[0] = pointthree[0];
            Point temp(pointthree[1].x + pointthree[2].x - pointthree[0].x , pointthree[1].y + pointthree[2].y - pointthree[0].y );
            poly[2] = temp;
        }

        CvPoint2D32f trans[4];
        int temp = 50;
        trans[0] = Point2f(0+temp,0+temp);  
        trans[1] = Point2f(0+temp,100+temp);  
        trans[2] = Point2f(100+temp,100+temp);  
        trans[3] = Point2f(100+temp,0+temp);

        //获取透视投影变换矩阵
        CvMat *warp_mat = cvCreateMat(3, 3, CV_32FC1);
        cvGetPerspectiveTransform(poly, trans, warp_mat);

        //计算变换结果
        IplImage ipl_img(src_all);
        IplImage *dst = cvCreateImage(cvSize(1000, 1000), 8, 3);
        cvWarpPerspective(&ipl_img,dst,warp_mat);
        //=========================================

#ifdef DEBUG
        namedWindow("透视变换后的图");  
        cvShowImage("透视变换后的图",dst);         //透视变换后的图

        drawContours( drawingAllContours, contours, -1,  CV_RGB(255,255,255) , 1, 8);
        namedWindow("DrawingAllContours");  
        imshow( "DrawingAllContours", drawingAllContours );  

        namedWindow(pathtemp);  
        imshow(pathtemp , drawing );    //3个角点填充
#endif

        //接下来要框出这整个二维码  
        Mat gray_all,threshold_output_all;  
        vector<vector<Point> > contours_all;  
        vector<Vec4i> hierarchy_all;  
        cvtColor( drawing, gray_all, CV_BGR2GRAY );  

        threshold( gray_all, threshold_output_all, 45, 255, THRESH_BINARY ); 

        findContours( threshold_output_all, contours_all, hierarchy_all,  RETR_EXTERNAL, CHAIN_APPROX_NONE, Point(0, 0) );//RETR_EXTERNAL表示只寻找最外层轮廓  

        Point2f fourPoint2f[4];  
        //求最小包围矩形  
        RotatedRect rectPoint = minAreaRect(contours_all[0]);  

        //将rectPoint变量中存储的坐标值放到 fourPoint的数组中  
        rectPoint.points(fourPoint2f);  
        for (int i = 0; i < 4; i++)  
        {  
            line(src_all, fourPoint2f[i%4], fourPoint2f[(i + 1)%4],
                Scalar(20,21,237), 3);  
        }  

        namedWindow(pathtemp);  
        imshow(pathtemp , src_all ); 

        //截取二维码区域
        CvSize size= cvSize(200,200);//区域大小
        cvSetImageROI(dst,cvRect(0,0,size.width, size.height));//设置源图像ROI
        IplImage* pDest = cvCreateImage(size,dst->depth,dst->nChannels);//创建目标图像
        cvCopy(dst,pDest); //复制图像
        cvSaveImage("Roi.jpg",pDest);//保存目标图像

二维码的信息识别

二维码的信息识别使用的是zbar,一个开源的二维码识别库,经过测试,对图像进行平滑,灰度等处理后识别效率还是很高的。zbar的算法流程简介:http://blog.csdn.net/u013738531/article/details/54574262。

        //对截取后的区域进行解码
        Mat imageSource = cv::Mat(pDest); 
        cvResetImageROI(pDest);//源图像用完后,清空ROI
        cvtColor( imageSource, imageSource, CV_BGR2GRAY );  //zbar需要输入灰度图像才能很好的识别

        //Zbar二维码识别
        ImageScanner scanner;
        scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);   
        int width1 = imageSource.cols;        
        int height1 = imageSource.rows;        
        uchar *raw = (uchar *)imageSource.data;    

        Image imageZbar(width1, height1, "Y800", raw, width1 * height1);          
        scanner.scan(imageZbar); //扫描条码      
        Image::SymbolIterator symbol = imageZbar.symbol_begin();    
        if(imageZbar.symbol_begin()==imageZbar.symbol_end())    
        {    
            cout<<"查询条码失败,请检查图片!"<<endl;    
        }    

        for(;symbol != imageZbar.symbol_end();++symbol)      
        {        
            cout<<"类型:"<<endl<<symbol->get_type_name()<<endl;      
            cout<<"条码:"<<endl<<symbol->get_data()<<endl;         
        }

        imageZbar.set_data(NULL,0);    

程序运行结果

运行结果1:网站上生成的二维码,依次是原图,二值化,角点定位,旋转矫正,识别结果。
这里写图片描述

运行结果2:相机拍摄的名片上二维码,依次是灰度图,二值化,角点定位,透视矫正,识别结果。

这里写图片描述
本文程序中一些代码参考以下博客:
http://blog.csdn.net/nick123chao/article/details/77573675
http://blog.csdn.net/u010925447/article/details/77996455

本文用到的的程序和图片素材在csdn资源下载区,下载链接稍后会在评论区发布。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

二维码的特征定位和信息识别 的相关文章

  • 树莓派3b引脚图

    如上图所示 xff0c 我们可以很清楚的看到各个引脚的功能 例如我们想使用pwm引脚来控制舵机 xff0c 则我们可以考虑使用其中的 BCM18 PWM0 和 BCM13 PWM1 在使用wiringPi库时 xff0c 我们定义的引脚即B
  • 跟踪slab分配堆栈流程的方法(perf、systemtap)

    跟踪slab分配堆栈流程的方法 xff08 perf systemtap xff09 内存泄露是在解决内核故障会遇到的棘手情况 xff0c 根据具体的内存使用情况 xff0c 追踪相应slab cache的分配堆栈流程 xff0c 是追踪泄
  • prometheus+grafana监控mysql、canal服务器

    一 prometheus配置 1 prometheus安装 1 1官网下载安装包 xff1a https prometheus io download 1 2解压安装包 xff1a tar zxvf prometheus 2 6 1 lin
  • mac配置jmeter

    一 步骤 1 安装jdk1 8版本 xff0c 因为jmeter是基于java环境运行的 2 安装jmeter5 x版本 二 安装jdk 1 下载jdk Java Downloads Oracle 2 下载好之后安装 xff0c 全部下一步
  • 操作系统(四):动态链接与静态链接的区别

    在回答这个问题之前希望大家大概了解一个文件编译的过程 xff0c 比如一个C文件在编译成功后文件夹里的文件会有什么变化 xff0c 大家可以先去创建一个helloworld c的文件 xff0c 观察其编译后的变化 那么问题来了 面试官经常
  • 【OpenVINS】(一)ZUPT

    参考 xff1a Measurement Update Derivations Zero Velocity Update 在典型的自主汽车场景中 xff0c 传感器系统将在停止灯处变得静止 xff0c 其中动态物体 xff08 例如交叉路口
  • OpenVINS与MSCKF_VIO RK4积分对比

    VIO系统在使用IMU测量值进行状态预测时 xff0c 需要将连续时间的微分方程离散化为差分方程 xff0c 离散化的本质是积分 xff0c 根据数值积分近似程度不同 xff0c 常用的有欧拉法 中点法和四阶龙格库塔法等 xff0c Ope
  • 全盘拷贝linux系统,转移至另一硬盘

    首先制作ubuntu启动盘 xff0c 选择try ubuntu进入live ubuntu系统 查看需拷贝硬盘盘符 span class token function sudo span span class token function
  • EKF SLAM

    EKF 方法是解决 SLAM 问题的一种经典方法 xff0c 其应用依赖于运动模型和观测模型的高斯噪声假设 在 SLAM 问题首次提出不久后 xff0c Smith 和 Cheesman 及 Durrant Whyte对机器人和路标间的几何
  • 如何将立创EDA中的元器件的原理图/封装和3D模型导入AD的库中

    如何将立创EDA中的元器件的原理图 封装和3D模型导入AD的库中 工具 xff1a AD 立创EDA专业版 fusion360 或其他3D软件 导入原理图 封装 在立创商城复制所需元器件的编号 打开立创EDA标准版或专业版 xff0c 这里
  • Xshell 提示 “要继续使用此程序,您必须应用最新的更新或使用新版本“的解决方案

    要想解决Xshell提示更新最新版问题 有两种方案 方案一 手动修改系统时间 步骤如下 右键右下角时间 弹出如下窗口 2 选中 调整日期 时间 A 并点击 弹出如下页面 更改时间 更改成之前的年份 如下图 更改成功后 再打开相应的应用 Xs
  • 2020.2.22 排位赛 G - Bucket Brigade(BFS)

    Bucket Brigade 题面 题目分析 BFS模板题 代码 span class token macro property span class token directive keyword include span span cl
  • Canal入门(二)

    Canal入门 xff08 二 xff09 canal kafka quickStart 1 基本说明 canal 1 1 1版本之后 默认支持将canal server接收到的binlog数据直接投递到MQ 目前默认支持的MQ系统有 ka
  • PID调节三个参数的作用

    1 比例调节作用 xff1a 按比例反应系统的偏差 系统一旦出现了偏差 比例调节立即产生调节作用用以减少偏差 比例作用大 可 以加快调节 能迅速反应误差 xff0c 从而减小稳态误差 但是 xff0c 比例控制不能消除稳态误差 过大的比例
  • (centos7)docker+jenkins运行python自动化

    目录 一 实现思路 二 环境准备 1 在liunx上安装docker 2 docker安装jenkins 三 访问前设置 四 配置jenkins容器 五 jenkins插件安装 1 安装git 2 安装docker 3 html Publi
  • OJ在线编程常见输入输出练习

    OJ在线编程常见输入输出练习 4 a 43 b 4 输入描述 xff1a 输入数据包括多组 每组数据一行 每行的第一个整数为整数的个数n 1 lt 61 n lt 61 100 n为0的时候结束输入 接下来n个正整数 即需要求和的每个正整数
  • js中数组与集合的相互转化

    数组 gt 集合 var a 61 1 2 3 4 5 5 var set 61 new Set a console log set 1 2 3 4 5 集合 gt 数组 var set 61 new Set set add 1 set a
  • Linux make/Makefile详解

    会不会写makefile xff0c 从侧面说明了一个人是否具备完成大型工程的能力 一个工程中的源文件不计数 xff0c 其按类型 功能 模块分别放在若干个目录中 xff0c makefile定义了一系列的 规则来指定 xff0c 哪些文件
  • 大疆H20系列吊舱,录制的视频含义

随机推荐

  • 写算法的方法

    写算法步骤 xff1a xff08 以下方法 xff0c 都是老生常谈 但是非常简单有用 xff09 数据结构 xff08 所有的算法都是基于数据结构的操作 所有算法都是针对数据结构的属性进行操作 列出所有的属性 xff0c 写算法逐项修改
  • Windows系统下QT+OpenCasCAD仿真开发

    背景 最近开发了一个六自由度机械臂调姿平台的控制软件 xff0c 集成了API激光跟踪仪和KUKA机器人 xff0c 实现了根据产品的测量位姿驱动仿真环境中模型并且实现模型间的碰撞检测 其中KUKA机器人的控制可以参考笔者以前的博客 xff
  • 飞控IMU姿态估计流程

    飞控中使用加速度计 xff0c 陀螺仪 xff0c 磁罗盘进行姿态估计算法流程 step1 xff1a 获取陀螺仪 xff0c 加速度计 xff0c 磁罗盘的原始数值 step2 xff1a 陀螺仪 xff0c 加速度计减去固定的偏移后得到
  • 图拓扑关系可视化的qt实现

    前言 最近在做数据可视化的相关工作 xff0c 包括曲线图 xff0c 航迹图 xff0c 图结构 xff0c 树结构等 其中树结构相关的工作笔者以前曾经做过 xff0c 可以参考笔者以前的博客 qt自定义树形控件之一和qt自定义树形控件之
  • 基于qwt3D 的3D航迹图的实现

    前言 使用qt实现三维空间直角坐标系中的航迹实时绘制网上很难查到资料 在qt下实现3D绘图通常实现方式有OpenGL VTK qwt3d QtDataVisualization等 Qcharts QCustomPlot只支持2D绘图 这里给
  • 树莓派4b连接RealSense T265

    使用的是树莓派4 8G版本 准备连接RealSense T265的双目相机 T265目前官方编译好的的只有Ubuntu16和18 其他的系统版本需要自己编译realsense驱动 安装ubuntu20 10 https ubuntu com
  • Dockerfile文件解释

    一 先来看一个简单的 Dockerfile 这个Dockerfile作用是打一个python3项目环境 FROM python 3 alpine WORKDIR app ADD app RUN pip3 install r requirem
  • 一文读懂BLOB算法

    算法执行效果 相关参考资料 看着玩的 BLOB算法简述 https blog csdn net icyrat article details 6594574 话说这老哥写的也太 简 了吧 完全口水话 把blob算法说的很神秘 说什么把blo
  • Sobel算法优化 AVX2与GPU

    国庆假期 一口气肝了10篇博客 基本上把最近的成果都做了遍总结 假期最后一天 以一个比较轻松的博客主题结束吧 这次是Sobel算法的AVX2优化 执行效果 sobel算法的原理 使用如下的卷积核 c 硬写 span class token
  • 随机Hough直线算法的改进

    背景介绍 随机Hough直线算法相比Hough直线算法 xff0c 算法效率会有提高 xff0c 但仍不能满足工程需求 因此提出使用生长的随机Hough直线算法 该算法对随机Hough直线算法进行改造 xff0c 在随机选点转到Hough空
  • MATLAB编写的读取.mat文件数据并画曲线图的gui程序

    matlab编写的读取sd卡数据的gui程序 界面截图 xff1a 打开文件界面 xff1a 导入数据后截图 xff1a 是不是高端大气上档次 xff0c 不要急 xff0c 慢慢往下看 xff0c 后面更精彩 xff0c 代码会贴出来的
  • px4飞控位置估计lpe移植到vs

    本文主要内容 px4飞控的位置估计有两种方式 xff0c 一是inav xff0c 二是lpe xff0c 用到的传感器用加速度计 xff0c 磁场传感器 xff0c gps xff0c 超声 xff0c 激光 xff0c 气压 xff0c
  • 常见的信号平滑处理方法

    本文介绍了常见的信号平滑处理方法 xff1a xff08 一阶滤波 xff0c 互补滤波 xff0c 卡尔曼滤波 xff09
  • PX4代码学习系列博客(1)——开发环境配置

    写在前面 虽然有很多关于px4博客 xff0c 但还是想自己亲手写 xff0c 一来记录自己的学习过程 xff0c 以备将来复习 xff0c 二来方便后来者参考学习 xff0c 好多西当然要大家分享 关于px4飞控程序的博客 xff0c 我
  • PX4代码学习系列博客(3)——px4固件目录结构和代码风格

    写在前面 px4不是普通的单片机程序 xff0c 其中没有main函数 它实际上是一个操作系统 xff0c 上面运行着很多应用程序 xff08 类比windows xff09 xff0c 比如姿态解算 xff0c 位置解算 xff0c 姿态
  • PX4代码学习系列博客(5)——在px4中添加自己的模块

    怎么在px4中添加自己的模块 在 px4固件目录结构和代码风格 这一节 xff0c 曾经说过NuttX是一个实时的嵌入式系统 xff0c 上面可以像windows那样运行程序 那既然是应用程序 xff0c 那我们应该也能写一些可以在Nutt
  • PX4代码学习系列博客(6)——offboard模式位置控制代码分析

    分析offboard模式的代码需要用到以下几个模块 local position estimator mavlink mc pos control mc att control mixer 程序数据走向 mavlink 一般的offboar
  • selenium安装

    一 安装webdriver 1 下载安装包 下载地址 xff1a CNPM Binaries Mirror 注意 xff1a 下载版本应与自己的chrome的大版本一致 chrome版本查看 xff0c 设置 gt 关于chrome xff
  • 基于惯性轮倒立摆原理的自行车

    背景 自平衡车有很多种 xff0c 其中一种是利用惯性轮倒立摆原理 xff0c 早在2003年 xff0c 日本的村田顽童就已经问世 xff0c 它采用的就是惯性轮倒立摆原理 后来其他研究组织和个人纷纷效仿 xff0c 制作出了五花八门的基
  • 二维码的特征定位和信息识别

    二维码的特征定位和信息识别 背景介绍 视觉的方法可以用来估计位置和姿态 最容易想到的是在目标上布置多个容易识别的特征 xff0c 这样使用opencv相机标定和 相机畸变矫正 轮廓提取 solvepnp来获取目标相对于相机的位姿 在实际使用