目录
前言
项目中遇到过进行开发免驱动USB类型相机的开发工作,这次记录一下。为了项目能快速进行,我们使用开源库Opencv进行相机的二次开发。
开发IDE:Qt Creator 4.8.0
编译器:MSVC2017 64bit
图像处理库:Opencv4.5.1
1. 进行Pro文件的修改
在Pro文件中增加opencv图像库的配置
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/opencv4.5.1/vc15/lib/ -lopencv_world451
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/opencv4.5.1/vc15/lib/ -lopencv_world451d
else:unix: LIBS += -L$$PWD/opencv4.5.1/vc15/lib/ -lopencv_world451
INCLUDEPATH += $$PWD/opencv4.5.1/include
DEPENDPATH += $$PWD/opencv4.5.1/include/opencv2
2. 头文件定义
在头文件中定义VideoCapture对象、Mat图像变量、以及相机初始化标志位;实现cvMatToQImage、QImagecvMat转换函数、显示函数,以及相关的按钮槽函数,此外需要重写定时器时间函数timerEvent函数。头文件内容如下所示。
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <opencv2/opencv.hpp>
#include <string.h>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
using namespace cv;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QImage cvMatToQImage(const cv::Mat& img);
Mat QImageTocvMat(const QImage & mat);
void Show();
VideoCapture cap;
Mat m_SrcImage;//源图像
bool m_bCameraFlag;
private slots:
void on_pb_OpenCamera_clicked();
void on_pb_CloseCamera_clicked();
private:
void timerEvent(QTimerEvent *event);
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
3. 源文件实现
在源文件进行函数定义以及构造函数的实现。
3.1 引入头文件
#include "mainwindow.h"
#include "ui_mainwindow.h"
3.2 实现MainWindow的构造函数
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
m_bCameraFlag = false;
ui->setupUi(this);
startTimer(50);//设置界面刷新延时
}
3.3 实现MainWindow的析构函数
MainWindow::~MainWindow()
{
delete ui;
}
3.4 实现显示函数
void MainWindow::Show()
{
if(m_bCameraFlag)
{
cap >> m_SrcImage; // 从相机读取图像帧
QImage qImage = cvMatToQImage(m_SrcImage);
QPixmap pixmap = QPixmap::fromImage(qImage).scaled(ui->lb_Show->size());
ui->lb_Show->setPixmap(pixmap);
}
}
3.5 实现定时器函数
void MainWindow::timerEvent(QTimerEvent *event)
{
Show();
}
3.6 实现打开相机的按钮槽函数
void MainWindow::on_pb_OpenCamera_clicked()
{
cap.open(1); // 打开默认的USB相机(如果有多个相机,可以根据需要选择相机索引)
if (!cap.isOpened()) {
// 相机无法打开,处理错误
return;
}
m_bCameraFlag=true;
}
3.7 实现关闭相机的按钮槽函数
void MainWindow::on_pb_CloseCamera_clicked()
{
cap.release(); // 释放相机资源
m_bCameraFlag = false;
}
3.8 实现QImage转换cv::Mat函数
cv::Mat MainWindow::QImageTocvMat(const QImage &image)
{
cv::Mat mat;
switch(image.format())
{
case QImage::Format_Grayscale8: //灰度图,每个像素点1个字节(8位)
case QImage::Format_Indexed8: //Mat构造:行数,列数,存储结构,数据,step每行多少字节
mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
break;
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: //RR,GG,BB字节顺序存储
mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
//opencv需要转为BGR的字节顺序
break;
}
return mat;
}
3.9 实现cv::Mat转换QImage函数
QImage MainWindow::cvMatToQImage(const Mat& mat)
{
switch (mat.type()) {
case CV_8UC1:{
QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
image.setColorCount(256);
for(int i = 0; i < 256; i++){
image.setColor(i, qRgb(i, i, i));
}
uchar *pSrc = mat.data;
for(int row = 0; row < mat.rows; row ++){
uchar *pDest = image.scanLine(row);
memcpy(pDest, pSrc, mat.cols);
pSrc += mat.step;
}
return image;
}
case CV_8UC3:{
const uchar *pSrc = (const uchar*)mat.data;
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
return image.rgbSwapped();
}
break;
case CV_8UC4:{
const uchar *pSrc = (const uchar*)mat.data;
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
return image.copy();
}
break;
default:
break;
}
return QImage();
}
4. 测试
测试效果如下图所示,已成功通过软件控制USB相机采集图像并显示在屏幕中。