数字图像处理之二维码图像提取算法(十一)

2023-11-13


// check ratio requirement b:w:b:w:b = 1:1:3:1:1
bool qr_checkRatio()
{
    totalFinderSize = 0;    
    for(int i =0;i<5; i++)
    {
        int count = stateCount[i];
        totalFinderSize += count;
        if(count == 0)
            return false;
    }
    if(totalFinderSize<7)
        return false;

    int moduleSize = ceil(totalFinderSize / 7.0); // scale factor of the finder
    
    // tolerate some "slop" of the ratio
    double maxVariance = moduleSize*tol_factor;
    bool retVal = ((abs(moduleSize - (stateCount[0]))< maxVariance) &&
    (abs(moduleSize - (stateCount[1]))< maxVariance) &&
    (abs(3*moduleSize - (stateCount[2]))< 3*maxVariance) &&
    (abs(moduleSize - (stateCount[3]))< maxVariance) &&
    (abs(moduleSize - (stateCount[4]))< maxVariance));

    return retVal;
}

以上代码就是判断是否为一个块。这个探测图像的比例为(1:1:3:1:1),计算出每个模块的平均宽度。差值不能超过0.5,这个tol_factor=0.5。如果满足这个条件那么就是我们所需找的一个定位点。


/* group possible finder locations, that is, each location vote in an array, so that 
we can find three largest votes, calculate the mean location of these three groups and
finally draw them on the image
*/
void group_points(vector<Point>& points)
{
    
   CvScalar red = CV_RGB(255,0,0);
    /* if the size of vector, number of possible finder locations is greater than 3,
    we need to group them. if not, then just draw them on the image
    */
    if (points.size()>= 3)
    {
        double distance;
        vector<vector<Point>> group(points.size());// every vector stores the finder locations which belong to one group
        vector<int> score(points.size());// store the number of votes
        vector<int> score_index(points.size());// store the index of score when we sort the score
        int temp1;
        int temp2;

        // set values for score_index
        for(size_t k=0; k < points.size();++k)
        {
            score_index[k] = k;
        }

        /* group the points by distance
        check whether point i is near enough to point j (j<i), if so, then vote for j.
        No matter whether i is near to j or not, it will vote for itself
        */
        for(size_t i = 0; i < points.size(); ++i)
        {
            for (size_t j=0; j < i; ++j)
            {
                distance = sqrt(double((points[i].x-points[j].x)*(points[i].x-points[j].x)+(points[i].y-points[j].y)*(points[i].y-points[j].y)));
                if (distance < tol_distance)
                {
                    score[j] += 1;
                    group[j].push_back(points[i]);
                    break;
                 }
             }
             score[i] += 1;
             group[i].push_back(points[i]);
         }


        // sort the score and write new index into score_index
         for(size_t m = 0; m < points.size()-1; ++m)
         {
            for(size_t n = m; n < points.size(); ++n)
            {
               if (score[m]<=score[n])
               {
                temp1 = score_index[m];
                score_index[m] = score_index[n];
                score_index[n] = temp1;
                temp2 = score[m];
                score[m] = score[n];
                score[n] = temp2;
                }
            }
         }

         // calculate the mean location of three groups with largest votes
         vector<Point>::iterator it;
         for (it = group[score_index[0]].begin(); it != group[score_index[0]].end(); ++it)
         {
             qr_point1 += (*it);
         }
         qr_point1.x = qr_point1.x/score[0];
         qr_point1.y = qr_point1.y/score[0];

         for (it = group[score_index[1]].begin(); it != group[score_index[1]].end(); ++it)
         {
             qr_point2 += (*it);
         }
         qr_point2.x = qr_point2.x/score[1];
         qr_point2.y = qr_point2.y/score[1];

         for (it = group[score_index[2]].begin(); it != group[score_index[2]].end(); ++it)
         {
            qr_point3 += (*it);
         }
         qr_point3.x = qr_point3.x/score[2];
         qr_point3.y = qr_point3.y/score[2];

         // output the final finder center location      
         cout<<qr_point1<<endl;
         cout<<qr_point2<<endl;
         cout<<qr_point3<<endl;
         draw_crosshair(qr_point1,src,red);
         draw_crosshair(qr_point2,src,red);
         draw_crosshair(qr_point3,src,red);
    }
    else
    {
        for(int v = 0; v < points.size(); ++v)
        {
            draw_crosshair(points[v],src,red);
        }
    }

}

使用这种算法可能会找到很多这样的点,那么需要把一堆的点进行一个均值化处理。这样得到的结果更加精确!其实这个已经写得比较复杂,其实做的事情就是把一些点根据它的范围把它归类再求均值!


