opencv +qt + vs2015 实现多线程开启多个摄像头

opencv +qt + vs2015 实现多线程开启多个摄像头

总体结构

整个程序主要包含三个类:UI相关的类,名为four;opencv打开和读取摄像头的类,名为video;qt多线程的类,名为videothread。

代码

ui_four.h

/********************************************************************************
** Form generated from reading UI file 'four.ui'
**
** Created by: Qt User Interface Compiler version 5.10.1
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/

#ifndef UI_FOUR_H
#define UI_FOUR_H

#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QGraphicsView>
#include <QtWidgets/QGridLayout>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QLabel>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QSlider>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QToolBar>
#include <QtWidgets/QWidget>

QT_BEGIN_NAMESPACE

class Ui_fourClass
{
public:
    QWidget *centralWidget;
    QGridLayout *gridLayout_2;
    QGridLayout *gridLayout;
    QGraphicsView *graphicsView;
    QGraphicsView *graphicsView_2;
    QGraphicsView *graphicsView_3;
    QGraphicsView *graphicsView_4;
    QLabel *label;
    QSlider *horizontalSlider;
    QMenuBar *menuBar;
    QToolBar *mainToolBar;
    QStatusBar *statusBar;

    void setupUi(QMainWindow *fourClass)
    {
        if (fourClass->objectName().isEmpty())
            fourClass->setObjectName(QStringLiteral("fourClass"));
        fourClass->resize(648, 556);
        centralWidget = new QWidget(fourClass);
        centralWidget->setObjectName(QStringLiteral("centralWidget"));
        gridLayout_2 = new QGridLayout(centralWidget);
        gridLayout_2->setSpacing(6);
        gridLayout_2->setContentsMargins(11, 11, 11, 11);
        gridLayout_2->setObjectName(QStringLiteral("gridLayout_2"));
        gridLayout = new QGridLayout();
        gridLayout->setSpacing(6);
        gridLayout->setObjectName(QStringLiteral("gridLayout"));
        graphicsView = new QGraphicsView(centralWidget);
        graphicsView->setObjectName(QStringLiteral("graphicsView"));

        gridLayout->addWidget(graphicsView, 0, 0, 1, 1);

        graphicsView_2 = new QGraphicsView(centralWidget);
        graphicsView_2->setObjectName(QStringLiteral("graphicsView_2"));

        gridLayout->addWidget(graphicsView_2, 0, 1, 1, 1);

        graphicsView_3 = new QGraphicsView(centralWidget);
        graphicsView_3->setObjectName(QStringLiteral("graphicsView_3"));

        gridLayout->addWidget(graphicsView_3, 1, 0, 1, 1);

        graphicsView_4 = new QGraphicsView(centralWidget);
        graphicsView_4->setObjectName(QStringLiteral("graphicsView_4"));

        gridLayout->addWidget(graphicsView_4, 1, 1, 1, 1);

        label = new QLabel(centralWidget);
        label->setObjectName(QStringLiteral("label"));

        gridLayout->addWidget(label, 2, 1, 1, 1);

        horizontalSlider = new QSlider(centralWidget);
        horizontalSlider->setObjectName(QStringLiteral("horizontalSlider"));
        horizontalSlider->setOrientation(Qt::Horizontal);

        gridLayout->addWidget(horizontalSlider, 3, 0, 1, 1);


        gridLayout_2->addLayout(gridLayout, 0, 0, 1, 1);

        fourClass->setCentralWidget(centralWidget);
        menuBar = new QMenuBar(fourClass);
        menuBar->setObjectName(QStringLiteral("menuBar"));
        menuBar->setGeometry(QRect(0, 0, 648, 23));
        fourClass->setMenuBar(menuBar);
        mainToolBar = new QToolBar(fourClass);
        mainToolBar->setObjectName(QStringLiteral("mainToolBar"));
        fourClass->addToolBar(Qt::TopToolBarArea, mainToolBar);
        statusBar = new QStatusBar(fourClass);
        statusBar->setObjectName(QStringLiteral("statusBar"));
        fourClass->setStatusBar(statusBar);

        retranslateUi(fourClass);
        QObject::connect(horizontalSlider, SIGNAL(valueChanged(int)), fourClass, SLOT(setslide()));

        QMetaObject::connectSlotsByName(fourClass);
    } // setupUi

    void retranslateUi(QMainWindow *fourClass)
    {
        fourClass->setWindowTitle(QApplication::translate("fourClass", "four", nullptr));
        label->setText(QApplication::translate("fourClass", "TextLabel", nullptr));
    } // retranslateUi

};

namespace Ui {
    class fourClass: public Ui_fourClass {};
} // namespace Ui

QT_END_NAMESPACE

#endif // UI_FOUR_H

four.h

#pragma once

#include <QtWidgets/QMainWindow>
#include <QtGui/QPixmap>
#include <opencv2/opencv.hpp>
#include "ui_four.h"
#include "video.h"
#include <QThread>
#include <QDebug>

using namespace std;
using namespace cv;

class videothread;
class four;



class four : public QMainWindow
{
	Q_OBJECT

public:
	four(QWidget *parent = Q_NULLPTR);

private:
	Ui::fourClass ui;
	int slide = 0;
	/* 为了在graphview中显示图片,需要创建QGraphicsScene变量
	 * 这里只显示两个摄像头的视频,因此只创建两个QGraphicsScene变量;多个graphview控件不能使用同一个QGraphicsScene变量,否则会显示不正常
	 * 网上有些示例代码是在成员方法中创建这个变量,但是由于在显示视频时,需要循环执行显示图像的代码,不断地new会导致程序崩溃
	 */
	QGraphicsScene *scene_1 = new QGraphicsScene;   
	QGraphicsScene *scene_2 = new QGraphicsScene;

