Win10环境下,通过Qt+Opencv+QThread,实现多路USB摄像头数据显示至ui界面。主要思想是通过Opencv的VideoCapture类,及Qthread类中的moveToThread方法实现,此外由于VideoCapture类的open方法的参数为摄像头的索引号,当外接多个USB摄像头的时候有可能造成索引号顺序不固定的问题,通过判断摄像头的硬件ID,即每个摄像头的vid、pid码,以实现在ui界面固定的位置(QLabel)显示固定的摄像头画面。
本案例中USB摄像头与PC机之间的连接方式要特别注意,每个摄像头应该单独连接至PC机的各个USB接口,不能使用多个摄像头连接至单个USB hub,再将USB hub连接至PC机的方式,本人使用的笔记本自带一个摄像头,然后外接的两个摄像头分别连接在笔记本的两个USB接口上。
本篇博客工程文件夹内所有代码内容,请至此处下载。
本次方案中的Opnecv直接通过官网的windows环境下的.exe安装模式安装,将inclue文件夹及Lib文件夹放至工程文件夹内,并通过"$$PWD"指引到当前文件夹。
QT += core gui multimedia
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
camera.cpp \
main.cpp \
mainwindow.cpp
HEADERS += \
camera.h \
mainwindow.h
FORMS += \
mainwindow.ui
INCLUDEPATH += "$$PWD"/opencv/include\
"$$PWD"/opencv/include/opencv \
"$$PWD"/opencv/include/opencv2 \
Debug:
{
LIBS += "$$PWD"/opencv/lib/opencv_world3416d.lib \
"$$PWD"/VIDPID.lib
}
Release:
{
LIBS += "$$PWD"/opencv/lib/opencv_world3416.lib \
"$$PWD"/VIDPID.lib
}
DEFINES -= UNICODE
DEFINES += UMBCS
QMAKE_CXXFLAGS -= -Zc:strictStrings
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
#ifndef CAMERA_H
#define CAMERA_H
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
class Camera:public QObject
{
Q_OBJECT
public:
Camera();
~Camera();
signals:
void sendPicture(const QImage &img);
public slots:
void camNumber(const int &n);
void openCamera();
void mainwindowDisplay();
private:
VideoCapture capture;
Mat src_image;
int camera_num = 0;
};
#endif // CAMERA_H
#include "camera.h"
#include
Camera::Camera()
{
}
Camera::~Camera()
{
}
void Camera::camNumber(const int &n)
{
camera_num = n;
}
void Camera::openCamera()
{
capture.set(CV_CAP_PROP_FRAME_HEIGHT, 960);
capture.set(CV_CAP_PROP_FRAME_HEIGHT, 1280);
// capture.open(camera_num,cv::CAP_DSHOW);
capture.open(camera_num);
if(!capture.isOpened())
{
qDebug() << "camer_num:"<<camera_num<<"not open";
return;
}
}
void Camera::mainwindowDisplay()
{
qDebug() << camera_num;
capture >> src_image;
QImage img1 = QImage((const unsigned char*)src_image.data,
src_image.cols, src_image.rows,
QImage::Format_RGB888).rgbSwapped();
emit sendPicture(img1);
}
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
#include
#include
#include "camera.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_opencamera_clicked();
void recivePicture(QImage);
void recivePicture_1(QImage);
void recivePicture_2(QImage);
private:
Ui::MainWindow *ui;
QThread *firstThread;
Camera *MyCamThread;
QThread *secondThread;
Camera *MyCamThread_2;
QThread *thirdThread;
Camera *MyCamThread_3;
QTimer fps_timer;
QTimer fps_timer_1;
QTimer fps_timer_2;
// int camer_indx;
int A,B,C;
QList<QCameraInfo> camera_list;
};
#endif // MAINWINDOW_H
获取USB摄像头硬件ID的方法见此篇博客,将编译生成的lib文件放入工作文件夹。
#include "mainwindow.h"
#include "ui_mainwindow.h"
extern "C" __declspec(dllexport) int getCamIDFromPidVid(const char* pidvid);
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
camera_list = QCameraInfo::availableCameras();
for(auto i =0;i<camera_list.size();i++)
{
qDebug()<<camera_list.at(i).description();
}
const char* pidvid_0 = "vid_2894&pid_0004";
A = getCamIDFromPidVid(pidvid_0);
std::cout << A << std::endl;
const char* pidvid_1 = "vid_1e4e&pid_0109";
B = getCamIDFromPidVid(pidvid_1);
std::cout << B << std::endl;
const char* pidvid_2 = "vid_30c9&pid_0041";
C = getCamIDFromPidVid(pidvid_2);
std::cout << C << std::endl;
firstThread = new QThread;
MyCamThread = new Camera;
secondThread = new QThread;
MyCamThread_2 = new Camera;
thirdThread = new QThread;
MyCamThread_3 = new Camera;
MyCamThread->moveToThread(firstThread);
MyCamThread_2->moveToThread(secondThread);
MyCamThread_3->moveToThread(thirdThread);
fps_timer.setInterval(30);
connect(&fps_timer, SIGNAL(timeout()), MyCamThread, SLOT(mainwindowDisplay()));
connect(MyCamThread, SIGNAL(sendPicture(QImage)),this,SLOT(recivePicture(QImage)));
connect(&fps_timer, SIGNAL(timeout()), MyCamThread_2, SLOT(mainwindowDisplay()));
connect(MyCamThread_2, SIGNAL(sendPicture(QImage)),this,SLOT(recivePicture_1(QImage)));
connect(&fps_timer, SIGNAL(timeout()), MyCamThread_3, SLOT(mainwindowDisplay()));
connect(MyCamThread_3, SIGNAL(sendPicture(QImage)),this,SLOT(recivePicture_2(QImage)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::recivePicture(QImage img)
{
QImage newImg = img.scaled(ui->label->width(), ui->label->height());
ui->label->setPixmap(QPixmap::fromImage(newImg));
}
void MainWindow::recivePicture_1(QImage img)
{
QImage newImg = img.scaled(ui->label_2->width(), ui->label_2->height());
ui->label_2->setPixmap(QPixmap::fromImage(newImg));
}
void MainWindow::recivePicture_2(QImage img)
{
QImage newImg = img.scaled(ui->label_3->width(), ui->label_3->height());
ui->label_3->setPixmap(QPixmap::fromImage(newImg));
}
void MainWindow::on_pushButton_opencamera_clicked()
{
MyCamThread->camNumber(C);
MyCamThread_2->camNumber(B);
MyCamThread_3->camNumber(A);
MyCamThread->openCamera();
MyCamThread_2->openCamera();
MyCamThread_3->openCamera();
fps_timer.start();
firstThread->start();
secondThread->start();
thirdThread->start();
}
本篇博客工程文件夹内所有代码内容,请至此处下载。