- 最近在搞qt监控软件的需求,经查资料发现可以通过opencv来实现图像的处理,先将opencv以及相关事件做一记录。
- 下图是本设计中关于C/S交互分布图,暂做记录
文章目录
- 成果测试
- 遗留问题
- opencv
- ffmpeg\SDL
- QtRO(Qt remote objects)
- rep 文件的产生(server & client 的信息交换接口)
- opencv GPU加速解码
- opencv 如何利用GPU加速
- 遇到的问题:
- 子线程完成图像采集并发送主线程-遇到的bug
- QtRO 在子线程发送不了消息?
- 异常指针导致程序异常退出
成果测试
greenBambooMonitoring_20230202
遗留问题
- opencv 读取视频帧cpu占用很高
opencv
- Mat
图像的存储容器。 - 完成一个video设备录像的关键步骤
- 打开video设备,同时打开目标保存文件。
VideoCapture videoCap;
VideoWriter videoWrite;
videoCap.open(1);
videoWrite.open(".\\test.avi", CV_FOURCC('M','J','P','G'), 30.0, Size(640, 480), true);
- 每隔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 输出设备
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,编译构建后产生在构建目录下(两个头文件是不一样的,头文件内容如下)。
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集合内部某些对象已经被销毁的,此时在使用就造成了程序异常。