zl程序教程

您现在的位置是:首页 >  工具

当前栏目

qt在window实现调取本机摄像头或者外设摄像头二维码识别升级版

Qt识别 实现 或者 window 摄像头 二维码 外设
2023-09-27 14:29:08 时间

之前发过一个帖子,后来发现有很多bug,不得已又研究了几天, 升级了这一版本,比之前好多了,bug也完美解决,但只是在我应用上解决,相对于大多数人来说还是未知的,看你们个人需求,希望能帮助到你们。话不多说,上正文。附上之前帖子链接,qt在window实现二维码识别_大桶矿泉水的博客-CSDN博客_qt windows扫一扫功能




主界面

识别界面

主界面 代码

#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QtWidgets>
#include <QVideosurfaceFormat>
#include <QDebug>
#include <QRect>
#include <QZXing.h>
QString str;
QZXingCamera* mypic;
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    mypic = new QZXingCamera();
    connect(mypic,&QZXingCamera::updateString,this,&MainWindow::updateStr);
    mypic->hide();
    mypic->setAttribute(Qt::WA_DeleteOnClose);//若是关闭界面,则彻底释放资源,未加关闭仍占用资源
}

MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::updateStr(QString string)
{
       //qDebug()<<"button clicked"<<string;
    ui->textEdit->setText(string);
}

void MainWindow::on_pushButton_clicked()
{
    qDebug()<<"button clicked";
    mypic->show();
}

识别界面代码

#include "qzxingcamera.h"
#include "ui_qzxingcamera.h"
#include <QtWidgets>
#include <QVideosurfaceFormat>
#include <QDebug>
#include <QRect>
#include <QZXing.h>
#include <QCameraInfo>
int cameranum=-1;
QZXingCamera::QZXingCamera(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::QZXingCamera)
{
    ui->setupUi(this);
    this->setWindowModality(Qt::ApplicationModal);//放置在顶层
    QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
    int i=0;
    foreach (const QCameraInfo &cameraInfo, cameras) {
        i++;
        qDebug() << "camera description is "<<cameraInfo.description();
        ui->comboBox->insertItem(i,cameraInfo.description());
        if(i==1)camera_ = new QCamera(cameraInfo);
        qDebug() << "iiii="<<i;
    }
    if(i==0){
        camera_ = new QCamera();
        ui->label->setText("没有识别到摄像头设备,或没安装驱动");
        qDebug() << "has no camera device";
    }
    //else{
        //camera_ = new QCamera(cameraInfo);
        surface_ = new MyVideoSurface(this);
        camera_->setViewfinder(surface_);
        camera_->start();
        //this->resize(400,300);
        //this->move(200,200);
        //this->setWindowFlags(Qt::FramelessWindowHint);//去掉右上角关闭窗口
        //this->showMaximized();//Qt最大化显示函数
    //}
    connect(ui->comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(on_comboBox_currentIndexChanged(int)));
}

QZXingCamera::~QZXingCamera()
{
    delete ui;
}
//切换通道
void QZXingCamera::on_comboBox_currentIndexChanged(int index)
{
    qDebug()<<"选择了"<<index;
    cameranum=index;
}
//
void QZXingCamera::on_pushButton_3_clicked()
{
    qDebug()<<"cameranum="<<cameranum;
    if(cameranum>=0)
        QCameraInfo::availableCameras().at(cameranum).description();
}
QSize QZXingCamera::sizeHint() const
{
    //return surface_->surfaceFormat().sizeHint();
    //qDebug()<<"size changed";
}