public slots:
	int setslide();    // 这是滑动条的槽函数,不必理会
	void show_image_1(QImage dstImage);  //分别在两个graphview中显示图像
	void show_image_2(QImage dstImage);

};



class videothread : public QThread
{
	Q_OBJECT

private:
	int cam;     //打开摄像头的索引
	int order;	//对应摄像头要在第几个graphview中进行显示

public:
	videothread(int cam, int order);
	~videothread();
	void run();   //qt多线程类需要重载run函数
	/*
	 * 多线程类中的run函数类似于主线程的main函数,
	 * 例如创建多线程类对象:videothread th1;   th1.start()之后便自动开始执行run函数
	 */

signals:
	/* 使用多线程可以同时读取两个摄像头的图像
	 * 但是在进行显示的时候需要操控UI界面中的控件,然而这一操作必须在主线程里执行
	 * 换言之,子线程不能对UI界面的控件进行修改
	 * 解决办法是当子线程读取图像以后,向主线程发送信号,并且将图像数据传送过去,然后由主线程中的槽函数执行显示图像的函数
	 */
	int singal_tomainthread(QImage dstImage); 
};



QImage cvMat2QImage(const Mat& mat);   //opencv的Mat数据类型转换为qt的QImage数据类型

four.cpp

#include "four.h"
#include <iostream>
using namespace std;


QImage cvMat2QImage(const cv::Mat& mat)    
{
	// 8-bits unsigned, NO. OF CHANNELS = 1
	if (mat.type() == CV_8UC1)
	{
		QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
		// Set the color table (used to translate colour indexes to qRgb values)
		image.setColorCount(256);
		for (int i = 0; i < 256; i++)
		{
			image.setColor(i, qRgb(i, i, i));
		}
		// Copy input Mat
		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;
		}
		pSrc = 0;
		return image;
	}
	// 8-bits unsigned, NO. OF CHANNELS = 3
	else if (mat.type() == CV_8UC3)
	{
		// Copy input Mat
		const uchar *pSrc = (const uchar*)mat.data;
		// Create QImage with same dimensions as input Mat
		QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
		pSrc = 0;
		return image.rgbSwapped();
	}
	else if (mat.type() == CV_8UC4)
	{
		// Copy input Mat
		const uchar *pSrc = (const uchar*)mat.data;
		// Create QImage with same dimensions as input Mat
		QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
		pSrc = 0;
		return image.copy();
	}
	else
	{
		return QImage();
	}
}


four::four(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);

	/* 在UI的类的构造函数中创建多线程对象,每一个对象表示一个线程;
	 * 之后连接多线程对象的信号和UI类中的槽函数
	 * 最后start()启动子线程
	 */
	videothread *th1 = new videothread(0, 1);    //这里必须用指针,否则构造函数执行完毕以后就会把局部变量删除
	QObject::connect(th1, SIGNAL(singal_tomainthread(QImage)), 
		this, SLOT(show_image_1(QImage)));
	th1->start();

	videothread *th2 = new videothread(1, 2);    //这里必须用指针,否则构造函数执行完毕以后就会把局部变量删除
	QObject::connect(th2, SIGNAL(singal_tomainthread(QImage)),
		this, SLOT(show_image_2(QImage)));
	th2->start();
}


int four::setslide()
{
	slide = ui.horizontalSlider->value();
	cout << slide;
	ui.label->setText(QString::number(slide, 10));
	return slide;
}


void four::show_image_1(QImage dstImage)
{
	scene_1->clear();   //清空scene_1的内容,否则addPixmap会导致scene_1占用的内存越来越大
	scene_1->addPixmap(QPixmap::fromImage(dstImage));
	ui.graphicsView->setScene(scene_1);
	ui.graphicsView->show();
}


void four::show_image_2(QImage dstImage)
{
	scene_2->clear();
	scene_2->addPixmap(QPixmap::fromImage(dstImage));
	ui.graphicsView_2->setScene(scene_2);
	ui.graphicsView_2->show();
}


videothread::videothread(int cam, int order)
{
	this->cam = cam;
	this->order = order;
}


videothread::~videothread()
{
}


void videothread::run()
{
	Camera frame;           
	frame.setcam(cam);     //设置要打开的摄像头的索引
	frame.open_camera();	//打开摄像头
	if (!frame.isopened())   //如果没有打开摄像头,则退出线程
	{
		qDebug() << "defeat";
		this->quit();
		waitKey(1000);
	}
	while(1)     //子线程进入死循环,不断地读取图像并发送信号
	{
		Mat srcImage = frame.read_frame();
		QImage dstImage = cvMat2QImage(srcImage);
		qDebug() << srcImage.rows << srcImage.cols << cam << order;
		emit singal_tomainthread(dstImage);
		msleep(50);
	}
}

video.h

#ifndef VIDEO_H
#define VIDEO_H


#include <opencv2/opencv.hpp>
using namespace cv;

class Camera
{
private:
	int camera_num = 0;
	Mat img;
	VideoCapture capture;


public:
	Camera();

	Camera(int cam);

	void setcam(int cam);

	void open_camera();

	Mat& read_frame();

	bool isopened();
};


#endif

video.cpp

#include "video.h"
#include <iostream>

Camera::Camera()
{
	
}


Camera::Camera(int cam)
{
	camera_num = cam;
}


void Camera::setcam(int cam)
{
	camera_num = cam;
}


void Camera::open_camera()
{
	if(!capture.open(camera_num))
		std::cout << "open camera defeat." << std::endl;
}


Mat& Camera::read_frame()
{
	capture >> img;
	return img;
}


bool Camera::isopened()
{
	if (capture.isOpened())
		return true;
	else
		return false;
}

main.cpp

#include "four.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	four w;
	w.show();
	return a.exec();
}

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值