QR扫码综合示例教程(二十一)Qt5.15.2+Qt6.2.1(qml)+opencv4.5.4实现扫码功能(多线程、微信扫码)

 前言:
在前面的教程中,使用openCV的库实现了扫码功能,但实际使用时却很不理想。本次教程使用微信的扫码代码来测试

本教程是在 Qt5.15.2+Qt6.2.1(qml)+opencv4.5.4实现扫码功能(多线程) 示例的基础上修改

QR扫码综合示例教程(二十)Qt5.15.2+Qt6.2.1(qml)+opencv4.5.4实现扫码功能(多线程)_aggs1990的专栏-CSDN博客

一、准备openCV库

微信的扫码在附加库里,所以必需要自己编译官方源码,请需要的小伙伴们自己参考以下链接

Qt+openCV学习笔记_aggs1990的专栏-CSDN博客

笔者使用的是自己编译库 

一、修改pro工程文件

修改工程文件是为了添加openCV的库

若是使用的VS2019 64位编译器,添加如下代码

win32{
CONFIG(release, debug|release){
    LIBS += -LOPENCV_DIR/opencv4.5.4/build_vs2019_64/install/x64/vc16/lib/ -lopencv_core454
    LIBS += -LOPENCV_DIR/opencv4.5.4/build_vs2019_64/install/x64/vc16/lib/ -lopencv_imgproc454
    LIBS += -LOPENCV_DIR/opencv4.5.4/build_vs2019_64/install/x64/vc16/lib/ -lopencv_wechat_qrcode454
}
else:CONFIG(debug, debug|release){
    LIBS += -LOPENCV_DIR/opencv4.5.4/build_vs2019_64/install/x64/vc16/lib/ -lopencv_core454d
    LIBS += -LOPENCV_DIR/opencv4.5.4/build_vs2019_64/install/x64/vc16/lib/ -lopencv_imgproc454d
    LIBS += -LOPENCV_DIR/opencv4.5.4/build_vs2019_64/install/x64/vc16/lib/ -lopencv_wechat_qrcode454d
}
LIBS += -LOPENCV_DIR/opencv4.5.4/build_vs2019_64/install/x64/vc16/bin/
INCLUDEPATH += OPENCV_DIR/opencv4.5.4/build_vs2019_64/install/include
DEPENDPATH += OPENCV_DIR/opencv4.5.4/build_vs2019_64/install/include
}

#OPENCV_DIR为openCV库存放目录

只要加载自己需要的模块就可以了,以减小发布包的体积

若是使用的android arm64-v8a编译器,添加如下代码

