最近需要使用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();
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。