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

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(使用前将#替换为@)

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

随机推荐

  • 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