最近须要应用opencv,就简略写了一个测试示例并记录下来。
其中 QCamera 等相干的类同样能够实现以后性能。
仓库
性能
- 反对有线或IP摄像头连贯
- 反对视频流播放
- 反对多分辨率设置
- 反对视频录制
- 反对拍照
- 视频抽帧、拍照、录制等由独单线程解决
测试可用的视频流
CCTV1 高清 http://ivi.bupt.edu.cn/hls/cctv1hd.m3u8CCTV3 高清 http://ivi.bupt.edu.cn/hls/cctv3hd.m3u8CCTV5+ 高清 http://ivi.bupt.edu.cn/hls/cctv5phd.m3u8CCTV6 高清 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_OBJECTpublic: 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();}