PnP 单目相机位姿估计(三):二维码角点检测

2023-05-16

      • 解PnP问题时用二维码的好处
      • 二维码识别的流程
      • 代码
      • 最后


IDE:visual studio 2013
使用库:Eigen opencv2.4.9
文档版本:1.0


解PnP问题时,用二维码的好处

  1. 二维码由黑白两色组成,容易通过对图像阈值处理而发现
  2. 二维码具有方向性(只要设计的不为中心对称),可以更好的辅助求解位姿
  3. 二维码具有可识别性,即可解析二维码内部黑白块的排列顺序,从而确定该二维码是否为我们所要用的二维码

二维码识别的流程

这里写图片描述

该流程以该二维码为例

  1. 阈值处理,二值化操作
  2. 去掉二维码周围一圈,即保存为5*5的信息
  3. 计算5*5图像内的海明距离,和程序所设定要查找的二维码的海明距离作比较
  4. 若该二维码即为程序所要查找的二维码,则用opencv自带的findContours查找角点

代码

#include "Marker.h"

/************************************************构造函数****************************************************/
Marker::Marker(): id(-1)
{
}

/************************************************析构函数****************************************************/
Marker::~Marker() 
{
}

/*******************************************读取二维码内含信息**********************************************/
int Marker::getMarkerId(cv::Mat &markerImage, int &nRotations)
{
    assert(markerImage.rows == markerImage.cols);
    assert(markerImage.type() == CV_8UC1);

    cv::Mat grey = markerImage;
    //threshold image
    cv::threshold(grey, grey, 125, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);

    //Markers  are divided in 7x7 regions, of which the inner 5x5 belongs to marker info
    //the external border should be entirely black
    //去掉周围的一圈黑色,提取出5x5的网格
    int cellSize = markerImage.rows / 7;

    for (int y = 0; y<7; ++y)
    {
        int inc = 6;
        //for first and last row, check the whole border
        if (y == 0 || y == 6) inc = 1;
        for (int x = 0; x<7; x += inc)
        {
            int cellX = x * cellSize;
            int cellY = y * cellSize;
            cv::Mat cell = grey(cv::Rect(cellX, cellY, cellSize, cellSize));
            //imshow("cell",cell);
            int nZ = cv::countNonZero(cell);
            //cout<<"nZ"<<nZ<<endl;
            //cout<<"(cellSize*cellSize) / 2"<<" "<<(cellSize*cellSize) / 2<<endl;
            if (nZ >(cellSize*cellSize) / 2)
            {
                //can not be a marker because the border element is not black!
                return -1;
            }
        }
    }

    //将图像标记信息存放在一个 5x5 的 Mat 中
    cv::Mat bitMatrix = cv::Mat::zeros(5, 5, CV_8UC1);

    //get information(for each inner square, determine if it is  black or white)  
    for (int y = 0; y<5; ++y)
    {
        for (int x = 0; x<5; ++x)
        {
            int cellX = (x + 1)*cellSize;
            int cellY = (y + 1)*cellSize;
            cv::Mat cell = grey(cv::Rect(cellX, cellY, cellSize, cellSize));

            int nZ = cv::countNonZero(cell);
            if (nZ>(cellSize*cellSize) / 2)
                bitMatrix.at<uchar>(y, x) = 1;
        }
    }

    //cout<<"bitMatrix:"<<" "<<bitMatrix<<endl;
    //check all possible rotations
    //因为会有4种放置方向
    cv::Mat rotations[4];
    //海明距离
    int distances[4];

    rotations[0] = bitMatrix;
    distances[0] = hammDistMarker(rotations[0]);

    std::pair<int, int> minDist(distances[0], 0);

    for (int i = 1; i<4; ++i)
    {
        //get the hamming distance to the nearest possible word
        rotations[i] = rotate(rotations[i - 1]);//逆时针转90度
        distances[i] = hammDistMarker(rotations[i]);

        if (distances[i] < minDist.first)
        {
            minDist.first = distances[i];
            minDist.second = i;
        }
    }
    //cout<<"minDist"<<" "<<minDist.first<<" "<<minDist.second<<endl;
    //cout<<"mat2id(rotations[minDist.second]):"<<" "<<mat2id(rotations[minDist.second])<<endl;
    nRotations = minDist.second;
    //819//1100110011
    if (minDist.first == 0)
    {
        return mat2id(rotations[minDist.second]);
    }
    return -1;
}

