Bootstrap

Qt+opencv 显示摄像头至QLabel(通过定时器实现)


前言

通过Qt+opencv,连接USB摄像头,将摄像头画面在界面上进行显示,主要思想是在Widget类中定义一个计时器,在计时结束时触发信号,连接至读取摄像头画面的槽函数对显示的QLabel进行更新。


效果

在这里插入图片描述

资源

本工程运行环境为windows,代码开箱即用,无需在编译opencv了,下载地址为https://download.csdn.net/download/wang_chao118/86497500

代码

建立Qt工程文件,自动生成widget.h,widget.cpp以及widget.ui

若要使用Opencv相关内容,需要在pro文件中添加opencv头文件、库文件,本实验将编译好的opencv相关头文件、库文件放置工程文件夹下,在文章末尾附上了本工程代码,开箱即用,不需要重新编译opencv了。

INCLUDEPATH += "$$PWD"/opencv/include\
               "$$PWD"/opencv/include/opencv \
               "$$PWD"/opencv/include/opencv2 \

Debug:
{
    LIBS += "$$PWD"/opencv/lib/opencv_world3416d.lib \
}

Release:
{
    LIBS += "$$PWD"/opencv/lib/opencv_world3416.lib \
}

Qt_opencv_test.pro

QT       += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
SOURCES += main.cpp \
           widget.cpp
HEADERS +=  widget.h
FORMS +=   widget.ui

INCLUDEPATH += "$$PWD"/opencv/include \
               "$$PWD"/opencv/include\opencv \
               "$$PWD"/opencv/include\opencv2 \

LIBS += "$$PWD"/opencv/lib\opencv_world3416d.lib \
		"$$PWD"/opencv/lib\opencv_world3416.lib

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

widget.h

在widget.h文件中需要声明一个VideoCapture类用于获取摄像头的每帧图像、一个QTimer类用于定时,Mat型的src_image变量用于记录图像数据。

此外,QImage型函数MatImageToQt用于将opencv的图像类型转换为Qt型的图像数据。
readFrame()函数用于获取到的图像数据,并进行ui界面相应区域的图像绘制任务。

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "opencv2/opencv.hpp"
#include <QTimer>

using namespace cv;

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

    //Mat型图像转换为QImage型图像
    QImage MatImageToQt(const Mat &src);

private slots:
    //读取摄像头每帧数据
     void readFarme();

private:
    Ui::Widget *ui;
    //声明opencv的视频类
    VideoCapture cap;
    //声明定时器
    QTimer *timer;
    //声明Mat类图像变量
    Mat src_image;

};
#endif // WIDGET_H

#endif // WIDGET_H

widget.cpp

在Widget构造函数中,首先建立ui界面,打开序号为0的默认摄像头,实例化一个QTimer。

connect(timer,SIGNAL(timeout()),this,SLOT(readFarme()));此句实现定时器的timeout()信号与Widget类中的readFarme()槽函数的连接,其意义是QTimer在设定的事件段后会发出一个timeout()信号,该信号促使了readFarme()函数,相当于每过一段事件刷新了Ui界面,所以是得UI界面看起来是连贯的视频。

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //打开序号为0的摄像头
    cap.open(0);
    //实例化定时器
    timer = new QTimer(this);
    //绑定时间信号及获取图像帧的图像
    connect(timer,SIGNAL(timeout()),this,SLOT(readFarme()));
    //开始定时器
    timer->start(33);
}

Widget::~Widget()
{
    //释放摄像头
    cap.release();
    //删除ui界面
    delete ui;
}

//摄像头读取函数
void Widget::readFarme()
{
    //读取一帧图像
    cap.read(src_image) ;
    //获取ui->label的尺寸
    int width = ui->label->width();
    int height = ui->label->height();
    //将opencv的mat型resize到label的尺寸
    cv::resize(src_image, src_image, Size(width, height));
    //转换图像数据类型
    QImage imag = MatImageToQt(src_image);
    //将图像绘制label
    ui->label->setPixmap(QPixmap::fromImage(imag));
}

//图像数据类型转换
QImage Widget::MatImageToQt(const Mat &src)
{
    if(src.type() == CV_8UC1)
    {
        QImage qImage(src.cols,src.rows,QImage::Format_Indexed8);
        qImage.setColorCount(256);
        for(int i = 0; i < 256; i ++)
        {
            qImage.setColor(i,qRgb(i,i,i));
        }
        uchar *pSrc = src.data;
        for(int row = 0; row < src.rows; row ++)
        {
            uchar *pDest = qImage.scanLine(row);
            memcmp(pDest,pSrc,src.cols);
            pSrc += src.step;
        }
        return qImage;
    }
    else if(src.type() == CV_8UC3)
    {
        const uchar *pSrc = (const uchar*)src.data;
        QImage qImage(pSrc,src.cols,src.rows,src.step,QImage::Format_RGB888);
        return qImage.rgbSwapped();
    }
    else if(src.type() == CV_8UC4)
    {
        const uchar *pSrc = (const uchar*)src.data;
        QImage qImage(pSrc, src.cols, src.rows, src.step, QImage::Format_ARGB32);
        return qImage.copy();
    }
    else
    {
        return QImage();
    }
}

widget.ui

ui界面中,在Widget中放两个QLabel,名称为label及label_2
在这里插入图片描述

资源

本工程运行环境为windows,代码开箱即用,无需在编译opencv了,下载地址为https://download.csdn.net/download/wang_chao118/86497500

;