void QZXingCamera::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    if (surface_->isActive()) {
        const QRect videoRect = surface_->videoRect();
        if (!videoRect.contains(event->rect())) {
            QRegion region = event->region();
            region = region.subtracted(videoRect);
            QBrush brush = palette().background();
            //for(const QRect &rect : region){
            //    painter.fillRect(rect, brush);
            //}
        }
        surface_->paint(&painter);//在主窗口绘制
    } else {
        painter.fillRect(event->rect(), palette().background());
    }
   //qDebug()<<"str bbbbs";
    if(str.isEmpty()==false){
        qDebug()<<"识别结果:"+str;
        emit updateString(str);
        str.clear();
        this->hide();
    }
}
//系统自带关闭界面回调函数
void QZXingCamera::closeEvent(QCloseEvent *event)//点击系统自带关闭按钮回调函数
{
    event->ignore();//失能关闭窗口功能,只能隐藏/显示
    this->hide();
}

void QZXingCamera::resizeEvent(QResizeEvent *event)
{
    QMainWindow::resizeEvent(event);
    surface_->updateVideoRect();
    qDebug()<<"size changed";
}

void QZXingCamera::on_pushButton_clicked()
{
    this->hide();
}

void QZXingCamera::on_pushButton_2_clicked()
{
    QString m_fileName;
    QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
    m_fileName = QFileDialog::getOpenFileName(this,
                                                 tr("条形码打开文件"),
                                                 "./",
                                                 tr("任何文件(*.*)"
                                                    ";;文本文件(*.png)")
                                                 );
    qDebug()<<m_fileName;
    ui->label->setText("");
    QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
    if(m_fileName.isEmpty() == false)
    {
       //ui->statusBar->setToolTip(m_fileName);
       QImage img;        //加载图像
       if(!(img.load(m_fileName)))
       {
           QMessageBox::information(this,
                                    tr("打开图像失败"),
                                    tr("打开图像失败!"));
           return;
       }
       QZXing decode;
       QString str = decode.decodeImage(img);
       if(str.isEmpty()==false){
           qDebug()<<"识别结果:"+str;
           emit updateString(str);
           str.clear();
           this->hide();
       }else
           ui->label->setText("未识别到条形码二维码!");
    }
}


硬核东西直接公开,接下来简单介绍一些本次升级的内容:

上一版采用的是QCameraImageCapture截取图像的方法,这个方法在其他设备如Mac,Linux, 等设备不会一直保存图片到本机,在win上面,只要在定时器里用QCameraImg->capture();//拍照获取一帧的方式,就会无限保存图片到 本机相册,我也是 在那天 试验几次之后,第二天偶然打开相册,一下子吓坏了, 发现了测试过程中记录下的好几千张照片,瞬间 就不高兴了,然后就各种找方法如何不保存图片到本机, 后来发现了这个帖子解决QCamera使用QCameraImageCapture截图卡顿问题_SDU-Leon的博客-CSDN博客_qcameraimagecapture,很大的希望来解决这个问题,但是最终发现只有在win上这个方法不好使,在其他设备都好使,所以不得不换一种方式 去调用摄像头识别二维码,经过和一个小伙伴几天的交流探讨,主要还是小伙伴给力的帮助下,成功用一种方法实现了画面不卡顿,还不会保存图片到本机,还不用去调用定时器来定时刷新函数,就一直在识别图片数据的方法。

        成功没热乎, 就发现新问题,把程序打包,换台win设备,就不行了,换台式,不行,换平板,不行,换同事电脑,哎行了,发现都是联想的,回家换对象电脑,哎行了,发现也是联想的,这不现实啊,难道QCamera是为联想而生的?后来发现这几台设备都好使的共同点是都装有摄像头驱动,并且在本机可直接调取摄像头出来,于是乎就把其他设备装上外设摄像头驱动,插上外设摄像头,哎行了。但是 在无摄像头的设备上不会提示无摄像头驱动,就是无图像,还会无故程序崩溃,这不得给用户带来不好的印象啊,怎么有问题也不能崩溃啊,于是就得在程序判断摄像头是否存在,就发掘了下面的方法

一开始没用好,打印出来摄像头名字是一堆乱码,后来发现原来cameraInfo.description()这个才是摄像头在本机设备上叫的名字,,既然能找到摄像头了,那么就能改摄像头显示(这个目前还未论证是否能切换,但实验结论得出在好使摄像头切换到空摄像头程序会死,间接说明切换到好使摄像头是好使的,等条件允许在试验,有个pad是有前后摄像头的,驱动没装成功,装好了在实验),就还能识别无摄像头的设备,从而进行提示,接下来以图片简单演示一下,以我的笔记本举例