/*****************************************Maker初始的坐标数据**********************************************/
int Marker::hammDistMarker(cv::Mat bits)
{
    //maker  1
    int ids[5][5] =
    {
        { 1, 1, 1, 1, 1 },
        { 1, 1, 0, 1, 1 },
        { 1, 0, 1, 0, 1 },
        { 1, 1, 1, 1, 1 },
        { 1, 1, 0, 1, 1 }
    };

    //maker 2
    int ids_1[5][5] =
    {
        { 1, 1, 1, 1, 1 },
        { 1, 1, 0, 1, 1 },
        { 1, 0, 1, 1, 0 },
        { 1, 1, 0, 1, 1 },
        { 1, 1, 1, 1, 1 }
    };

    int dist = 0;

    for (int y = 0; y<5; ++y)
    {
        float minSum = 1e5; //hamming distance to each possible word
        for (int p = 0; p<5; ++p)
        {
            float sum = 0;
            //now, count
            for (int x = 0; x<5; ++x)
            {
                sum += bits.at<uchar>(y, x) == ids[p][x] ? 0 : 1;
            }
            if (minSum>sum)
                minSum = sum;
        }
        //do the and
        dist += minSum;
    }

    return dist;
}

/*********************************************计算二维码信息*************************************************/
int Marker::mat2id(const cv::Mat &bits)
{
    int val = 0;
    for (int y = 0; y<5; ++y)
    {
        val <<= 1;
        if (bits.at<uchar>(y, 1)) val |= 1;
        val <<= 1;
        if (bits.at<uchar>(y, 3)) val |= 1;
    }
    return val;
}

/********************************************CV图像旋转函数*************************************************/
cv::Mat Marker::rotate(cv::Mat in)
{
    cv::Mat out;
    in.copyTo(out);
    for (int i = 0; i<in.rows; ++i)
    {
        for (int j = 0; j<in.cols; ++j)
        {
            out.at<uchar>(i, j) = in.at<uchar>(in.cols - j - 1, i);
        }
    }
    return out;

}

/*****************************************Maker初始的坐标数据**********************************************/
bool operator<(const Marker &M1, const Marker&M2)
{
    return M1.id<M2.id;
}


最后

相关文章
solvepnp三维位姿估算
PnP 单目相机位姿估计(一):初识PnP问题
PnP 单目相机位姿估计(二):solvePnP利用二维码求解相机世界坐标

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

