最近须要应用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();}