现在网络上开源的OpenCV打开摄像头大多还是用死循环的方式,这里采用OpenCV+Qt多线程打开多个摄像头,并在一个界面上显示。本例程打开四个USB摄像头,三个型号一样,另一个型号不一样,原本想打开四个型号一样的,但是不知道为什么有一个就是打不开,现在还在查找原因。下面结合代码来讲解。
头文件thread_cam.h中定义了子线程类thread_cam,继承于QThread,功能是打开摄像头并将拍到的图片传回主线程显示,代码如下:
#ifndef THREAD_CAM_H
#define THREAD_CAM_H
#include
#include
#include "opencv2/core/core.hpp"
#include "opencv2/videoio/videoio.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgcodecs/imgcodecs.hpp"
#include "opencv2/highgui/highgui.hpp"
#include
#include
using namespace cv;
using namespace std;
class thread_cam : public QThread
{
Q_OBJECT
public:
explicit thread_cam(QObject *parent = 0);
thread_cam(int set_count=0)//记录打开了多少个摄像头
{
count=set_count;
}
void show_cam();
protected:
void run();
private:
int count;
QTimer *timer;
Mat img;
QImage Qimg;
VideoCapture cap;
signals:
void return_QImage(QImage);//通过信号将子线程中采集的图片传回主线程
public slots:
};
#endif // THREAD_CAM_H
widget.h里面则不用多说了,直接看代码:
#ifndef WIDGET_H
#define WIDGET_H
#include
#include "thread_cam.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void get_QImage1(QImage);
void get_QImage2(QImage);
void get_QImage3(QImage);
void get_QImage4(QImage);
private:
Ui::Widget *ui;
thread_cam *thread_cam1;
thread_cam *thread_cam2;
thread_cam *thread_cam3;
thread_cam *thread_cam4;
QImage image;
};
#endif // WIDGET_H
thread_cam.cpp里是子线程类的实现,这里讲图片作为信号参数直接传回主程序会导致速度变慢,以后再想办法改进。
#include "thread_cam.h"
#include
thread_cam::thread_cam(QObject *parent) : QThread(parent)
{
}
void thread_cam::run()
{
cap=VideoCapture(count);
QString massage=QString("camera%1 opens fail").arg(count);
if(!cap.isOpened())
{
qDebug()<start(100);
connect(timer,&QTimer::timeout,this,&thread_cam::show_cam);
this->exec();//此句必须有,否则线程会立即结束
}
void thread_cam::show_cam()
{
cap>>img;
cvtColor(img,img,CV_BGR2RGB);//opencv中的图片以BGR格式保存,Qt中是RGB,故先转换格式再将Mat转为QImage
QImage Qimg((uchar*) img.data, img.cols, img.rows, img.step, QImage::Format_RGB888 );
QString cam_name=QString("camera%1").arg(count);
//imshow(cam_name.toStdString(),img);
emit return_QImage(Qimg);
}
接下来就是主线程里处理的东西:
#include "widget.h"
#include "ui_widget.h"
#include
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
thread_cam1=new thread_cam(0);
thread_cam2=new thread_cam(1);
thread_cam3=new thread_cam(2);
thread_cam4=new thread_cam(3);
connect(thread_cam1,&thread_cam::return_QImage,this,&Widget::get_QImage1);
connect(thread_cam2,&thread_cam::return_QImage,this,&Widget::get_QImage2);
connect(thread_cam3,&thread_cam::return_QImage,this,&Widget::get_QImage3);
connect(thread_cam4,&thread_cam::return_QImage,this,&Widget::get_QImage4);
}
Widget::~Widget()
{
delete ui;
}
void Widget::get_QImage1(QImage img_temp)
{
image=img_temp;
image.scaled(ui->label->width(),ui->label->height());
ui->label->setPixmap(QPixmap::fromImage(image));
}
void Widget::get_QImage2(QImage img_temp)
{
image=img_temp;
image.scaled(ui->label_2->width(),ui->label_2->height());
ui->label_2->setPixmap(QPixmap::fromImage(image));
}
void Widget::get_QImage3(QImage img_temp)
{
image=img_temp;
image.scaled(ui->label_3->width(),ui->label_3->height());
ui->label_3->setPixmap(QPixmap::fromImage(image));
}
void Widget::get_QImage4(QImage img_temp)
{
image=img_temp;
image.scaled(ui->label_4->width(),ui->label_4->height());
ui->label_4->setPixmap(QPixmap::fromImage(image));
}
void Widget::on_pushButton_clicked()
{
thread_cam1->start();//启动线程
thread_cam2->start();
thread_cam3->start();
thread_cam4->start();
}
void Widget::on_pushButton_2_clicked()
{
thread_cam1->quit();//关闭线程
thread_cam2->quit();
thread_cam3->quit();
thread_cam4->quit();
}
最后看看效果: