c++二维码定位和识别+zbar+opencv+ubuntu16.04+clion开发+相机实时扫描

c++二维码定位和识别+zbar+opencv+ubuntu16.04+clion开发+相机实时扫描

  • 二维码的定位
    • 准备安装opencv和配置好clion中的环境
    • C++demo:图片二维码定位
  • 使用zbar读取二维码信息
    • 安装zbar和测试执行zbar
    • C++demo:读取二维码图片上数据
  • 其他博主参考
  • 编写不宜,如果帮助记得打赏

二维码的定位

准备安装opencv和配置好clion中的环境

版主用的相机是小觅相机,opencv环境和cmake也是匹配好的
参考添加链接描述

C++demo:图片二维码定位


#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include 


using namespace cv;
using namespace std;


Mat src;
Mat src_gray;


RNG rng(12345);
//Scalar colorful = CV_RGB(rng.uniform(0,255),rng.uniform(0,255),rng.uniform(0,255));


Point Center_cal(vector > contours, int i)//找到所提取轮廓的中心点
{
    int centerx = 0, centery = 0, n = contours[i].size();
    //在提取的小正方形的边界上每隔周长个像素提取一个点的坐标,求所提取四个点的平均坐标(即为小正方形的大致中心)
    centerx = (contours[i][n / 4].x + contours[i][n * 2 / 4].x + contours[i][3 * n / 4].x + contours[i][n - 1].x) / 4;
    centery = (contours[i][n / 4].y + contours[i][n * 2 / 4].y + contours[i][3 * n / 4].y + contours[i][n - 1].y) / 4;
    Point point1 = Point(centerx, centery);
    return point1;
}