//draw a red crosshair on some point of the image
void draw_crosshair(Point qr_point,Mat src,CvScalar color)
{
    Point up1,up2;
    up1.x = qr_point.x;
    up1.y = qr_point.y -2;
    up2.x = qr_point.x;
    up2.y = qr_point.y +2;
    Point down1,down2;
    down1.x = qr_point.x -2;
    down1.y = qr_point.y;
    down2.x = qr_point.x + 2;
    down2.y = qr_point.y;
    // draw two lines that intersects on qr_point
    line(src,up1,up2,color,1,8);
    line(src,down1,down2,color,1,8);
}

这个函数是用于找到QR码三个点之后,把它在图片上标记出来

line( CvArr* img,CvPoint pt1, CvPoint pt2, CvScalar color,int thickness=1, int line_type=8, int shift=0 );

第一个参数img:要划的线所在的图像;第二个参数pt1:直线起点;第二个参数pt2:直线终点;第三个参数color:直线的颜色 e.g:Scalor(0,0,255);第四个参数thickness=1:线条粗细;第五个参数line_type=8, 8 (or 0) - 8-connected line(8邻接)连接 线。4 - 4-connected line(4邻接)连接线。CV_AA - antialiased 线条。第六个参数:坐标点的小数点位数。


至于怎么找这些点计算其个数,请看我下一篇BLOG!


注意点:

release():这个函数是用于自己定义的指针,分配了内存,那么要自己释放。

cvDestroyWindow,该函数为开放计算机视觉(OpenCV)库库函数之一,用来销毁一个窗口。

waitKey():waitKey仅对窗口机制起作用,即namedWindow产生的窗口。若在此之前没有产生窗口,则waitKey无用。waitKey(10)是等待10ms,在此期间按下按钮则会返回按下的键值。waitKey(0)就是无限等待,直到有按键。另外,在imshow之后如果没有waitKey语句则不会正常显示图像。



 


        


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

