天天看點

QT opencv讀取視訊資料,QLabel實時顯示圖像(定時器)簡述代碼因是公司項目,是以很多地方做了删減,但是大緻思路都在。

簡述

使用 Qt 做一個實時顯示視訊的Demo,這裡結合Opencv來做的。該視訊可以是從攝像頭實時擷取的資料,也可以是本地儲存的視訊資料。

簡述下思路:

  • 使用 QT 做一個檔案選擇器,選擇本地視訊;
  • 使用opencv讀取該視訊資料,将視訊分解成一幀一幀的圖像;
  • 利用定時器,定時的調用顯示圖像接口。(這裡使用QLabel顯示每一幀圖像;定時器的時間與視訊的幀率有關;);
注:這裡注重說明一點,這裡必須用定時器,而不可用 waitKey(),因QLabel是元件,使用waitKey()方法會使得QLabel資料堵塞,不能顯示。

代碼

界面展示:

QT opencv讀取視訊資料,QLabel實時顯示圖像(定時器)簡述代碼因是公司項目,是以很多地方做了删減,但是大緻思路都在。

1、初始化

QTimer m_timer = new QTimer(this);
VideoCapture m_cap = new VideoCapture();
//定時器信号關聯 
connect(m_timer, SIGNAL(timeout()), this, SLOT(slots_catchCap()));
           

2、選擇本地視訊路徑

//"選擇視訊"按鈕點選事件
void LeakDetectionSimulator::slots_chooseVideo_Btn_Clicked()
{
	//定義檔案對話框類
	QFileDialog *fileDialog = new QFileDialog(this);
	//定義檔案對話框标題
	fileDialog->setWindowTitle(QStringLiteral("選擇視訊"));
	//設定預設檔案路徑
	fileDialog->setDirectory(".");
	//設定檔案過濾器
	fileDialog->setNameFilter(tr("Video(*.mp4 *.avi *.mkv *.flv *.rmvb)"));
	//設定視圖模式
	fileDialog->setViewMode(QFileDialog::Detail);
	//列印所選擇的檔案的路徑
	QString fileName;
	if (fileDialog->exec())
	{
		fileName = fileDialog->selectedFiles()[0];
        //顯示選擇的視訊路徑
		ui.videoPath_LineEdit->setText(fileName);
	}
}
           

3、開始檢測

//“開始檢測”按鈕點選事件
void slots_start_Btn_Clicked()
{
	if (ui.start_Btn->text().compare(QStringLiteral("停止檢測")) == 0)
	{		
		//關閉定時器
		m_timer->stop();
		ui.imgShow_label->clear();
		PrintInfo("已停止檢測!");
		ui.start_Btn->setText(QStringLiteral("開始檢測"));
		return;
	}

	//擷取全局參數
	if (ui.videoPath_LineEdit->text().compare("") == 0)
	{
		QMessageBox::about(NULL, QStringLiteral("提示"), QStringLiteral("未選擇視訊,請選擇視訊後重新操作!"));
		return;
	}

	if (ui.interval_LineEdit->text().compare("") == 0)
	{
		QMessageBox::about(NULL, QStringLiteral("提示"), QStringLiteral("未輸入間隔時間,請檢查!"));
		return;
	}

    //打開視訊
    m_cap->open(QStr2Str(ui.videoPath_LineEdit->text()));
	if (m_cap->isOpened() == false)
    {
        PrintInfo("視訊未能打開!");
		return;
    }

	//擷取目前視訊幀率
	double rate = m_cap->get(CV_CAP_PROP_FPS);
	//每一幀之間的延時與視訊的幀率相對應
	m_delay = 1000 / rate;


	//開啟定時器
	m_timer->start(m_delay);

	PrintInfo("開始檢測!");

	ui.start_Btn->setText(QStringLiteral("停止檢測"));
}
           
//QString 轉 string (無中文論碼)
string QStr2Str(const QString qStr)
{
	QByteArray cdata = qStr.toLocal8Bit();
	return string(cdata);
}
           
//擷取圖像(定時器關聯的槽方法)
void slots_catchCap()
{
    m_cap->read(m_frame);

	if (m_frame.empty())
    {
        PrintInfo("視訊讀取完!");
		//關閉定時器
		m_timer->stop();
        return;
    }
	//顯示圖像
	ui.imgShow_label->setPixmap(QPixmap::fromImage(MatToQImage(m_frame)));
}
           
// Mat 轉換成 QImage
QImage MatToQImage(const cv::Mat &inMat)
{
	switch (inMat.type())
	{
		case CV_8UC4:		// 8-bit, 4 channel
		{
			QImage image(inMat.data,
				inMat.cols, inMat.rows,
				static_cast<int>(inMat.step),
				QImage::Format_ARGB32);

			return image;
		}

		case CV_8UC3:		// 8-bit, 3 channel
		{
			QImage image(inMat.data,
				inMat.cols, inMat.rows,
				static_cast<int>(inMat.step),
				QImage::Format_RGB888);

			return image.rgbSwapped();
		}

	
		case CV_8UC1:// 8-bit, 1 channel
		{
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
			QImage image(inMat.data,
				inMat.cols, inMat.rows,
				static_cast<int>(inMat.step),
				QImage::Format_Grayscale8); //Format_Alpha8 and Format_Grayscale8 were added in Qt 5.5
#else
			static QVector<QRgb>  sColorTable;

			// only create our color table the first time
			if (sColorTable.isEmpty())
			{
				sColorTable.resize(256);

				for (int i = 0; i < 256; ++i)
				{
					sColorTable[i] = qRgb(i, i, i);
				}
			}

			QImage image(inMat.data,
				inMat.cols, inMat.rows,
				static_cast<int>(inMat.step),
				QImage::Format_Indexed8);

			image.setColorTable(sColorTable);
#endif
			return image;
		}

		default:
//			qWarning() << "CVS::cvMatToQImage() - cv::Mat image type not handled in switch:" << inMat.type();
			break;
	}

	return QImage();
}
           

因是公司項目,是以很多地方做了删減,但是大緻思路都在。

繼續閱讀