int main(int argc, char const* argv[])
{
//    src = imread("/home/dzy/MYNT-EYE-D-SDK/samples/src/imgs/aaa.jpg");
    src = imread("/home/dzy/MYNT-EYE-D-SDK/samples/src/imgs/weixin.png");
    // 图片的缩小
//    Mat dstImage1;
//    Mat tempImage = src;
//    resize( tempImage, dstImage1, Size(tempImage.cols/4, tempImage.rows/4), 0, 0, INTER_NEAREST );
//    imshow("er_src", dstImage1);
    Mat src_all = src.clone();

    cvtColor(src, src_gray, CV_BGR2GRAY);
    blur(src_gray, src_gray, Size(3, 3));//均值滤波

//    equalizeHist(src_gray, src_gray);
//    imshow("lvbo_hou", src_gray);

    Scalar color = Scalar(1, 1, 255);
    Mat threshold_output;
    vector hierarchy;
    Mat drawing = Mat::zeros(src.size(), CV_8UC3);
    Mat drawing2 = Mat::zeros(src.size(), CV_8UC3);
    threshold(src_gray, threshold_output, 112, 255, THRESH_BINARY);
//    imshow("threshold_output", threshold_output);

    //Canny(src_gray,threshold_output,136,196,3);
    //imshow("预处理后:",threshold_output);
    //寻找轮廓
    //第一个参数是输入图像 2值化的
    //第二个参数是内存存储器,FindContours找到的轮廓放到内存里面。
    //第三个参数是层级,**[Next, Previous, First_Child, Parent]** 的vector
    //第四个参数是类型,采用树结构
    //第五个参数是节点拟合模式,这里是全部寻找
    vector > contours, contours2;
    findContours(threshold_output, contours, hierarchy, CV_RETR_TREE, CHAIN_APPROX_NONE, Point(0, 0));
    //CHAIN_APPROX_NONE全体,CV_CHAIN_APPROX_SIMPLE,,,RETR_TREE    RETR_EXTERNAL    RETR_LIST   RETR_CCOMP

    int c = 0, ic = 0, k = 0, area = 0;

    //程序的核心筛选
    int parentIdx = -1;
    for (int i = 0; i < contours.size(); i++)
    {
        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,Scalar(1, 1, 255), 1, 8);
            ic = 0;
            parentIdx = -1;
            area = contourArea(contours[i]);//得出一个二维码定位角的面积,以便计算其边长(area_side)(数据覆盖无所谓,三个定位角中任意一个数据都可以)
        }
    }

    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());

    Point point[3];
    for (int i = 0; i < contours2.size(); i++)
    {
        point[i] = Center_cal(contours2, i);
    }

    if (!contours2.empty() && contours2.size()>2){
        vector &vector_t = contours2[1];

        if (!vector_t.empty() && vector_t.size()>1){
            area = contourArea(vector_t);//为什么这一句和前面一句计算的面积不一样呢
            int area_side = cvRound(sqrt(double(area)));
            for (int i = 0; i < contours2.size(); i++)
            {
                line(drawing2, point[i%contours2.size()], point[(i + 1) % contours2.size()], color, area_side / 4, 8);
            }

//            imshow("tiqu_hou", drawing2);
//            printf("%d\n", contours.size());
//            imshow( "Contours", drawing );
            //接下来要框出这整个二维码
            Mat gray_all, threshold_output_all;
            vector > contours_all;
            vector hierarchy_all;
            cvtColor(drawing2, gray_all, CV_BGR2GRAY);
//            imshow( "gray_all", gray_all );
            threshold(gray_all, threshold_output_all, 45, 255, THRESH_BINARY);
//            imshow( "threshold_output_all", threshold_output_all );
            //表示只寻找出来连线的最外层轮廓
            findContours(threshold_output_all, contours_all, hierarchy_all, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point(0, 0));//RETR_EXTERNAL表示只寻找最外层轮廓

            //求最小包围矩形,斜的也可以哦
            RotatedRect rectPoint = minAreaRect(contours_all[0]);
            Point2f fourPoint2f[4];
            //将rectPoint变量中存储的坐标值放到 fourPoint的数组中
            rectPoint.points(fourPoint2f);

            for (int i = 0; i < 4; i++)
            {
                line(src_all, fourPoint2f[i % 4], fourPoint2f[(i + 1) % 4], Scalar(1, 1, 255), 3);
            }

            /**
             * 图片截取
             * */
            int threshold_val = 20;
            Mat img = src;
            Mat dst;
            Mat roi = Mat::zeros(img.size(),CV_8U);
            vector> contour;
            vector pts;
            pts.emplace_back(Point( fourPoint2f[0].x-threshold_val,fourPoint2f[0].y+threshold_val));//左下角坐标
            pts.emplace_back(Point( fourPoint2f[1].x-threshold_val,fourPoint2f[1].y-threshold_val));//左上角坐标
            pts.emplace_back(Point( fourPoint2f[2].x+threshold_val,fourPoint2f[2].y-threshold_val));//右上角坐标
            pts.emplace_back(Point( fourPoint2f[3].x+threshold_val,fourPoint2f[3].y+threshold_val));//右下角坐标
            contour.push_back(pts);
            drawContours(roi,contour,0,Scalar::all(255),-1);
            img.copyTo(dst,roi);
            imshow("dst",dst);
            imwrite("../../src/out_ers/caijian1.png",dst);

            imshow("erweima", src_all);
        }
    }

    waitKey(0);
    return(0);
}

使用zbar读取二维码信息

安装zbar和测试执行zbar

参考: https://blog.csdn.net/Kano365/article/details/89636188

我在编译zbar时正常通过,在执行时出现错误--------------------- zbarcam: error while loading shared libraries: libzbar.so.0: cannot open shared object file: No such file or directory
查阅了一下资料:

https://blog.csdn.net/Visrul/article/details/80406830
https://blog.csdn.net/starelegant/article/details/77869792
都没有找到合适的解决办法,最终在/usr/local/lib目录下执行终端窗口执行ldconfig命令,执行通过~ 原因可能为刚安装的zbar库动态链接并没有加载的缓存文件中需要执行ldconfig命令。

如果共享库文件安装到了/lib或/usr/lib目录下, 那么需执行一下ldconfig命令
ldconfig命令的用途, 主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下, 搜索出可共享的动态链接库(格式如lib*.so*), 进而创建出动态装入程序(ld.so)所需的连接和缓存文件. 缓存文件默认为/etc/ld.so.cache, 此文件保存已排好序的动态链接库名字列表.

C++demo:读取二维码图片上数据

#include 
#include 
#include 

using namespace std;
using namespace cv;

int main()