数字图像处理之二维码图像提取算法(十一) 的相关文章

  • 二维码 ThoughtWorks.QRCode 之 index was outside bounds of the array

    最近在使用ThoughtWorks QRCode过程中 单独生成一个二维码没有出现过问题 在重复利用QRCodeEncoder生成二维码的过程中 会出现index was outside bounds of the array错误 经过调试
  • 微信小程序生成二维码

    微信小程序生成二维码 官网api 先请求得到access token wx request url https api weixin qq com cgi bin token grant type client credential app
  • 二维码名片的格式 - vcard

    二维码名片的格式 vcard 如果你希望生成的二维码名片可以被智能设备识别 并可以直接导入到通讯录中 那么就应遵循某种标准格式 常见的是生成vcard标准格式 一个简单的vcard名片格式例子参考如下 BEGIN VCARD VERSION
  • 数字图像处理之配置opencv中遇到的问题

    现在网络上有很多的教程 上面有配置opnecv的教程有很多 综合其中的优点便可以配置成功 参考教程 配置系统变量 http wenku baidu com link url 8J6XO19h3dncpZRXgAY JBmpsgVsNtZEs
  • Algorithm Accumulation

    目标检测 DPM HOG SIFT 最优匹配 DTW HMM 优化入门 爬山算法 退火算法 遗传算法 多目标优化 ILP 复杂度 NP完全问题 这篇博客就用来积累学过的一些比较好的算法 现开始觉得算法真是一个宝啊 目标检测 DPM 参考博客
  • 基于Zxing的二维码生成和二维码扫描

    最近又在倒腾二维码 发现网上的教程都不够用 所以把之前整合的二维码Demo有拿出来重新添加些功能 这里也算是重新学习吧 当然对于二维码 相信大家都很熟悉了 这里就不多说 本项目是基于Zxing的开源项目开发的 这里用的Demo是之前网上搜的
  • 数字图象处理之二维码图像提取算法(六)

    整体的框图如下所示 Hough 变换是图像空间和参数空间之间的一种变换 利用点与线的对偶性 将原始图像空间的给定曲线变为参数空间的一个点 这样直线的检测就变为参数空间中峰值的检测 接下来来了解一下霍夫变换 可以证明 直角坐标系p 0中的一条
  • java批量生成二维码图片,并打包成ZIP

    最近开发遇到了一个批量打印二维码并生成zip包的需求 先记录下来 pom依赖
  • 数字图象处理之二维码图像提取算法(五)

    在预处理之后 接下来就要进行码字提取 在码字提取部分 我们采用的就是霍夫 Hough transform 变换 通过霍夫变换我们可以知道整个二维码倾斜的角度 然后我们就可以进行二维码的矫正 霍夫变换具体如下 采用分级的Hough变换方法 不
  • Qt + QR-Code-generator 生成二维码

    0 前言 之前使用 libgrencode 生成二维码 LGPL 协议实在不方便 所以需要找一个 github 星星多的 代码简单最好 header only 协议最好是 MIT 或者兼容协议而不是 GPL 或者 LPGL QR Code
  • Zxing和QR CODE 生成与解析二维码实例(普通篇)

    首先下载对应的jar包 本实例用的是Zxing2 2jar 下载地址 http download csdn net detail gao36951 8161861 Zxing是Google提供的关于条码 一维码 二维码 的解析工具 提供了二
  • tms sparkle实现apk下载安装。

    缘起 存放在pc端的apk 如何下载到手机端并安装 一种是通过IM通讯工具 或是复制到u盘上 或是ftp下载 还有就是通过云盘安装 但是以上方法都不是非常方便 思路 下面介绍一种思路 将apk文件存放在pc端的某一路径下 然后生成html文
  • (个人)AR电子书系统创新实训第二周(1)

    从头实现一个识别二维码的Unity项目 通过上次大致了解了ZXing Net的基本使用方法后 此次我决定使用它和unity制作一个简单的测试项目 以检验其功能是否满足要求 具体步骤如下 1 创建Unity项目 将zxing unity dl
  • 错误隐藏学习手记(二)

    错误隐藏技术是在H 264在解码端后端的一种技术 用于恢复某一丢失帧或者宏块 一般来说每个宏块是16 16 Step1 我们怎么知道是哪一块宏块丢失了呢 这就和视频编解码H 264有些关系了 JM86中丢失块的确定取决于编码端灵活宏块重排模
  • 【Python-利用动态二维码传输文件(五)】动态二维码文件发送端开发,使用Tkinter filedialog实现任意格式文件选中,并显示发送状态

    之前四篇文章论证了利用二维码传输文件的可行性 本章使用tkinter开发 动态二维码文件发送端 发送端具备文件选择 开始发送文件 停止发送文件以及显示发送状态的功能 程序界面下 这里下载源码运行 使用tkinter开发动态二维码文件发送端
  • 错误隐藏学习手记(三)

    帧内错误隐藏算法集合 1 空间加权像素平均算法 加权像素平均插值算法 P0就是丢失的宏块 灰色的是最近的像素点 2 方向插值 1 边缘检测及梯度计算 使用Sobel算子 计算的是Sx和Sy 水平边缘和垂直边缘 下图中 a b c d是缺失的
  • OpenCV之摄像头捕捉图像

    代码 数据类型 运行效果 代码 之前我找过directshow CameraDS VedioCaptureFromCam之类的东西 发现都不可以用 directshow是因为版本太老了 会出现 http www opencv org cn
  • QRCode简单生成二维码

    QRCode简单生成二维码 1 导包 2 jsp的body里 div div
  • 【Python-利用动态二维码传输文件(二)】实现文件二进制读取、利用base64编码把文件拆分成多张二维码、重组拆分后的文件并验证。

    为了使用二维码传输文件 上一篇文章已经实现了获取信息存入二维码并打印 由于单个二维码存储的信息量是有限的 而且文件一般也比较大 所以必须把文件先进行拆分 拆分后一块一块信息存入多张二维码中 最后通过图像识别 把所有二维码信息准确读取后再重新
  • 12. openCV在QT环境中利用zBar开发库实现二维码内容识别

    1 说明 本篇博客仅记录如何使用zBar库进行二维码内容的识别 其中牵扯到的一些其它知识点 比如二维码区域检测 zBar库开发环境配置等可以参考本专栏的其它相关博客 此篇博客不再赘述 2 具体步骤 博客中代码功能 手动选择一张包含二维码的图