PnP 单目相机位姿估计(三):二维码角点检测 的相关文章

  • 毕业后就是程序员——我的阿里、金山、中华、腾讯、360、网易面试总结(三)

    接着上篇 xff0c 这篇侧重于具体的笔试 面试的问题 xff0c 至于是哪个公司的就不去追究了 xff0c 但一定是经常问到的 xff0c 而且我嵌入式系统工程师和移动开发工程师都参与了 xff0c 问题要区别看待 xff0c 那么自然就
  • 你投资的那些EOS“侧链”都还好么?

    EOS侧链BOS的启动声势浩大 xff0c 引得一众EOS超级节点与公司参与支持 xff0c 也招来币圈大佬老猫的质疑 xff0c 直言 熊市 xff0c 我劝你善良 xff1b 近几日 xff0c 曾被称作是EOS上首条侧链的FIBOS开
  • 销毁3417万枚EOS与被刺激的EOS价格——理解增发与销毁机制

    eosio saving帐号销毁的3417万枚EOS与REX锁住的6000多万枚EOS xff0c 都刺激不了EOS价格 xff0c 甚至仍有下跌的趋势 xff0c 而几天后一觉醒来 xff0c 不管BTC还是EOS都在疯涨 xff0c 过
  • Error executing aapt: Return code -1073741819

    总会有让人喷血的事情勾起写博客的欲望 xff0c 希望能坚持 折腾了两天的是个小问题 xff0c 就是标题上的Error executing aapt Return code 1073741819 解决的方法也很简单参考1中所述 xff0c
  • EOS的危险信号——记主网上线一周年后

    市值已经跌落到第八 xff0c 除了期待即将推出的社交应用 Voice 能给 EOS 注入新的活力外 xff0c 我已经很难找到 EOS 上的新热点 xff0c 而一些危险的信号 xff0c 可能对 EOS 的发展带来负面的影响 xff0c
  • 五轴机械臂实现视觉抓取--realsense深度相机和五自由度机械臂

    前言 xff1a 要实现视觉抓取 xff0c 首先需要实现机械臂的驱动 xff0c 深度相机的目标识别 xff0c 能够反馈位置 1 实现机械臂在ROS层的控制 2 基于深度相机目标物体的空间坐标反馈 xff0c 需要知道摄像头中物体的像素
  • solvepnp三维位姿估算

    一 前言 关于PNP问题就是指通过世界中的N个特征点与图像成像中的N个像点 xff0c 计算出其投影关系 xff0c 从而获得相机或物体位姿的问题 opencv提供的solvepnp函数就是用来解决pnp问题 利用该函数可以实现测算相机 物
  • emwin自定义颜色

    颜色管理中已经帮助我们定义了这些颜色 xff0c 但是我们通常会使用自定义的颜色 xff0c 怎么怎么设置值呢 xff1f 通常情况下使用的是BGR颜色 就是蓝色和红色是相反的 GUI SetBkColor 0x00FFaa80 自定义调色
  • STemwin 实现滑动切换主页 滑动翻页 滑动解锁功能

    STM32上实现类似iPhone的解锁和滑屏功能 xff0c emwin这个库官方的文档中控件没有一样的 xff0c 但是有一个上下滑动的 xff0c 基本上能够完成大致上的功能 xff0c 但是如果想使用emwin实现类似的效果的话 xf
  • freeRTOS中断简介

    目录 参考材料 中断简介 中断管理简介 优先级分组定义 正点原子freertos手册 优先级设置 用于中断屏蔽的特殊寄存器 primask暂时屏蔽中断寄存器 xff08 RT THREAD使用 xff09 faultmask寄存器 base
  • 【01】初识ThreadX

    目录 简介 微内核 资料链接 入门索引 简介 ThreadX是一个成熟的商用硬实时嵌入式操作系统 xff0c 被广泛应用于消费电子 航空航天 通信 工业控制与医疗等应用领域中 xff0c 至今已服务超过62亿设备 它以轻量级的规模 xff0
  • [解决方案] VNC Viewer 连接灰屏问题 (能够连接上,但全是灰点,没有任何菜单、按钮,鼠标变为x)

    解决方案 VNC Viewer 连接灰屏问题 xff08 能够连接上 xff0c 但全是灰点 xff0c 没有任何菜单 按钮 xff0c 鼠标变为x xff09 情况1情况2情况3 情况1 登陆VNCviewer可能会发现服务器的mate桌
  • VNC Viewer 10061, connection refused

    在Windows系统下用VNC Viewer去连接Linux系统的VNC Server xff0c 双方都可ping通 xff0c 但是VNC Viewer连接不上 xff0c 显示connection refused 10061 xff0
  • 现代C++语言(C++11/14/17)特性总结和使用建议(一)

    C 43 43 语言在历史上经过了很多次的演进 最早的时候 xff0c C 43 43 语言没有模板 STL 异常等特性 xff0c 之后加入这些特性形成大多数人所熟悉的C 43 43 98 03标准 在此之后 xff0c C 43 43
  • 现代C++语言(C++11/14/17)特性总结和使用建议(二)

    override和final成员函数 以前C 43 43 中虚函数没有一个强制的机制来标识虚函数会在派生类里被改写 vitual关键字是可选的 xff0c 这使得阅读代码变得很费劲 因为可能需要追溯到继承体系的源头才能确定某个方法是否是虚函
  • 高通芯片方案的Wi-Fi6路由器汇总和推荐

    2017年 xff0c 高通宣布推出端到端的802 11ax产品组合 xff0c 其中包括用于网络基础设施的IPQ 8074 SoC 用于客户端设备的QCA 6290解决方案 xff0c 这让高通公司成为第一家宣布支持802 11ax的端到
  • (十)嵌入式:使用TCP协议实现图传

    这段时间做了通信相关的项目 xff0c 需要用到无线图传 xff0c 因此想到了用TCP协议实现 废话不多说 xff0c 直接上代码 xff1a 服务器端 xff1a include lt stdlib h gt include lt st
  • PnP 单目相机位姿估计(一):初识PnP问题

    简介理解更多 IDE xff1a visual studio 2013 使用库 xff1a Eigen opencv2 4 9 文档版本 xff1a 1 1 简介 PnP问题是求解3D 2D点对运动的方法 他描述了当知道n个三维空间点坐标及
  • 多传感器融合中的时间同步2-论文阅读

    文章目录 前言主要内容pps对于INS时间戳校准作用原理 测试结果参考文献 前言 阅读硕士论文 GPS INS组合导航系统研究及实现 xff0c 该论文第5章为时间同步系统设计 xff0c 为GPS INS系统设计的时间同步系统部分内容非常
  • PSINS源码阅读—STIM300/GNSS组合导航

    文章目录 前言代码解读主要框架代码阅读主要脚本sinsgps函数 结果测试 前言 严老师最近在PSINS网站上上传了一组STIM300 GNSS跑车数据 xff0c 并且有光纤惯导数据作为真值参考 xff0c 网站是一组STIM300 GN

