首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Qt实用技巧:使用OpenCV库操作摄像头拍照、调节参数和视频录制

Qt实用技巧:使用OpenCV库操作摄像头拍照、调节参数和视频录制

作者头像
OpenCV学堂
发布于 2019-11-11 15:17:40
发布于 2019-11-11 15:17:40
4.2K00
代码可运行
举报
运行总次数:0
代码可运行

投稿作者: 红模仿_红胖子 研究方向:OpenCV/OpenGL/QT/软硬件结合 博客地址:https://blog.csdn.net/qq21497936 文字编辑:gloomyfish

需求

使用OpenCV做功能,播放摄像头(usb和网络),对摄像头设备进行参数调整(亮度、对比度、饱和度、色调、增益、曝光度)调节,拍照和录像。

原理

使用OpenCV打开摄像头(可打开USB和网路哦摄像头),渲染图像显示,可使用OpenCV属性调整摄像头的各项参数,使用拍照可以将当前图片拍照,使用录像可以从当前时间点开始录像直至停止录像

注意

目前测试,即使PC上有编码器,但是OpenCV存储mat为对应的录像视频文件失败,出现:

  • 录制完视频大小为200多B(基本为0),mp4格式时(查看入坑一)
  • 录制完视频大小为6KB,avi格式时
  • 录制avi传入图像mat,源码内部出现错误宕机

运行效果:

核心代码

打开摄像头代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
bool OpenCVManager::startCapture(int usb, int width, int height)
{
    if(!_pVideoCapture->open(usb))
    {
        qDebug() << __FILE__ << __LINE__ << "Failed to start capture :" << usb;
        return false;
    }
    _width = width;
    _height = height;
    _pVideoCapture->set(CV_CAP_PROP_FRAME_WIDTH, _width);
    _pVideoCapture->set(CV_CAP_PROP_FRAME_HEIGHT, _height);
    _width = _pVideoCapture->get(CV_CAP_PROP_FRAME_WIDTH);
    _height = _pVideoCapture->get(CV_CAP_PROP_FRAME_HEIGHT);
    _pVideoCapture->set(CV_CAP_PROP_FPS, 25);
    _brightness  = _pVideoCapture->get(cv::CAP_PROP_BRIGHTNESS);
    _contrast    = _pVideoCapture->get(cv::CAP_PROP_CONTRAST);
    _saturation  = _pVideoCapture->get(cv::CAP_PROP_SATURATION);
    _hue         = _pVideoCapture->get(cv::CAP_PROP_HUE);
    _gain        = _pVideoCapture->get(cv::CAP_PROP_GAIN);
    _exposure    = _pVideoCapture->get(cv::CAP_PROP_EXPOSURE);
    QTimer::singleShot(0, this, SLOT(slot_captrueFrame()));
    return true;
}

调整属性代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
bool OpenCVManager::getShowProperty() const
{
    return _showProperty;
}

void OpenCVManager::setShowProperty(bool value)
{
    _showProperty = value;
}

double OpenCVManager::getBrightness()
{
    return _brightness;
}

void OpenCVManager::setBrightness(double value)
{
    _brightness = value;
    if(_pVideoCapture)
    {
        _pVideoCapture->set(cv::CAP_PROP_BRIGHTNESS, _brightness);
    }
}

double OpenCVManager::getContrast() const
{
    return _contrast;
}

void OpenCVManager::setContrast(double value)
{
    _contrast = value;
    if(_pVideoCapture)
    {
        _pVideoCapture->set(cv::CAP_PROP_CONTRAST, _contrast);
    }
}

double OpenCVManager::getSaturation() const
{
    return _saturation;
}

void OpenCVManager::setSaturation(double value)
{
    _saturation = value;
    if(_pVideoCapture)
    {
        _pVideoCapture->set(cv::CAP_PROP_SATURATION, _saturation);
    }
}

double OpenCVManager::getHue() const
{
    return _hue;
}

void OpenCVManager::setHue(double value)
{
    _hue = value;
    if(_pVideoCapture)
    {
        _pVideoCapture->set(cv::CAP_PROP_HUE, _hue);
    }
}

double OpenCVManager::getGain() const
{
    return _gain;
}

void OpenCVManager::setGain(double value)
{
    _gain = value;
    if(_pVideoCapture)
    {
        _pVideoCapture->set(cv::CAP_PROP_GAIN, _gain);
    }
}

double OpenCVManager::getExposure() const
{
    return _exposure;
}

void OpenCVManager::setExposure(double value)
{
    _exposure = value;
    if(_pVideoCapture)
    {
        _pVideoCapture->set(cv::CAP_PROP_EXPOSURE, _exposure);
    }
}

拍照代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void PhotoAndRecordWidget::on_pushButton_photo_clicked()
{
    QString timeStr = QDateTime::currentDateTime().toString("yyyy-MM-hh hh_mm_ss");
    QString dirName = "photos";
    if(!QFile::exists(dirName))
    {
        QDir dir;
        if(!dir.mkdir(dirName))
        {
            ui->label_state->setText("创建文件夹 " + dirName + "失败!!!");
        }
    }
    QString filePath = QString("%1/%2.png").arg(dirName).arg(timeStr);
    if(_image.save(filePath))
    {
        ui->label_state->setText("保存照片至: " + filePath);
    }else{
        ui->label_state->setText("保存照片失败!!!");
    }
}

录像代码

开启录像

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void OpenCVManager::startRecord(QString pathFile)
{
    // 多线程处理
    QMetaObject::invokeMethod(this, "slot_startRecord",
                              Qt::DirectConnection, Q_ARG(QString, pathFile));
}
void OpenCVManager::slot_startRecord(QString filePath)
{
    if(_pVideoWrite)
    {
        qDebug() << __FILE__ << __LINE__ << "It's recording!!!";
        return;
    }
    _pVideoWrite = new cv::VideoWriter;
    QString ext = filePath.mid(filePath.lastIndexOf(".") + 1);
    int cvFourcc = 0;
    if(ext == "mpg")
    {
        cvFourcc = CV_FOURCC('D','I','V','X');
        qDebug() << __FILE__ << __LINE__<< ext << "DIVX" << cvFourcc;
    }else if(ext == "avi")
    {
        cvFourcc = CV_FOURCC('M','J','P','G');
        qDebug() << __FILE__ << __LINE__<< ext << "MJPG" << cvFourcc;
    }else if(ext == "mp4")
    {
        // mp4目前录制不成功(可以生成文件,但是打开失败)
//        cvFourcc = CV_FOURCC('M','P','4','2');
        cvFourcc = CV_FOURCC('M','J','P','G');
//        cvFourcc = CV_FOURCC('I', 'Y', 'U', 'V');
        qDebug() << __FILE__ << __LINE__<< ext << "MP42" << cvFourcc;
    }
    _pVideoWrite->open(filePath.toStdString(), cvFourcc, 25, cv::Size(_width, _height));

    _recordFilePath = filePath;
    _recording = true;
}

录像过程

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void OpenCVManager::slot_captrueFrame()
{
    if(!_running)
    {
        return;
    }
    if(_pVideoCapture->isOpened())
    {
        cv::Mat mat;
        *_pVideoCapture >> mat;
        if(_showProperty)
        {
            cv::putText(mat, QString("brightness: %1").arg(_brightness).toStdString(),
                        cvPoint(0, 30), cv::FONT_HERSHEY_COMPLEX, 1.0, cv::Scalar(255));
            cv::putText(mat, QString("  contrast: %1").arg(_contrast  ).toStdString(),
                        cvPoint(0, 60), cv::FONT_HERSHEY_COMPLEX, 1.0, cv::Scalar(255));
            cv::putText(mat, QString("saturation: %1").arg(_saturation).toStdString(),
                        cvPoint(0, 90), cv::FONT_HERSHEY_COMPLEX, 1.0, cv::Scalar(255));
            cv::putText(mat, QString("       hue: %1").arg(_hue       ).toStdString(),
                        cvPoint(0, 120), cv::FONT_HERSHEY_COMPLEX, 1.0, cv::Scalar(255));
            cv::putText(mat, QString("      gain: %1").arg(_gain      ).toStdString(),
                        cvPoint(0, 150), cv::FONT_HERSHEY_COMPLEX, 1.0, cv::Scalar(255));
            cv::putText(mat, QString("  exposure: %1").arg(_exposure  ).toStdString(),
                        cvPoint(0, 180), cv::FONT_HERSHEY_COMPLEX, 1.0, cv::Scalar(255));
            cv::putText(mat, QString("press ESC out").toStdString(),
                        cvPoint(0, 210), cv::FONT_HERSHEY_COMPLEX, 1.0, cv::Scalar(255));
        }
        if(_recording)
        {
            _pVideoWrite->write(mat);
        }
        emit signal_captureOneFrame(mat);
        QTimer::singleShot(10, this, SLOT(slot_captrueFrame()));
    }
}

关闭录像

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void OpenCVManager::stopRecord()
{
    // 多线程处理
    QMetaObject::invokeMethod(this, "slot_stopRecord", Qt::DirectConnection);
}

void OpenCVManager::slot_stopRecord()
{
    if(_pVideoWrite)
    {
        _recording = false;
        _pVideoWrite->release();
        delete _pVideoWrite;
        _pVideoWrite = 0;
    }
}

入坑记录

入坑一:录制视频保存为空

解决方法:

编解码器得问题,cv::VideoWrite查阅相关资料发现其只支持固定的几个格式,其中就包括avi。

入坑二:录制视频奔溃

原因:

因为初始设置摄像头的宽高(400 x 400),根据测试推断摄像头会默认给最接近初始化设置的分辨率,但是却不是直接是设置的(400 x 400)而是返回了最接近的分辨率(320 x 240),除非设置的分辨率正好是摄像头本身支持。

所以设置分辨率是需要摄像头硬件支持。

解决方法:

进一步验证同时解决该问题

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-11-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 OpenCV学堂 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
简单工厂模式都不会,你真应该去工厂搬砖!
创建型模式关注对象的创建过程,在软件开发中应用非常广泛。创建型模式描述如何将对象的创建和使用分离,让用户在使用对象过程中无须关心对象的创建细节,从而降低系统耦合度,并且让系统易于修改和扩展。
用户6557940
2022/07/24
2120
简单工厂模式都不会,你真应该去工厂搬砖!
学会工厂方法模式,搬起砖头更加给力!
在介绍简单工厂方法模式时Jungle总结出简单工厂模式存在最大的问题是违背了“开闭原则”,每当增加新的产品时,需要修改工厂类的逻辑。为了规避这种不足,同时很好的利用简单工厂模式的优点,本节Jungle将声情并茂地为您奉上工厂方法模式。
用户6557940
2022/07/24
2000
学会工厂方法模式,搬起砖头更加给力!
设计模式之简单工厂模式
简单工厂模式 Simple Factory Pattern 也叫静态工厂方法模式 Static Factory Method Pattern,隶属于设计模式中的创建型模式。简单工厂通过一个静态方法来给使用方提供类创建的方式,将对象创建的控制权由使用方转换到提供方,可以将使用方和提供方具体的实现解耦,提供方就可以在用户无感知的情况下进行具体实现的替换。
Dylan Liu
2019/08/05
3710
「聊设计模式」之简单工厂模式(Simple Factory)
🏆本文收录于 《聊设计模式》 专栏,专门攻坚指数级提升,助你一臂之力,早日登顶🚀,欢迎持续关注&&收藏&&订阅!
bug菌
2023/10/30
7342
「聊设计模式」之简单工厂模式(Simple Factory)
【设计模式】-创建型模式-第2章第2讲-【工厂模式】
2.1、案例场景:假设有一个汽车工厂,目前只生产两种车型,小型跑车和大型家用车。顾客决定买小还是大型。
跟着飞哥学编程
2022/12/02
2940
Java设计模式学习记录-简单工厂模式、工厂方法模式
之前介绍了设计模式的原则和分类等概述。今天开启设计模式的学习,首先要介绍的就是工厂模式,在介绍工厂模式前会先介绍一下简单工厂模式,这样由浅入深来介绍。
纪莫
2018/07/24
3160
Java设计模式学习记录-简单工厂模式、工厂方法模式
简单工厂模式
简单工厂模式(Simple Factory Pattern)属于类的创新型模式,又叫静态工厂方法模式(Static FactoryMethod Pattern),是通过专门定义一个类来负责创建其它类的实例,被创建的实例通常都具有共同的父类。
全栈程序员站长
2021/12/12
2930
简单工厂模式
详解设计模式:简单工厂模式
工厂方法是一种十分常用的创建型设计模式,它在父类中提供了创建对象的接口但允许子类更改将要创建的对象的类型。
栗筝i
2022/12/02
3820
详解设计模式:简单工厂模式
Java设计模式-工厂模式(1)简单工厂模式
设计一个咖啡类(Coffee),并定义其两个子类(美式咖啡【AmericanCoffee】和拿铁咖啡【LatteCoffee】);再设计一个咖啡店类(CoffeeStore),咖啡店具有点咖啡的功能。
宁在春
2022/10/31
3160
Java设计模式-工厂模式(1)简单工厂模式
抽象工厂模式——工厂方法的大结局
回顾之前的设计模式,简单工厂模式所有逻辑都封装在工厂类中,工厂根据客户提供的产品名字创建对应产品的对象实例;工厂方法模式将产品的创建过程放到了具体工厂类中,每一个工厂可以创建一个具体产品,由此可能会创建许多工厂类。很多时候,一个工厂不只是生产一种产品,而是生产一类产品,比如一个体育用品工厂,可以生产篮球、足球、排球等多种产品。此时我们可以把这些相关的产品归纳为一个“产品族”,由同一个工厂来生产,这即是Jungle今天要学习的抽象工厂模式。
用户6557940
2022/07/24
5700
抽象工厂模式——工厂方法的大结局
Java设计模式:工厂模式之简单工厂、工厂方法、抽象工厂(三)
在软件设计中,工厂模式是一种常见的设计模式,它提供了一种创建对象的最佳方式。通过工厂模式,我们可以将对象的创建逻辑与使用逻辑分离,降低代码的耦合度,提高系统的可扩展性和可维护性。
公众号:码到三十五
2024/03/19
2470
Java设计模式-工厂模式
简单来说工厂模式就是帮助我们创建对象,隐藏了对象创建过程的复杂度(如类B需要调用类A,工厂类提供A类的创建接口,B只需要调用接口传入相应参数即可)、避免你辛苦的准备构造方法的参数。说白了--就是工厂提供产品给客户(按照提供的方式不同分成三类:简单工厂、工厂、抽象工厂) 具体简介看下面:
蒋老湿
2020/01/03
5920
设计模式-简单工厂
使用工厂方法模式可以应付我们遇到的大部分需求,当产品种类变多的时候,这个时候会出现大量的工厂类,怎么解决这个问题?可以对产品树上类似的种类使用简单工厂模式来实现。也就是说 工厂方法+简单工厂= 抽象工厂。
王小明_HIT
2020/11/11
3660
设计模式一:简单工厂模式
简单工厂模式属于创建型模式,又叫做静态工厂方法(Static Factory Method)。简单工厂模式是由一个工厂对象决定创建哪一种产品类实例。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为不同工厂模式的一个特殊实现
对弈
2019/09/29
4170
设计模式一:简单工厂模式
小谈设计模式(2)—简单工厂模式
主要对目前市面上常见的23种设计模式进行逐一分析和总结,希望有兴趣的小伙伴们可以看一下,会持续更新的。希望各位可以监督我,我们一起学习进步,加油,各位。
学编程的小程
2023/10/11
2330
小谈设计模式(2)—简单工厂模式
设计模式-简单工厂模式
模式定义 简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式定义了一个创建对象的类,由这个类来封装实例化
武培轩
2018/04/18
6730
设计模式-简单工厂模式
一起学习设计模式--02.简单工厂模式
工厂模式是最常用的一类创建型设计模式。我们所说的工厂模式是指工厂方法模式,它也是使用频率最高的工厂模式。
独立观察员
2022/12/06
3310
一起学习设计模式--02.简单工厂模式
设计模式--简单工厂模式
简单工厂模式是一种创建型模式,它可以根据参数的不同返回不同类的实例,通常用一个静态方法来实现工厂的功能,这个方法就叫做简单工厂。简单工厂模式的优点是可以将对象的创建和使用分离,降低客户端的复杂度;缺点是不符合开闭原则,如果要增加新的产品类,就需要修改工厂类的代码。
软件架构师Michael
2023/06/13
2790
『设计模式』简单工厂模式
简单工厂模式也被称为静态工厂模式;使用简单工厂模式可以将产品的“消费”和生产完全分开,客户端只需要知道自己需要什么产品,如何来使用产品就可以了,具体的产品生产任务由具体的工厂类来实现。工厂类根据传进来的参数生产具体的产品供消费者使用。这种模式使得更加利于扩展,当有新的产品加入时仅仅需要在工厂中加入新产品的构造就可以了。
风骨散人Chiam
2020/10/28
3810
设计模式 - 简单工厂模式
在这个问题中,沙发上的你,是苹果对象的使用者。超市(果农场)是苹果对象的生产者,可以理解为工厂。
子乾建建-Jeff
2020/06/29
4650
设计模式 - 简单工厂模式
相关推荐
简单工厂模式都不会,你真应该去工厂搬砖!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档