随机推荐

  • ArrayList源码解析(二)

    在末尾添加一个元素add E e public boolean add E e ensureCapacityInternal size 1 确保内部容量够用 必要的话进行扩容 否则elementData size 将会数组越界 elemen
  • 报名丨 “中国的城市化、数字技术和创新市场” ——清华大学-麻省理工学院联合训练营开始招募啦...

    世界各地的城市正竞相利用数字技术改造其城市系统 使之更有效率 更可持续 更有弹性和活力 数字技术带来了城市规划 发展 运行 治理等方面快速而深刻的变化 技术创新和城市化正在融合 以形成新的商业模式以及企业 以应对城市挑战 中国正进行着全球最
  • 力扣二叉树,根据leetcode的控制台输入快速在本地建树

    使用说明 目的 为了刷二叉树题目时根据leetcode的控制台输入快速在本地建树 例子 leetocde 控制台输入 3 9 20 null null 15 7 ide中java代码 将数值复制到数组中 并将null用 Integer MI
  • 微信小程序如何监听左上角的返回按钮

    在微信小程序中 如果页面出现多级跳转 就会出现一种恶心的bug 比如 从首页进入A页面 然后在A页面进行了点击一个新增或者编辑的B页面 操作完成之后 B级页面是会回调到A页面 然后继续在A页面进行跳转到B页面进行操作 这种循环多次之后 会发
  • SourceTree导入产品证书

    SourceTree导入产品证书 可以到我的资源中下载 SourceTree产品证书 解压后得到一个文件 sourcetree license 直接导入即可使用
  • Matlab知识点基础(一)

    最近感觉在这上面搜相应的知识点都好困难 所以自己写点总结 以免又忘了 1 循环的总结 1 1 编写MATLAB程序 计算1到100的和 for 循环 s 0 for i 1 1 100 这里分别是初始值 间隔 终止值 s s i end s
  • live555学习之二和客户端通信流程顶层

    1 创建了一个 RTSPClientConnection 类型的实例 session RTSPClientConnection 2 调用该类的处理函数 session gt incomingRequestHandler1 2 1 读取 so
  • python基础语法

    基础语法 持续学习更新中 1 变量类型 2 逻辑语句 3 类 Python内置类属性 4 错误和异常 1 变量类型 数字 字符串 字符串可以看做是字符的列表 不存在字符类型 包含一个字符的也称作字符串 创建字符串可以用单引号也可以用双引号
  • 机器学习速成课程笔记10:使用TF的基本步骤

    快速翻阅 快速学习 TensorFlow 是一个用于人工智能的开源神器 TensorFlow 是一个采用数据流图 data flow graphs 用于数值计算的开源软件库 节点 Nodes 在图中表示数学操作 图中的线 edges 则表示
  • Qt纯代码实现添加背景图片的自定义按钮

    Qt的控件中提供了按钮类 我们在调用一个按钮控件的时候 一般通过使用按钮类本身的接口函数已经够用了 在添加按钮的图标或者背景的时候可以通过调用如下所示的接口函数 void setIcon const QIcon icon 虽然Qt已经提供了
  • 异步模式之生产者消费者

    4 异步模式之生产者消费者 刚才的情况 我们一直都在讨论 一个执行者对应一个接收者的情况 下面 我们来讨论另外一种情况 多个生产者对应多应多个消费者的情况 消息类 class Message private int id private O
  • json基本使用与简介

    一 简介 二 json两种构造结构 三 js解析JSON 1 JSON2解析JSON 2 用eval 方法把JSON字符串转化成JSON对象 3 使用JSON2中的JSON对象的parser 方法解析JSON字符串 4 使用JSON2中的J
  • Jupyter notebook更换工作目录

    打开Anaconda 打开cmd Prompt如图所示 输入jupyter notebook generate config找到目录文件jupyter notebook config py jupyter notebook config p
  • vsphere 虚拟机的迁移,冷迁移,vmotion(热迁移)

    备注 理论部分参考王春海老师的课程 一 概述 1 vsphere数据中心当处于某种目的进行维护时 需要将某台主机上运行或关闭的虚拟机 迁移到其他主机上 这个时候就需要使用迁移 2 可以使用冷迁移或热迁移将虚拟机移到其他主机或数据存储 3 迁
  • 开发前期准备工作

    开发前期准备工作 文章目录 开发前期准备工作 0 代码规范 0 1 强制 0 2 推荐 0 3 参考 dao 跟数据库打交道 service 业务层 人类思维解决 controller 抽象化 0 4 注释规范 0 5 日志规范 0 6 专
  • 欧姆龙NJ1P2 Fins Udp通讯

    NJ1P2 Tcp连接不成功 咨询客服说不支持Fins Tcp 所以改成Udp方式 Udp连接 locateIp IPAddress Parse txtLocateIP Text locatePoint new IPEndPoint loc
  • 使用CMakeList编译报错

    可能出现的一个原因是磁盘空间不足 使用 df h 查看磁盘空间 若磁盘空间已满 清理磁盘 然后再进行编译
  • Gradle project sync failed. Please fix your project and try again.

    在Android Studio中Import Module后 再运行项目 报下列错误 Gradle project sync failed Please fix your project and try again 这是由于build gr
  • node.js学习

    一 基础知识 1 终端 shell命令 dir 列出当前目录下所有路径 表示当前目录 表示上一级目录 md 目录名 新建文件 rd 目录名 删除文件 文件名 直接打开文件 2 环境变量 windows系统中的变量 配置path 当在命令行窗
  • 数字图像处理之二维码图像提取算法(十一)

    check ratio requirement b w b w b 1 1 3 1 1 bool qr checkRatio totalFinderSize 0 for int i 0 i lt 5 i int count stateCou