• 最近在搞qt监控软件的需求,经查资料发现可以通过opencv来实现图像的处理,先将opencv以及相关事件做一记录。
  • 下图是本设计中关于C/S交互分布图,暂做记录


文章目录

  • 成果测试
  • 遗留问题
  • opencv
  • ffmpeg\SDL
  • QtRO(Qt remote objects)
  • rep 文件的产生(server & client 的信息交换接口)
  • opencv GPU加速解码
  • opencv 如何利用GPU加速
  • 遇到的问题:
  • 子线程完成图像采集并发送主线程-遇到的bug
  • QtRO 在子线程发送不了消息?
  • 异常指针导致程序异常退出


成果测试


greenBambooMonitoring_20230202


遗留问题

  1. opencv 读取视频帧cpu占用很高

opencv

  • Mat
    图像的存储容器。
  • 完成一个video设备录像的关键步骤
  1. 打开video设备,同时打开目标保存文件。
VideoCapture videoCap;
VideoWriter videoWrite;
videoCap.open(1);
videoWrite.open(".\\test.avi", CV_FOURCC('M','J','P','G'), 30.0, Size(640, 480), true);
  1. 每隔1ms,将一帧图像写入已经打开的视频文件
void videomonitorthread::run()
{
    QEventLoop loop;
    QTimer timer;
    timer.setInterval(0.001 *1000);
    connect(&timer, &QTimer::timeout, [&loop, this](){
        videoCap >> matFrame;
        if(!matFrame.empty())
       {
            videoWrite.write(matFrame);  //保存视频帧
            emit timerFrameSignal(matFrame);//发送到主线程通过ui显示
        }
    });
    timer.start();
    loop.exec();
    //关闭设备
    videoCap.release();
    videoWrite.release();//关闭打开的视频文件,否则视频文件可能无法打开
    timer.stop();
    qDebug()<<"running exit"<<endl;
}

ffmpeg\SDL

sdl 下载 sdl 输出设备

android opencv处理视频格式 opencv处理视频流_ide

QtRO(Qt remote objects)

关键词

解释

acquire

获得

source

词汇解释:信息来源

本文代之服务端(功能提供节点)

Replica

词汇翻译:复制品

本文代之客户端实体

QtRO解释
QtRO本质上是一个点对点的通信网络。每个进程通过QRemoteObjectNode接入QtRO网络。功能提供节点(可以理解为服务器)需要使用QRemoteObjectHost将一个提供实际功能的QObject派生类注册(rep定义的函数接口,两边信息交换的接口)进QtRO网络中,然后其他使用该功能的程序则通过各自的QRemoteObjectNode连接到该Host上,然后acquire一个该功能对象的Replica。等到该Replica初始化好后,该程序就能够使用Replica中的信号、槽以及属性,就好像功能类就在本地一样。

QtRO关键步骤

  • Server端需要把功能类通过QRemoteObjectHost的enableRemoting方法共享出来
  • Client连接到该QRemoteObjectHost,然后acquire到Replica
  • QtRO会自动初始化该Replica,待初始化完后客户端就可以用该Replica

rep 文件的产生(server & client 的信息交换接口)

新建两个工程分别为clientPro, serverPro,新建.rep文件(定义所需要的信息交换接口),rep文件参考。

server 端.pro文件添加:

REPC_SOURCE +=

./Reps/CommonInterface.rep

client端.pro添加:

REPC_REPLICA +=

./Reps/CommonInterface.rep

server & client的.pro都添加 Qt += remoteobjects,编译构建后产生在构建目录下(两个头文件是不一样的,头文件内容如下)。

android opencv处理视频格式 opencv处理视频流_子线程_02


opencv GPU加速解码

由于采用cpu解码图像太耗资源,同时经查阅资料得知,如果采用gpu解码,性能明显得到提升,但是gpu加速必须硬件支持,如下:

opencv只支持NVIDIA的cuda技术。AMD的显卡在opencv环境下无法使用GPU计算。

opencv 如何利用GPU加速

GPU加速,需要显卡支持之外,也需要一些库和配置
opencv 中文.论坛

遇到的问题:

子线程完成图像采集并发送主线程-遇到的bug

  • 问题 1:
    Q: Qt5.9 修改界面控件名称不生效;
    A: 删除Debug,重新构建,对比Debug目录下的ui文件和工程目录下的ui,发现Debug目录下ui文件中存在所修改的名称,但是工程目录下的没有,因此,备份工程目录下的文件,用Debug目录下的ui文件替换,编译正常。
  • 问题 2:
    Q: 在主线程th1 创建的子线程th2, th2中采用Qtimer + connect + eventloop 完成事件循环,当给出退出线程的条件时,程序报出如下警告。
QObject::startTimer: Timers cannot be started from another thread

A: 在run之外创建的对象也属于主线程(当前子线程类中的对象除了run内部的都属于主线程),定时器相关的逻辑和对象只能用在一个线程中使用,因此不能将父线程的timer对象用于子线程中。

  • 问题 3:
    Q: 点击主窗口的X关闭程序时,提示系统崩溃了,如下:
QThread: Destroyed while thread is still running
20:13:27: 程序异常结束。

A: 当关闭主线程时,子线程还处于运行状态,因此,需要等待并将所有子线程关闭完成,最后再关闭主线程。

  • 问题 4:
    QtRO实现server&client发送数据时出错-遇到的bug
    提示:
    qt.remoteobjects: connectionToSource is null
    问题原因:
    server端的QRemoteObjectHost通过enableRemoting注册rep文件接口后才设定Url,导致host的url未生效,或者没有与共享接口完成某种绑定,因此client通过acquire获取Replica后,使用时找不到主机的共享接口。
    正常的顺序如下:
//server 侧
    //host完成对提供实际功能的Qobject派生类的注册
    pRemoteObj = new QRemoteObjectHost(this);//创建remotehost,设置主机url
    pRemoteObj->setHostUrl(QUrl(NODE_ADDRESS));
    pInterfaceObj = new CommonInterface(this);//host注册rep信息交互对象
    pRemoteObj->enableRemoting(pInterfaceObj);
  • 问题 5
    申请堆内存大小设置 与实际操作内存大小不一致导致程序异常。
int len = (int)sizeof (MessageHeader) + (int)data.size();
   Message* replyMess = (Message*)malloc(sizeof(len));//只申请了int 4个字节空间
   memset(replyMess, 0, len); //因此这里就会导致访问越界

QtRO 在子线程发送不了消息?

如下对象在线程中使用时,定义和逻辑只能在同一个线程中使用,否则会出现一些问题。

  • QTimer
  • QtRO
    如果source的QtRO对象定义在父线程中,(发送消息是在子线程中实时的)source 通过rep的sig向client发送消息时,消息事发送不过去的,但是可以接收到client的消息(有知道原因的的伙伴可以留言,谢谢!),将QtRO对象定义在run()中可以解决消息发送不了的问题。

异常指针导致程序异常退出

  • client连接服务端socket断开时,服务端此时点击stop,程序异常退出
    服务端问题原因:
    1 服务端采用threadPool管理所有新建的线程,并且设置了线程退出时进行资源释放
    2 服务端所有新建线程都保存在一个set集合中
    因此:当socket断开连接时,根据服务端工作线程设定原理,工作线程会退出(此时该线程对象也会被销毁释放),但是服务端功能设定,点击stop时,会遍历set集合,使用之前保存的线程对象,但是由于set集合内部某些对象已经被销毁的,此时在使用就造成了程序异常。