unix:!macx{
contains(ANDROID_TARGET_ARCH,arm64-v8a) {
    message("arm64-v8a")
ANDROID_OPENCV = opencv_dir/opencv4.5.4/build_android_arm64-v8a/install/sdk/native

    INCLUDEPATH += $$ANDROID_OPENCV/jni/include/opencv2 \
                   $$ANDROID_OPENCV/jni/include


LIBS += \
$$ANDROID_OPENCV/libs/arm64-v8a/libopencv_wechat_qrcode.so \
$$ANDROID_OPENCV/libs/arm64-v8a/libopencv_dnn.so \
$$ANDROID_OPENCV/libs/arm64-v8a/libopencv_imgproc.so \
$$ANDROID_OPENCV/libs/arm64-v8a/libopencv_calib3d.so \
$$ANDROID_OPENCV/libs/arm64-v8a/libopencv_flann.so \
$$ANDROID_OPENCV/libs/arm64-v8a/libopencv_features2d.so \
$$ANDROID_OPENCV/libs/arm64-v8a/libopencv_core.so

ANDROID_EXTRA_LIBS = \
    opencv_dir/opencv4.5.4/build_android_arm64-v8a/install/sdk/native/libs/arm64-v8a/libopencv_core.so \
    opencv_dir/opencv4.5.4/build_android_arm64-v8a/install/sdk/native/libs/arm64-v8a/libopencv_features2d.so \
    opencv_dir/opencv4.5.4/build_android_arm64-v8a/install/sdk/native/libs/arm64-v8a/libopencv_flann.so \
    opencv_dir/opencv4.5.4/build_android_arm64-v8a/install/sdk/native/libs/arm64-v8a/libopencv_calib3d.so \
    opencv_dir/opencv4.5.4/build_android_arm64-v8a/install/sdk/native/libs/arm64-v8a/libopencv_imgproc.so \
    opencv_dir/opencv4.5.4/build_android_arm64-v8a/install/sdk/native/libs/arm64-v8a/libopencv_dnn.so \
    opencv_dir/opencv4.5.4/build_android_arm64-v8a/install/sdk/native/libs/arm64-v8a/libopencv_wechat_qrcode.so

}

若是使用的android armeabi-v7a编译器,添加如下代码

unix:!macx{
#添加opencv库(android armeabi-v7a版)
contains(ANDROID_TARGET_ARCH,armeabi-v7a) {
    message("armeabi-v7a")

ANDROID_OPENCV = opencv_dir/opencv4.5.4/build_android_armeabi-v7a/install/sdk/native

    INCLUDEPATH += $$ANDROID_OPENCV/jni/include/opencv2 \
                   $$ANDROID_OPENCV/jni/include

LIBS += \
$$ANDROID_OPENCV/libs/armeabi-v7a/libopencv_wechat_qrcode.so \
$$ANDROID_OPENCV/libs/armeabi-v7a/libopencv_dnn.so \
$$ANDROID_OPENCV/libs/armeabi-v7a/libopencv_imgproc.so \
$$ANDROID_OPENCV/libs/armeabi-v7a/libopencv_calib3d.so \
$$ANDROID_OPENCV/libs/armeabi-v7a/libopencv_flann.so \
$$ANDROID_OPENCV/libs/armeabi-v7a/libopencv_features2d.so \
$$ANDROID_OPENCV/libs/armeabi-v7a/libopencv_core.so

ANDROID_EXTRA_LIBS = \
    opencv_dir/opencv4.5.4/build_android_armeabi-v7a/install/sdk/native/libs/armeabi-v7a/libopencv_core.so \
    opencv_dir/opencv4.5.4/build_android_armeabi-v7a/install/sdk/native/libs/armeabi-v7a/libopencv_features2d.so \
    opencv_dir/opencv4.5.4/build_android_armeabi-v7a/install/sdk/native/libs/armeabi-v7a/libopencv_flann.so \
    opencv_dir/opencv4.5.4/build_android_armeabi-v7a/install/sdk/native/libs/armeabi-v7a/libopencv_calib3d.so \
    opencv_dir/opencv4.5.4/build_android_armeabi-v7a/install/sdk/native/libs/armeabi-v7a/libopencv_imgproc.so \
    opencv_dir/opencv4.5.4/build_android_armeabi-v7a/install/sdk/native/libs/armeabi-v7a/libopencv_dnn.so \
    opencv_dir/opencv4.5.4/build_android_armeabi-v7a/install/sdk/native/libs/armeabi-v7a/libopencv_wechat_qrcode.so

}

}

二、修改处理类

类Tool_Process头文件修改如下
class Tool_Process : public QObject
{
    Q_OBJECT
public:
    explicit Tool_Process(QObject *parent = nullptr);
    ~Tool_Process();

    //添加待处理的图像
    void setImage(const QImage &image, bool isModeMultiQR);
signals:
    //返回已解读的二维码数据
    void decoded(const QStringList resultStringList, const QImage image);

    //启动定时器
    void start();
protected:
    //处理定时器事件
    void timerEvent(QTimerEvent *event) override;
private:
    //复制微信模型文件内容
    void copyModelFileByteArray();
    //二维码解码
    void process();
    //将QImage对象转换为cv::Mat
    cv::Mat QImage2cvMat(QImage image);
    //将cv::Mat对象转换为QImage
    const QImage MatToQImage(cv::Mat mtx);

    //二维码解码并绘制
    double processQRCodeDetection(cv::wechat_qrcode::WeChatQRCode  *weChatQR, const cv::Mat& input, cv::Mat& result,
                                  std::vector& corners, bool isModeMultiQR, QStringList &resultStringList);
    //二维码解码
    void runQR(cv::wechat_qrcode::WeChatQRCode  *weChatQR, const cv::Mat& input,
        std::vector& corners, std::vector& decode_info,
        bool isModeMultiQR);

    //二维码边框、用时绘制
    void drawQRCodeResults(cv::Mat& frame, const std::vector& corners, const std::vector& decode_info, double fps);

    //二维码边框绘制
    void drawQRCodeContour(cv::Mat &color_image, std::vector& corners);

    //用时绘制
    void drawFPS(cv::Mat &color_image, double fps);


    //启动定时器
    void onStart();

    //保存的图像
    QImage m_image;
    //是否多个二维码
    bool m_isModeMultiQR;
    //定时器Id
    int m_timerId = -1;
    //互斥量
    QMutex m_mutex;

    //微信解码器
    cv::wechat_qrcode::WeChatQRCode  *m_weChatQR = nullptr;

    //微信模型文件
    QTemporaryFile *m_file_detector_prototxt = nullptr;
    QTemporaryFile *m_file_detector_caffe_model = nullptr;
    QTemporaryFile *m_file_super_resolution_prototxt = nullptr;
    QTemporaryFile *m_file_super_resolution_caffe_model = nullptr;
};

源文件修改的关键代码

Tool_Process::Tool_Process(QObject *parent) : QObject(parent)
{
    //复制微信模型文件内容
    copyModelFileByteArray();


    //初始化微信解码器
    const std::string detector_prototxt_path = m_file_detector_prototxt->fileName().toStdString();
    const std::string detector_caffe_model_path = m_file_detector_caffe_model->fileName().toStdString();
    const std::string super_resolution_prototxt_path = m_file_super_resolution_prototxt->fileName().toStdString();
    const std::string super_resolution_caffe_model_path = m_file_super_resolution_caffe_model->fileName().toStdString();
    m_weChatQR=new cv::wechat_qrcode::WeChatQRCode(detector_prototxt_path,detector_caffe_model_path,
                                              super_resolution_prototxt_path,super_resolution_caffe_model_path);

    connect(this, &Tool_Process::start, this, &Tool_Process::onStart);
}


/*!
 * \brief Tool_Process::copyModelFileByteArray 复制微信模型文件内容
 */
void Tool_Process::copyModelFileByteArray()
{
    {
        QFile f(":/wechat_qrcode/detect.prototxt");
        m_file_detector_prototxt = QTemporaryFile::createNativeFile(f);
    }

    {
        QFile f(":/wechat_qrcode/detect.caffemodel");
        m_file_detector_caffe_model = QTemporaryFile::createNativeFile(f);
    }

    {
        QFile f(":/wechat_qrcode/sr.prototxt");
        m_file_super_resolution_prototxt = QTemporaryFile::createNativeFile(f);
    }

    {
        QFile f(":/wechat_qrcode/sr.caffemodel");
        m_file_super_resolution_caffe_model = QTemporaryFile::createNativeFile(f);
    }
}

/*!
 * \brief Tool_Process::runQR 二维码解码
 * \param qrcode 解码器
 * \param input 输入图像
 * \param corners 二维码定位点
 * \param decode_info 二维码解码信息
 * \param isModeMultiQR 是否多个二维码
 */
void Tool_Process::runQR(cv::wechat_qrcode::WeChatQRCode *weChatQR, const cv::Mat &input, std::vector &corners,
                         std::vector &decode_info, bool isModeMultiQR)
{

    decode_info = m_weChatQR->detectAndDecode(input, corners);
}

说明:

1.在程序运行时,主线程调用setImage()函数,不停注入新的图像,但处理类只保留最后一张图像

2.process()运行在新开的线程中,被定时触发,若有图像未处理,就处理掉

有关解码处理函数的具体实现方法,修改自openCV官方示例,在此就不再解释

3.微信解码器初始化时,需要载入4个模型相关的文件,笔者为方便大家学习,已经直接放入Qt资源文件中,在处理类初始化时,会复制到临时文件中。

4.关于微信扫码的结果,返回的点放入std::vector中。

每个二维码的四个点对应一个cv::Mat

每个cv::Mat是一个4行2列的float矩阵,每行存放x、y坐标,均点4个字节

修改完成以上代码,就可以运行程序了,以下是笔者的运行结果

1.Qt6.2.1在win10下的运行结果

QR扫码综合示例教程(二十一)Qt5.15.2+Qt6.2.1(qml)+opencv4.5.4实现扫码功能(多线程、微信扫码)_第1张图片

 2.Qt5.15.2在win10下的运行结果

QR扫码综合示例教程(二十一)Qt5.15.2+Qt6.2.1(qml)+opencv4.5.4实现扫码功能(多线程、微信扫码)_第2张图片

 3.Qt6.2.1在android下的运行结果

 4.Qt5.15.2在android下的运行结果

 划线的效果不是很明显,小伙伴们可以自己加粗或修改下颜色

本次教程源码下载

后记:

经过笔者测试,使用微信开源的二维码扫码代码,无论是扫码速度、准确率、解码时消耗内存,都优于openCV自带的二维码扫码器。

要说美中不足的是,需要自己编译openCV库,且不支持条码扫描比较可惜

下篇可能会写下使用其他开源库解码

感谢项目经理临时给了台平板测试,虽然测试完成后要回收

你可能感兴趣的:(Qt+openCV,Qt,for,android,QR扫码综合示例教程,opencv,qt)