目录
1、opencv介绍
opencv的全称是Open Source Computer Vision Library,是一个跨平台的计算机视觉库,底层代码由C++编写,拥有c++、python、java等接口。
因为其跨平台特性,被广泛运用于:人脸识别,图像处理、人机交互等领域。
2、效果图
本项目实现了通过opencv+qt播放视频的功能。其中用qt制作前端,opencv负责处理视频的解码过程。
3、下载并编译opencv源码,生成DLL
opencv下载地址:https://opencv.org/releases/
我选择的是3.4.12。点击sources下载源码。
打开cmake,编译源码出库。cmake下载地址:https://cmake.org/download/
因为我的vs是2015,然后本次的项目是基于x64编译的,所以勾选的是以上。
cmake结束后,打开OpenCV.sln。生成解决方案。
然后找到CMakeTargets。右键INSTALL,选择仅生成INSTALL
在install\x64\vc14的目录下,会有对应的bin目录和lib目录。分别存放着DLL和lib。
最后再切换到release,编译即可得到release版本的DLL。
4、核心代码
1、绘制视频图像
bool LMoviePlayer::eventFilter(QObject *e, QEvent *event)
{
if (e == this->_widget && event->type() == QEvent::Paint)
{
showImage();
}
return QWidget::eventFilter(e, event);
}
void LMoviePlayer::showImage()
{
QPainter painter;
painter.begin(this->_widget);
if(!_image.isNull())
painter.drawImage(0, 0, _image);
painter.end();
}
通过Qt的QPainter类提供的drawImage进行绘制。因为视频其实是一幅幅连续的图像组成,所以drawImage能够很好的显示视频的图像。
因为视频是在界面的子控件上显示的,所以需要注册事件过滤器,而不是重写paintEvent中进行。
2、opencv的Mat转QImage
void LMoviePlayer::onSendMat(cv::Mat mat)
{
Mat matDes;
uchar *buf = new uchar[_widget->width()*_widget->height() * 3];
_image = QImage(buf, _widget->width(), _widget->height(), QImage::Format_RGB888);
cv::resize(mat, matDes, Size(_image.size().width(), _image.size().height()));
cv::cvtColor(matDes, matDes, COLOR_BGR2RGB);
int matDesSize = matDes.cols*matDes.rows*matDes.elemSize();
memcpy(_image.bits(), matDes.data, matDesSize);
update();
}
mat对象通过信号槽传递而来,通过它可以获取到图像数据。因为opencv是按bgr存储像素,所以把它转换为rgb。QImage才能被绘制出来。
3、子线程读取视频,发出图像数据
void MovieWork::run()
{
Mat mat;
while (!_bIswork)
{
if(!_capture.isOpened()) continue;
if (!_capture.read(mat)) {
if(mat.empty()) continue;
}
emit sigSendMat(mat);
QThread::msleep(40); //25帧
}
}
通过继承QThread,重写run方法,实现子线程对视频数据的读取,解码过程被封装在了opencv的VideoCapture类中,
将解码到的数据通过Qt特有的信号槽发送到界面绘制类进行。
4、界面绘制
LMoviePlayer::LMoviePlayer(QWidget *parent)
: QWidget(parent)
{
_widget = new QWidget;
_widget->installEventFilter(this);
_openMovieBtn = new QPushButton;
_openMovieBtn->setText(TC("打开视频"));
_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QVBoxLayout *vlayout = new QVBoxLayout;
vlayout->setMargin(0);
vlayout->setSpacing(5);
vlayout->addWidget(_widget);
vlayout->addWidget(_openMovieBtn);
this->setMinimumSize(400, 300);
this->setLayout(vlayout);
_movieWork = new MovieWork(this);
qRegisterMetaType<cv::Mat>("cv::Mat");
connect(_movieWork, SIGNAL(sigSendMat(cv::Mat)), this, SLOT(onSendMat(cv::Mat)));
connect(_openMovieBtn, SIGNAL(clicked()), this, SLOT(onOpenMovie()));
}
这里需要注意的是qRegisterMetaType<cv::Mat>("cv::Mat");因为这个类型不是qt自带的类型,所以需要注册,qt的信号槽才能够识别并发送出来。
界面上通过QVBoxLayout进行垂直布局,对_widget这个现实视频的子控件设置为宽、高可扩展。
以上就是opencv+qt实现视频的播放,如需要完整源代码和opencv库,可以关注我的公众号 回复 LMoviePlayer 领取。