最近须要应用 opencv,就简略写了一个测试示例并记录下来。
其中 QCamera 等相干的类同样能够实现以后性能。
仓库
性能
- 反对有线或 IP 摄像头连贯
- 反对视频流播放
- 反对多分辨率设置
- 反对视频录制
- 反对拍照
- 视频抽帧、拍照、录制等由独单线程解决
测试可用的视频流
CCTV1 高清 http://ivi.bupt.edu.cn/hls/cctv1hd.m3u8
CCTV3 高清 http://ivi.bupt.edu.cn/hls/cctv3hd.m3u8
CCTV5+ 高清 http://ivi.bupt.edu.cn/hls/cctv5phd.m3u8
CCTV6 高清 http://ivi.bupt.edu.cn/hls/cctv6hd.m3u8
camara.h
#ifndef CAMARA_H
#define CAMARA_H
#include <QImage>
#include <QObject>
#include <QThread>
#include <QTimer>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
Q_DECLARE_METATYPE(QImage);
/*
*@brief Camara 在独自线程中实现视频抽帧、拍照及录像性能
*@brief open、close 等是耗时操作,请保障在 Camara 线程工夫中实现调用(可思考异步槽函数、QMetaObject::invokeMethod)*/
class Camara : public QObject
{
Q_OBJECT
public:
Camara();
~Camara();
bool isOpened() const;
bool isTakevideoed() const;
QString getSavePath() const;
QSize getResolutions() const;
bool isTakeVideo() const;
signals:
void updateImage(QImage);
void statusChanged(bool isOpen);
public slots:
void openCamara(const QString &url);
void openCamara(int index);
void closeCamara();
void takePicture();
void takeVideo();
void setSavePath(const QString &path);
void setResolutions(const QSize &size);
private slots:
void tbegin();
void tend();
void captureCamara();
private:
QString m_savepath;
QAtomicInteger<bool> m_isTakepicture = false;
QAtomicInteger<bool> m_isTakevideo = false;
QAtomicInteger<bool> m_isflip = false;
QScopedPointer<cv::VideoCapture> m_capture;
QScopedPointer<cv::VideoWriter> m_writer;
QTimer *m_timer = nullptr;
QThread m_thread;
};
#endif // CAMARA_H
#include "camara.h"
#include <QDateTime>
Camara::Camara()
{moveToThread(&m_thread);
connect(&m_thread, &QThread::started, this, &Camara::tbegin);
connect(&m_thread, &QThread::finished, this, &Camara::tend);
m_thread.start(QThread::HighPriority);
}
Camara::~Camara()
{m_thread.quit();
m_thread.wait();}
void Camara::tbegin()
{m_capture.reset(new cv::VideoCapture);
m_writer.reset(new cv::VideoWriter);
m_timer = new QTimer(this);
m_timer->setTimerType(Qt::PreciseTimer);
connect(m_timer, &QTimer::timeout, this, &Camara::captureCamara);
}
void Camara::tend()
{closeCamara();
}
void Camara::openCamara(const QString &url)
{if (!m_capture->isOpened() && m_capture->open(url.toLatin1().data()))
{
m_isflip = false;
m_timer->start(33);
emit statusChanged(true);
}
else
{emit statusChanged(false);
}
}
void Camara::openCamara(int index)
{if (!m_capture->isOpened() && m_capture->open(index))
{
m_isflip = true;
m_timer->start(33);
emit statusChanged(true);
}
else
{emit statusChanged(false);
}
}
void Camara::closeCamara()
{m_timer->stop();
if (m_writer->isOpened())
m_writer->release();
if (m_capture->isOpened())
m_capture->release();}
void Camara::captureCamara()
{
cv::Mat originalframe;
cv::Mat flipframe;
*m_capture >> originalframe;
if (m_isflip)
cv::flip(originalframe, flipframe, 1);
else
flipframe = originalframe;
QImage img = QImage(flipframe.data, flipframe.cols, flipframe.rows, QImage::Format_RGB888).rgbSwapped();
if (!img.isNull())
{if (m_isTakepicture)
{
m_isTakepicture = !m_isTakepicture;
QString name = m_savepath + QDateTime::currentDateTime().toString("yyyy-MM-hh hh_mm_ss") + ".jpeg";
img.save(name, "jpeg");
}
if (m_isTakevideo)
{*m_writer << flipframe;}
updateImage(img);
}
originalframe.release();
flipframe.release();}
void Camara::takePicture()
{m_isTakepicture = true;}
void Camara::takeVideo()
{if (!m_isTakevideo)
{QString name = m_savepath + QDateTime::currentDateTime().toString("yyyy-MM-hh hh_mm_ss") + ".avi";
if (m_writer->open(name.toLatin1().data(), cv::VideoWriter::fourcc('M', 'J', 'P', 'G'), 30.0, cv::Size(m_capture->get(cv::CAP_PROP_FRAME_WIDTH), m_capture->get(cv::CAP_PROP_FRAME_HEIGHT)), true))
{m_isTakevideo = true;}
}
else
{
m_isTakevideo = false;
m_writer->release();}
}
void Camara::setSavePath(const QString &path)
{m_savepath = path + '/';}
void Camara::setResolutions(const QSize &size)
{if (m_capture->isOpened())
{m_capture->set(cv::CAP_PROP_FRAME_WIDTH, size.width());
m_capture->set(cv::CAP_PROP_FRAME_HEIGHT, size.height());
}
}
QString Camara::getSavePath() const
{return m_savepath;}
bool Camara::isOpened() const
{return m_capture->isOpened();
}
bool Camara::isTakevideoed() const
{return m_isTakevideo;}
QSize Camara::getResolutions() const
{
QSize ret;
ret.setWidth(m_capture->get(cv::CAP_PROP_FRAME_WIDTH));
ret.setHeight(m_capture->get(cv::CAP_PROP_FRAME_HEIGHT));
return ret;
}
bool Camara::isTakeVideo() const
{return m_writer->isOpened();
}