Windows下使用Qt引用opencv库进行二维码识别

原文链接

欢迎大家对于本站的访问 - AsterCasc

前言

在前文交叉编译armv7运行环境以及嵌入式opencv的编译示例以及实现嵌入式设备中的人脸检测中,我们都是在Linux环境中工作的。如果需要引用摄像头等多媒体测试,Linux编译机就没有那么易用了,这里我们以windows举例演示opencv库的引用及二维码的识别

环境

opencv编译

前文中已经提及了关于opencv的交叉编译,本地编译只需要修改编译文件即可。如果懒的编译的小伙伴可以直接从github上下载官方已经编译完成的release资源,opencv release。如果你用是的MSVC那么是可以直接使用的,如果你使用的是MinGW是无法使用的,此时我们可以找其他人编译好的版本,比如说OpenCV-MinGW-Build,选择对应的编译器位数下载即可。如果需要人脸识别等附加功能,由于目前人脸识别不在opencv基本库中,而是处于opencv contrib中,此时我们需要选择带contrib编译的包,如果是自己编译的小伙伴也需要相应修改编译命令

这里我们以32位带contrib4.5.0版本举例

此时我们有{path}/x64/mingw/lib{path}/x64/mingw/bin的动态库,以及{path}/include/opencv2的头文件

Qt构建

.pro文件中引入库以及头文件

INCLUDEPATH += $${YOUR_PATH}/include
LIBS+= $${YOUR_PATH}/x64/mingw/bin/libopencv_*.dll

然后随便写个程序测试一下

//main
int main(int argc, char* argv[])
{
    QApplication a(argc, argv);
    Widget       w;
    w.show();
    return a.exec();
}
//.h
class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget* parent = nullptr);
    virtual ~Widget() = default;

private:
    bool                    inCodeParse  = false;
    QVideoProbe*            m_probe      = nullptr;
    QVBoxLayout*            m_mainLayout = nullptr;
    QCameraViewfinder*      m_viewfinder = nullptr;
    QScopedPointer<QCamera> m_camera;

public slots:
    void slotOnProbeFrame(const QVideoFrame& frame);
};
//cpp
Widget::Widget(QWidget* parent) : QWidget(parent)
{
    this->resize(750, 500);

    m_mainLayout = new QVBoxLayout(this);
    m_mainLayout->setSpacing(0);
    m_mainLayout->setContentsMargins(0, 0, 0, 0);

    m_viewfinder = new QCameraViewfinder(this);
    m_viewfinder->show();
    m_mainLayout->addWidget(m_viewfinder);

    QCameraInfo defualtCamera = QCameraInfo::defaultCamera();
    if (defualtCamera.isNull())
    {
        // todo throw
    }
    m_camera.reset(new QCamera(defualtCamera, this));
    m_camera.data()->setViewfinder(m_viewfinder);

    // probe
    m_probe = new QVideoProbe();
    connect(m_probe, SIGNAL(videoFrameProbed(QVideoFrame)), this, SLOT(slotOnProbeFrame(QVideoFrame)), Qt::QueuedConnection);
    m_probe->setSource(m_camera.data());

    // start
    m_camera->start();
}

cv::Mat qImg2Mat(QImage image)
{
    cv::Mat mat;
    switch (image.format())
    {
    case QImage::Format_ARGB32:
    case QImage::Format_RGB32:
    case QImage::Format_ARGB32_Premultiplied:
        mat = cv::Mat(image.height(), image.width(), CV_8UC4, ( void* )image.constBits(), image.bytesPerLine());
        break;
    case QImage::Format_RGB888:
        mat = cv::Mat(image.height(), image.width(), CV_8UC3, ( void* )image.constBits(), image.bytesPerLine());
        cv::cvtColor(mat, mat, CV_BGR2RGB);
        break;
    case QImage::Format_Indexed8:
        mat = cv::Mat(image.height(), image.width(), CV_8UC1, ( void* )image.constBits(), image.bytesPerLine());
        break;
    }
    return mat;
}

cv::Mat qVideoFrame2Mat(const QVideoFrame& buffer)
{
    cv::Mat        mat;
    QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(buffer.pixelFormat());
    switch (imageFormat)
    {
    case QImage::Format_ARGB32:
    case QImage::Format_RGB32:
    case QImage::Format_ARGB32_Premultiplied:
        mat = cv::Mat(buffer.height(), buffer.width(), CV_8UC4, ( void* )buffer.bits(), buffer.bytesPerLine());
        break;
    case QImage::Format_RGB888:
        mat = cv::Mat(buffer.height(), buffer.width(), CV_8UC3, ( void* )buffer.bits(), buffer.bytesPerLine());
        cv::cvtColor(mat, mat, CV_BGR2RGB);
        break;
    case QImage::Format_Indexed8:
        mat = cv::Mat(buffer.height(), buffer.width(), CV_8UC1, ( void* )buffer.bits(), buffer.bytesPerLine());
        break;
    }
    return mat;
}

void Widget::slotOnProbeFrame(const QVideoFrame& buffer)
{
    if (!inCodeParse)
    {
        QtConcurrent::run([=]() {
            inCodeParse = true;

            QVideoFrame frame(buffer);
            frame.map(QAbstractVideoBuffer::ReadOnly);
            QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat());
            QImage         img(frame.bits(), frame.width(), frame.height(), imageFormat);
            img = img.mirrored();
            frame.unmap();

            cv::Mat            mat = qImg2Mat(img);
            cv::QRCodeDetector detector;
            std::string        outStr = detector.detectAndDecode(mat, cv::noArray(), cv::noArray());

            if (0 != outStr.length())
            {
                std::cout << "code is " << outStr << std::endl;
            }

            inCodeParse = false;
        });
    }
}

注意img = img.mirrored();这里是由于某些windows机器摄像机型号设置的问题需要进行镜像反转,否则直接使用qVideoFrame2Mat转换为cv::Mat即可,不需要从QImage走一层

此时编译是没有问题了,但是由于我们使用的是动态库,所以需要将这些动态库放在windows系统库文件夹内,或者置于应用程序运行文件夹内以供调用,如果小伙伴们是自行编译的静态库,使用静态链接后则不需要再配置动态库了

这样我们运行程序将二维码置于摄像头前,即可完成二维码的检测以及解析

原文链接

欢迎大家对于本站的访问 - AsterCasc

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值