随机推荐

  • mpu6500-gnss组合导航代码分析

    文章目录 前言代码分析调参P矩阵陀螺仪偏置P矩阵加速度计偏置P矩阵 前言 导航数据为如下链接 xff0c 数据集使用了低成本Mems器件MPU6500和GNSS做组合导航 代码运行需要严老师psins210406组合导航函数库的支持 xff
  • Java中数组元素的删除

    这是一个LeetCode的简单题 xff0c 在二刷做过的题时突然感觉这个题真的是非常的不错 xff0c 虽然是个简单题 xff0c 没有什么技巧 xff0c 但是写代码的过程中有很多要注意的点 xff0c 感觉还是很考验基本功 xff0c
  • 【视觉里程计】对极几何,三角测量,PnP,ICP原理

    老早就想写些东西 xff0c 但是介于个人懒惰 xff0c 一直没开这个头 xff0c 前几天才发现自己以前学的东西很容易忘记 xff0c 于是决定还是将学习做个总结 xff0c 以便后续回头查看 xff0c 温故而知新嘛 此文章为对相关知
  • Java泛型--泛型应用--泛型接口、泛型方法、泛型数组、泛型嵌套

    1 泛型接口 1 1泛型接口的基本概念 1 2泛型接口实现的两种方式 定义子类 xff1a 在子类的定义上也声明泛型类型 interface Info lt T gt 在接口上定义泛型 public T getVar 定义抽象方法 xff0
  • Linux下调试段错误的方法[Segmentation Fault]--GDB

    原文 1 段错误是什么 xff1f 段错误是指访问的内存超出了系统给这个程序所设定的内存空间 xff0c 例如访问了不存在的内存地址 访问了系统保护的内存地址 访问了只读的内存地址等等情况 A segmentation fault ofte
  • linux驱动开发--copy_to_user 、copy_from_user函数实现内核空间数据与用户空间数据的相互访问

    设备读操作 如果该操作为空 xff0c 将使得read系统调用返回负EINVAL失败 xff0c 正常返回实际读取的字节数 ssize t read struct file filp char user buf size t count l
  • 函数中的形式参数和实际参数

    1 举例 xff1a 使用函数交换两个整形变量的值 运行结果 xff1a 分析 xff1a c语言中实际参数和形式参数之间采用值传递的方式来传递数据 在被调函数中 xff0c 使用的是实际参数的一个拷贝数据 我们在swap函数中交换了a和b
  • Linux 线程挂起与唤醒功能 实例

    pthread cond wait 多线程的条件变量 条件变量是利用线程间共享的 全局变量进行同步的一种机制 xff0c 主要包括两个动作 xff1a 一个线程等待 34 条件变量的条件成立 34 而挂起 xff1b 另一个线程使 34 条
  • PnP 单目相机位姿估计(二):solvePnP利用二维码求解相机世界坐标

    前言原理简介输入参数准备 1 objectPoints特征点世界坐标2 imagePoints特征点在摄像头下的像素点坐标3cameraMatrixdistCoeffs内参矩阵和畸变矩阵 相机世界坐标的求解 1求世界坐标中的点在相机坐标系下
  • Linux下socket编程,附带tcp例子

    1 网络中进程之间如何通信 xff1f 本地的进程间通信 xff08 IPC xff09 有很多种方式 xff0c 但可以总结为下面4类 xff1a 消息传递 xff08 管道 FIFO 消息队列 xff09 同步 xff08 互斥量 条件
  • 程序员加班到深夜,你经历过没?

    我看到了自己的影子啊 虽然自己非科班出身 xff0c 学历也不高吧 xff0c 但是自认为还是很努力的 xff0c 但是为什么现在的工资水平却跟应届生差不多呢 xff1f xff08 xff09 仔细想想 xff0c 自己毕业3年了 xff
  • 【C/C++学院】(16)QT版:幸运大抽奖

    程序效果 xff1a ifndef DIALOG H define DIALOG H include lt QDialog gt include lt QLabel gt include lt QPushButton gt include
  • 【Python基础】--Pickle/函数默认参数/函数的参数*args/Bytes<=>str/32-64bit/bytes对象

    Pickle gt gt gt import pickle gt gt gt my list 61 1 2 3 39 haha 39 39 and 39 39 or 39 gt gt gt pickle file 61 open 39 my
  • Windows平台python操作串口示例,可以加工下,改写成方便的测试软件

    在 windows中 xff0c 使用 Python 进行串口编程需要安装一个 Serial 模块 pyserial xff1a 下载地址 https pypi python org pypi pyserial下载完成后得到一个 pyser
  • 告别csdn一年了

    原本坚持了4年的学习 xff0c 整理笔记 xff0c 在csdn平台上进行发表 xff0c 记录 同朋友们互动 xff0c 探讨进行学习 xff0c 自己也在不断地成长 今天再次进入博客页面 xff0c 发现界面来了个大改版 xff0c
  • php视频课程

    php视频课程 xff1a 下载地址 xff1a http php itcast cn php video shtml 注 xff1a 此系列视频 xff0c 韩顺平主讲 1 php入门到精通教程 2 第二版mysql视频教程 进行中 3
  • pixhawk ulg转csv

    ulg是目前最新版px4固件生成的log格式 xff0c 下载最新版的flightplot即可对内部数据进行预览分析 xff0c flightplot中支持部分函数和运算符操作 xff0c 但对带 数据的操作不支持 xff0c 如需要对某些
  • 将Kinetic中的Gazebo7升级为Gazebo9

    将Kinetic中的Gazebo7升级为Gazebo9 一 查看所有gazebo7的相关包二 卸载当前已安装的gazebo相关包三 添加源四 安装新版本gazebo五 安装gazebo ros pkgs六 后记 官方教程 http gaze
  • 你真的了解串口 (Serial)吗?

    一 串口的定义 串口 xff0c 全称串行通信接口或串行通讯接口 xff0c 是一种常用于电子设备间通讯的全双工扩展接口 xff1b 串行通信 xff0c 串口通讯的技术基础 xff0c 指一位一位地按顺序传送数据 其特点是线路简单 xff
  • PnP 单目相机位姿估计(三):二维码角点检测

    解PnP问题时用二维码的好处二维码识别的流程代码最后 IDE xff1a visual studio 2013 使用库 xff1a Eigen opencv2 4 9 文档版本 xff1a 1 0 解PnP问题时 xff0c 用二维码的好处