IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> zbar下条形码和二维码的识别与解码Ⅲ|2021SC@SDUSC -> 正文阅读

[人工智能]zbar下条形码和二维码的识别与解码Ⅲ|2021SC@SDUSC

2021SC@SDUSC

4.对非标准的QR二维码图片,进行定位,然后用Zbar解码显示。

这里主要参考opencv二维码识别解码_nickchao的IT生涯-CSDN博客_opencv二维码识别的博客。不过该博客的处理没有考虑多个识别点时的情况:

例图:

本文主要处理去除干扰的识别点的方向进行研究解决。根据二维码特性:

我们只要找到90°±Δx的角,且夹角两边为最小的边即可。

找到三个点后,我们需要对齐做旋转处理,旋转的角度如下:

其中处理的步骤分为:

灰度处理-》边缘检测-》特征轮廓检测-》提取特征点-》排除干扰点-》绘制直角三角形-》纠正旋转-》提取ROI-》识别

这里先给效果,后展示代码

边缘检测:

?特征轮廓检测:

?提取特征点-》排除干扰点-》绘制直角三角形

纠正旋转

提取ROI

识别

源码如下:

void MyClass::QrRun(){
    RNG rng(12345);
    //imshow("原图", srcimage);
    Mat src_all = srcimage.clone();
    Mat src_gray;
    //灰度处理
    src_gray = getBlur(getGray(srcimage));

    Scalar color = Scalar(1, 1, 255);
    Mat threshold_output;
    vector<vector<Point> > contours, contours2;
    vector<Vec4i> hierarchy;
    Mat drawing = Mat::zeros(srcimage.size(), CV_8UC3);
    Mat drawing2 = Mat::zeros(srcimage.size(), CV_8UC3);
    Mat drawingAllContours = Mat::zeros(srcimage.size(), CV_8UC3);

    threshold_output = getThold(src_gray);

    findContours(threshold_output, contours, hierarchy, CV_RETR_TREE, CHAIN_APPROX_NONE, Point(0, 0));

    int c = 0, ic = 0, k = 0, area = 0;
    // 边缘检测
    //通过黑色定位角作为父轮廓,有两个子轮廓的特点,筛选出三个定位角
    int parentIdx = -1;
    for (int i = 0; i< contours.size(); i++)
    {
        //画出所以轮廓图
        drawContours(drawingAllContours, contours, parentIdx, CV_RGB(255, 255, 255), 1, 8);
        if (hierarchy[i][2] != -1 && ic == 0)
        {
            parentIdx = i;
            ic++;
        }
        else if (hierarchy[i][2] != -1)
        {
            ic++;
        }
        else if (hierarchy[i][2] == -1)
        {
            ic = 0;
            parentIdx = -1;
        }
        //特征轮廓检测 - 》
        //有两个子轮廓
        if (ic >= 2)
        {
            //保存找到的三个黑色定位角
            contours2.push_back(contours[parentIdx]);
            //画出三个黑色定位角的轮廓
            drawContours(drawing, contours, parentIdx, CV_RGB(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 1, 8);
            ic = 0;
            parentIdx = -1;
        }
    }
    //提取特征点
    //填充的方式画出黑色定位角的轮廓
    for (int i = 0; i<contours2.size(); i++)
        drawContours(drawing2, contours2, i, CV_RGB(rng.uniform(100, 255), rng.uniform(100, 255), rng.uniform(100, 255)), -1, 4, hierarchy[k][2], 0, Point());

    //获取定位角的中心坐标
    vector<Point> pointfind;
    for (int i = 0; i<contours2.size(); i++)
    {
        pointfind.push_back(Center_cal(contours2, i));
    }
    //排除干扰点
    Mat dst;
    Point point[3]; double angle; Mat rot_mat;
    ///选择合适的点-核心筛选
    if (pointfind.size()>3){
        double lengthA = 10000000000000000, lengthB = 10000000000000000000;
        for (int i = 0; i < pointfind.size(); i++){
            for (int j = 0; j < pointfind.size(); j++){
                for (int k = 0; k < pointfind.size(); k++){
                    if (i != j&&j != k&&i != k){
                        double dxa, dxb,dya,dyb;
                        double k1, k2, wa, wb;
                        dxa = pointfind[i].x - pointfind[j].x;
                        dxb = pointfind[i].x - pointfind[k].x;
                        dya = pointfind[i].y - pointfind[j].y;
                        dyb = pointfind[i].y - pointfind[k].y;
                        if (dxa == 0 || dxb == 0)continue;
                        k1 = dya/dxa;
                        k2 = dyb/dxb ;
                        wa = sqrt(pow(dya, 2) + pow(dya, 2));
                        wb = sqrt(pow(dyb, 2) + pow(dxb, 2));
                        double anglea = abs(atan(k1) * 180 / CV_PI) + abs(atan(k2) * 180 / CV_PI);
                        if (int(anglea)>=85&&int(anglea)<=95&&wa<=lengthA&&wb<=lengthB){
                            lengthA = wa;
                            lengthB = wb;
                            point[0] = pointfind[i];
                            point[1] = pointfind[j];
                            point[2] = pointfind[k];
                        }
                    }
                }
            }
        }
    }
    else{
        for (int i = 0; i < 3; i++){
            point[i] = pointfind[i];
        }
    }
    //绘制直角三角形
    //计算轮廓的面积,计算定位角的面积,从而计算出边长
    area = contourArea(contours2[0]);
    int area_side = cvRound(sqrt(double(area)));
    for (int i = 0; i < 3; i++){
        line(drawing2, point[i], point[(i + 1)%3], color, area_side / 2, 8);
    }

    //纠正旋转
    //判断是否正对
    if (!IsCorrect(point)){
    //进入修正环节
        double angle; Mat rot_mat;
        int start = 0;
        for (int i = 0; i < 3; i++){
            double k1, k2,kk;
            k1 = (point[i].y - point[(i + 1) % 3].y) / (point[i].x - point[(i + 1) % 3].x);
            k2 = (point[i].y - point[(i + 2) % 3].y) / (point[i].x - point[(i + 2) % 3].x);
            kk = k1*k2;
            if (k1*k2 <0)
                start = i;
        }
        double ax, ay, bx, by;
        ax = point[(start + 1) % 3].x;
        ay = point[(start + 1) % 3].y;
        bx = point[(start + 2) % 3].x;
        by = point[(start + 2) % 3].y;
        Point2f center(abs(ax - bx) / 2, abs(ay -by)/ 2);
        double dy = ay - by;
        double dx = ax - bx;
        double k3 = dy / dx;
        angle =atan(k3) * 180 / CV_PI;//转化角度
        rot_mat = getRotationMatrix2D(center, angle, 1.0);

        warpAffine(src_all, dst, rot_mat, src_all.size(), 1, 0, 0);//旋转原图查看
        warpAffine(drawing2, drawing2, rot_mat, src_all.size(), 1, 0, 0);//旋转连线图
        warpAffine(src_all, src_all, rot_mat, src_all.size(), 1, 0, 0);//旋转原图

        namedWindow("Dst");
        imshow("Dst", dst);
    }

    namedWindow("DrawingAllContours");
    imshow("DrawingAllContours", drawingAllContours);

    namedWindow("Drawing2");
    imshow("Drawing2", drawing2);

    namedWindow("Drawing");
    imshow("Drawing", drawing);

    //提取ROI
    //接下来要框出这整个二维码
    Mat gray_all, threshold_output_all;
    vector<vector<Point> > contours_all;
    vector<Vec4i> hierarchy_all;
    cvtColor(drawing2, 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[1]);//pointfind.size()-3

    //将rectPoint变量中存储的坐标值放到 fourPoint的数组中
    rectPoint.points(fourPoint2f);

    int maxx = 0, maxy = 0, minx = 100000, miny = 100000;
    for (int i = 0; i < 4; i++)
    {
        if (maxx < fourPoint2f[i].x)maxx = fourPoint2f[i].x;
        if (maxy < fourPoint2f[i].y)maxy = fourPoint2f[i].y;
        if (minx > fourPoint2f[i].x)minx = fourPoint2f[i].x;
        if (miny > fourPoint2f[i].y)miny = fourPoint2f[i].y;
        line(src_all, fourPoint2f[i % 4], fourPoint2f[(i + 1) % 4]
            , Scalar(0), 3);
    }
    namedWindow("Src_all");
    ///边际处理
    int set_inter = 5;
    while (true)
    {
        minx -= set_inter;
        miny -= set_inter;
        maxx += set_inter;
        maxy += set_inter;
        if (maxx > srcimage.size().width || maxy > srcimage.size().height || minx < 0 || miny < 0){
            minx += set_inter;
            miny += set_inter;
            maxx -= set_inter;
            maxy -= set_inter;
            set_inter--;
        }
        else
        {
            break;
        }
    }
    imshow("Src_all", src_all(Rect(minx, miny, maxx - minx, maxy - miny)));//ROI
    Mat fout = src_all(Rect(minx, miny, maxx - minx, maxy - miny));//ROI

    //识别
    Dis_code(fout);

    waitKey(0);
    destroyAllWindows();
}

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-10-25 12:32:33  更:2021-10-25 12:33:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 8:39:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码