{
    zbar::ImageScanner scanner;
    scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1);
    cv::Mat img = cv::imread("/home/dzy/MYNT-EYE-D-SDK/samples/src/imgs/weixin.png");
    cv::Mat imgGray;
    imgGray.create(img.size(), CV_8UC1);
    cvtColor(img, imgGray, CV_BGR2GRAY);
    int width = imgGray.cols;
    int height = imgGray.rows;
    zbar::Image image(width, height, "Y800", imgGray.data, width *height);
    int n = scanner.scan(image);
    for (zbar::Image::SymbolIterator symbol = image.symbol_begin();symbol != image.symbol_end();++symbol) {
//        cout << "decoded " << symbol->get_type_name()<< " symbol \"" << symbol->get_data() << '"' << endl;
        cout << symbol->get_data() << endl;
    }
    image.set_data(NULL, 0);
    return(0);
}

其他博主参考

参考链接:https://www.cnblogs.com/lx17746071609/p/11428788.html
源文件.cpp

#include 
#include 

using namespace cv;
using namespace std;
using namespace zbar;

typedef struct
{
    string type;
    string data;
    vector  location;
} decodedObject;

// 查找和解码条形码和二维码
void decode(Mat &im, vector&decodedObjects)
{

    // 创建ZBAR扫描器
    ImageScanner scanner;

    scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);

    // 将图像转换为灰度
    Mat imGray;
    cvtColor(im, imGray, COLOR_BGR2GRAY);
    imshow("gray",imGray);
    // 在ZBAR图像中包装图像数据
    Image image(im.cols, im.rows, "Y800", (uchar *)imGray.data, im.cols * im.rows);

    // 扫描图像中的条形码和二维码
    int n = scanner.scan(image);

    // 打印输出结果
    for (Image::SymbolIterator symbol = image.symbol_begin(); symbol != image.symbol_end(); ++symbol)
    {
        decodedObject obj;

        obj.type = symbol->get_type_name();
        obj.data = symbol->get_data();

        // Print type and data
        cout << "Type : " << obj.type << endl;
        cout << "Data : " << obj.data << endl << endl;

        // Obtain location
        for (int i = 0; i < symbol->get_location_size(); i++)
        {
            obj.location.push_back(Point(symbol->get_location_x(i), symbol->get_location_y(i)));
        }

        decodedObjects.push_back(obj);
    }
}

// 显示条形码和二维码位置
void display(Mat &im, vector&decodedObjects)
{
    // 循环所有解码对象
    for (int i = 0; i < decodedObjects.size(); i++)
    {
        vector points = decodedObjects[i].location;
        vector hull;

        // 如果这些点不形成四边形,则找到凸包。
        if (points.size() > 4)
            convexHull(points, hull);
        else
            hull = points;

        // 凸包中的点数
        int n = hull.size();

        for (int j = 0; j < n; j++)
        {
            line(im, hull[j], hull[(j + 1) % n], Scalar(255, 0, 0), 3);
        }

    }

    // 显示结果
    imshow("Results", im);
    waitKey(0);

}


int main(int argc, char* argv[])
{

    // Read image
    Mat im = imread("/home/dzy/MYNT-EYE-D-SDK/samples/src/imgs/weixin.png");
    imshow("Results", im);
    // Variable for decoded objects
    vector decodedObjects;

    // Find and decode barcodes and QR codes
    decode(im, decodedObjects);

    // Display location
    display(im, decodedObjects);
    waitKey(0);
    return 0;
}

CMakeLists.txt配置

cmake_minimum_required(VERSION 3.13)
project(ercode)

set(CMAKE_CXX_STANDARD 14)

add_executable(ercode main.cpp)

#找到opencv的包
set(TARGET_LIBS "/usr/local/include/opencv2/")
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )

#zbar
set(zbar_include_dir "/usr/local/include")
set(zbar_link_dir "/usr/local/lib")
include_directories(${zbar_include_dir})
link_directories(${zbar_link_dir})
link_libraries(zbar)

#动态链接
target_link_libraries(ercode ${OpenCV_LIBS} )
target_link_libraries(ercode jsoncpp)
target_link_libraries(ercode zbar)

编写不宜,如果帮助记得打赏

c++二维码定位和识别+zbar+opencv+ubuntu16.04+clion开发+相机实时扫描_第1张图片

你可能感兴趣的:(Linux,C++)