尝试利用opencv在qt窗口中打开视频并播放,且解析视频信息并显示。
get()
|
参数
PROPID | 来自cv :: VideoCaptureProperties的属性标识符(例如,cv :: CAP_PROP_POS_MSEC,cv :: CAP_PROP_POS_FRAMES,...)或来自视频I / O API后端的附加标志的属性标识符 |
返回
指定属性的值。查询VideoCapture实例使用的后端不支持的属性时返回值0
这是本程序中用到的代码,对于不同版本的opencv,参数略有不同,文中使用的是opencv4.1
参考教程:
https://blog.csdn.net/weixin_43477163/article/details/88691799
界面设计:
mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>427</width>
<height>464</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QPushButton" name="pushButton_open">
<property name="geometry">
<rect>
<x>30</x>
<y>20</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>open</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_pause">
<property name="geometry">
<rect>
<x>140</x>
<y>20</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>pause</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_play">
<property name="geometry">
<rect>
<x>250</x>
<y>20</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>play</string>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>30</x>
<y>60</y>
<width>54</width>
<height>12</height>
</rect>
</property>
<property name="text">
<string>视频信息:</string>
</property>
</widget>
<widget class="QLabel" name="label_image">
<property name="geometry">
<rect>
<x>43</x>
<y>151</y>
<width>331</width>
<height>221</height>
</rect>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
<widget class="QTextBrowser" name="textBrowser_info">
<property name="geometry">
<rect>
<x>100</x>
<y>50</y>
<width>256</width>
<height>81</height>
</rect>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>427</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QWidget>
#include <QTimer>
#include <QFileDialog>
#include <QPushButton>
#include <QImage>
#include <QString>
#include <QMessageBox>
#include <QDebug>
#include <QMainWindow>
#include "opencv2/opencv.hpp"
using namespace cv;
using namespace std;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
QImage MatToQImage2(const cv::Mat& mat);
void ShowImage(cv::Mat& mat);
private slots:
void on_pushButton_open_clicked();
void on_pushButton_play_clicked();
void ReadFrame();
void on_pushButton_pause_clicked();
private:
Ui::MainWindow *ui;
VideoCapture video;
QTimer *timer;
int fps;
QString videofileName;
std::string sfileName;
};
#endif // MainWindow_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
timer=new QTimer(this);
ui-> label_image->setScaledContents(true);//可以使图片完全按QWidget缩放,而不保持原视频比例
connect(timer,SIGNAL(timeout()),this,SLOT(ReadFrame()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_open_clicked()
{
videofileName = QFileDialog::getOpenFileName(
this, "open video",
".",
"video (*.avi *.mp4 *.flv));;All files (*.*)");
sfileName = videofileName.toStdString();
video.open(sfileName);
if(!video.isOpened()){
QMessageBox::information(this,tr("提示"),tr("视频没有打开"));
}
else {
int videoW = int( video.get(CAP_PROP_FRAME_WIDTH) );
int videoH = int( video.get(CAP_PROP_FRAME_HEIGHT) );
fps = int( video.get(CAP_PROP_FPS) );
//ui->widget_info->setVisible(true);
//ui->widget_show->setVisible(true);
ui->textBrowser_info->setText(QString("视频信息:%1").arg(videofileName));
ui->textBrowser_info->append(QString("视频尺寸:%2×%3").arg(videoW).arg(videoH));
ui->textBrowser_info->append(QString("视频帧率:%4").arg(fps));
Mat frame_start;
video >> frame_start;
ShowImage(frame_start);
}
}
void MainWindow::ShowImage(cv::Mat& mat)
{
//方法二,按比例缩放
QImage image=MatToQImage2(mat);
QPixmap pixmap = QPixmap::fromImage(image);
int width = ui->label_image->width();
int height = ui->label_image->height();
QPixmap fitpixmap = pixmap.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation);
//按比例缩放
ui->label_image->setPixmap(fitpixmap);
}
void MainWindow::on_pushButton_play_clicked()
{
timer->start(1000/fps);
}
void MainWindow::on_pushButton_pause_clicked()
{
timer->stop();
}
void MainWindow::ReadFrame()
{
Mat frame_now;
video >> frame_now;//读帧进frame
if (frame_now.empty())
{
QMessageBox::information(this, tr("warning"), tr("the video is end!"));
timer->stop();
}
else {
ShowImage(frame_now);
}
}
//图像格式转换
QImage MainWindow::MatToQImage2(const cv::Mat &mat)
{
QImage img;
int chana = mat.channels();
//依据通道数不同,改变不同的装换方式
if(3 == chana ){
//调整通道次序
cv::cvtColor(mat,mat,COLOR_BGR2RGB);
img = QImage(static_cast<uchar *>(mat.data),mat.cols,mat.rows,QImage::Format_RGB888);
}
else if(4 == chana )
{
//argb
img = QImage(static_cast<uchar *>(mat.data),mat.cols,mat.rows,QImage::Format_ARGB32);
}
else {
//单通道,灰度图
img = QImage( mat.cols, mat.rows , QImage::Format_Indexed8);
uchar * matdata = mat.data;
for(int row = 0 ; row <mat.rows ; ++row )
{
uchar* rowdata = img.scanLine( row );
memcpy(rowdata,matdata ,mat.cols);
matdata+=mat.cols;
}
}
return img;
}
由于我将播放窗口设置为了QMainWindow因此调节窗口大小时,无法产生原教程中QWeight中label随窗口大小变化的效果。