首先我的笔记本设备只有前置摄像头,显示启动摄像头显示,然后打开程序,

打印出来当前选中的摄像头名字,放个二维码识别,如下图

图中下拉中只有一个摄像头设备,理论如有多个,切换后可更换显示,识别成功后会自动隐藏摄像头界面,打印出识别的内容,也可识别本机二维码图片,接下来演示设备无摄像头驱动,之前要么无提示,用户不知道咋回事,要么直接就程序崩溃,用户也是蒙圈不知道乍回事。

在设备管理器将我的摄像头设置为禁用

 重新打开程序,结果如下

点击涉嫌头识别如下

下拉列表中无内容,点击选择此设备按键也无反应,会提示未识别到摄像头设备或驱动未安装成功,用户就知道问题 的根源了。

本次改动主要就是以上内容,目前我用起来是没有其他问题了,接下来就研究如何安装摄像头驱动了,现在百度找东西垃圾软件太多了,大多数都是没用的。

附上源码下载链接qt在window实现调取摄像头识别二维码条形码不会保存图片到本机多个摄像头可切换无摄像头不崩溃会提示-QT代码类资源-CSDN下载

2019.4.19更新

研究了3天, 加一个线程去处理图像二维码识别,效果比在主线程处理好的多,但是加线程中遇到一个一直死机的问题,卡了两天,问了很多群友,最后在自己一直耐住性子去试验,最终调出来了加线程版,加个线程,很多坑,在线程处理image,还要防止传输image重入,不然会崩溃。

    thread = new MyThread(this);
    connect(thread,&MyThread::updateString11,this,&QZXingCamera::updateStr);
    thread->start();
    connect(surface_,&MyVideoSurface::updateImage,thread,&MyThread::getdateImage);

在摄像头初始化完毕实例化新线程,

#include "mythread.h"
#include <QDebug>
#include <QCoreApplication>
#include <QMutex>
#include <myvideosurface.h>
#include "qzxingcamera.h"
bool isRun;
MyVideoSurface * aaa;
extern bool device_flag;
MyThread::MyThread(QObject *parent)
{
    decode = new QZXing;
}

void MyThread::run()
{
    QString str ;
    int i=0;
    while (1) {
        if(isRun==false){
            sleep(1);
        }
        else{
            if(device_flag==true){
                msleep(200);
                aaa->blockSignals(true);
                msleep(10);
                str = decode->decodeImage(image);
                //str = decode->decodeImage(image,-1,-1,true);
                i++;
                qDebug()<<"str"<<i<<"="<<str;
                if(!str.isEmpty()){
                     emit updateString11(str);
                     str.clear();
                     isRun=false;
                }
                msleep(10);
                aaa->blockSignals(false);
            }
            else
                sleep(1);
        }
    }
}

void MyThread::start(QThread::Priority priority)
{
    isRun = false;
    QThread::start(priority);
    qDebug()<<"==============thread已启动==========";
}
void MyThread::getdateImage(QImage image1)
{
    aaa=qobject_cast<MyVideoSurface*>(sender());
    image=image1;
}

MyThread::~MyThread()
{

}

在run中要做好blockSignals,进行信号阻塞,否则必亡。

但是在调用blockSignals要获取到信号的sender是谁,这个sender的定义是在另外一个cpp函数中定义的,所以只能通过槽函数,然后在接收函数中去获取这个sender,aaa=qobject_cast<MyVideoSurface*>(sender());,获取到之后就可以光明正大的调用blockSignals了

附上源码:qt在window实现调取摄像头识别二维码条形码不会保存图片到本机多个摄像头可切换无摄像头或格式不识别不崩溃会提示(加线程处理)-QT代码类资源-CSDN下载