1.简单流程
首先通过opencv打开视频流,获取到数据帧,然后将数据帧转换为QT可识别的图像,显示到QT界面上。
2.opencv解码线程源码
//DecodeOpencv.h
class DecodeOpencv : public QThread
{
Q_OBJECT
Q_SIGNALS:
void sigSendFrame(cv::Mat mat);
public:
DecodeOpencv(QObject *parent = nullptr);
~DecodeOpencv();
public:
void setUrl(QString url);
void setStoped(bool stop);
protected:
void run();
private:
QString m_rtsp;
bool m_isStop = false;
};
//DecodeOpencv.cpp
DecodeOpencv::DecodeOpencv(QObject *parent)
: QThread(parent)
{
qRegisterMetaType<cv::Mat>("cv::Mat");
}
DecodeOpencv::~DecodeOpencv()
{
m_isStop = true;
}
void DecodeOpencv::setUrl(QString url)
{
m_rtsp = url;
}
void DecodeOpencv::setStoped(bool stop)
{
m_isStop = stop;
}
void DecodeOpencv::run()
{
cv::VideoCapture cap;
if (m_rtsp.isEmpty())
{
qDebug() << "未找到视频流地址";
return;
}
bool suc = false;
if (m_rtsp.contains("localhost:camera"))
{
suc = cap.open(0); //打开本地摄像头
}
else
{
suc = cap.open(m_rtsp.toStdString()); //打开网络流地址
}
if (!suc)
{
qDebug() << "播放失败";
return;
}
while (true)
{
if (!m_isStop)
{
cv::Mat frame;
cap >> frame;
if (frame.empty())
{
qDebug() << "播放帧解析失败";
continue;
}
emit sigSendFrame(frame);
}
else
{
qDebug() << "停止播放";
break;
}
}
}
3.QT界面
//ShowMatWidget.h
class ShowMatWidget : public QWidget
{
Q_OBJECT
public:
ShowMatWidget(QWidget *parent = Q_NULLPTR);
~ShowMatWidget();
private Q_SLOTS:
void slotBtnConnected();
void slotGetFrame(cv::Mat mat);
QImage cvMat2QImage(const cv::Mat& mat);
private:
Ui::ShowMatWidget ui;
DecodeOpencv *m_thread = nullptr;
};
//ShowMatWidget.cpp
ShowMatWidget::ShowMatWidget(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
m_thread = new DecodeOpencv(this);
connect(m_thread, &DecodeOpencv::sigSendFrame, this, &ShowMatWidget::slotGetFrame);
connect(ui.pushButton, &QPushButton::clicked, this, &ShowMatWidget::slotBtnConnected);
}
ShowMatWidget::~ShowMatWidget()
{
}
void ShowMatWidget::slotBtnConnected()
{
m_thread->setUrl(ui.lineEdit->text());
m_thread->start();
}
void ShowMatWidget::slotGetFrame(cv::Mat mat)
{
QImage image = cvMat2QImage(mat);
ui.label->setPixmap(QPixmap::fromImage(image));
}
QImage ShowMatWidget::cvMat2QImage(const cv::Mat& mat)
{
//8位,通道数为1
if (mat.type() == 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;
}
//8位,通道数为3
else if (mat.type() == CV_8UC3)
{
const uchar *pSrc = (const uchar*)mat.data;
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
return image.rgbSwapped();
}
//8位,通道数为4
else if (mat.type() == CV_8UC4)
{
qDebug() << "CV_8UC4";
const uchar *pSrc = (const uchar*)mat.data;
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
return image.copy();
}
//32位,通道数为3
else if (mat.type() == CV_32FC3)
{
cv::Mat temp;
mat.convertTo(temp, CV_8UC3);
const uchar *pSrc = (const uchar*)temp.data;
QImage image(pSrc, temp.cols, temp.rows, temp.step, QImage::Format_RGB888);
return image.rgbSwapped();
}
else
{
qDebug() << "ERROR: Mat could not be converted to QImage.";
return QImage();
}
}