得益于标准的onvif协议,各大监控厂商的设备都会支持onvif协议,在onvif协议中就包括了事件订阅机制,通过这个机制,可以拿到各种报警事件,比如移动侦测/遮挡报警/区域入侵/越界侦测/报警输入输出等,这样就不用自己去搞算法识别,相当于前端设备在后台配置好以后都自己运算掉,客户端这边就没有什么压力,分散在各个前端设备去处理,和有个高大上的名词叫什么边缘计算类似。如果在客户端这边处理这么多通道的算法识别,每个通道每秒钟起码要拿到一张图片去处理,运算压力非常大,而且很多算法默认走的CPU,搞得CPU占用很高,本来64个通道就几乎要把这个电脑的CPU榨干,哪里还有更多的空闲CPU留给算法运算,除非用专门的算法服务器,要么搞点简单的运算,要么强劲的配置,要么走fpga这种专用加速。如果是要从简单通用着手,兼容各大厂家的设备,就走onvif协议,拿到报警事件后,再通过onvif抓图或者直接打开的通道截图即可,这样就完美的组成了图文警情模块,一旦识别到某个摄像头报警,解析出对应的事件内容,抓图或者截图完成后,将文字信息和抓拍图片插入到图文警情列表中,一般都是最新的插入在最前面,当然也可以自行设置报警等级。
最初做的收到报警事件后就抓图写在一起,在只有几个通道或者分开报警的时候,还能处理,一旦通道多了,而且多个通道同时报警的话,很可能卡主,而且可能由于来不及处理导致丢掉一些事件,所以后面改成了专门线程处理,保证抓图完成后再插入到图文警情列表中。在线程中采用万能办法QMetaObject::invokeMethod和UI交互。
由于onvif事件有多种,而且不同厂家对应关键字对应的事件含义可能不一样,要做就做完美一点,所以又增加了事件字典表,对应内容 事件等级/唯一标识/报警字样/解除字样,用户如果有自己特有的可以自行打开这个字典表增加即可,而且这个字典表还可以用来过滤,比如不在这个字典表中的就不处理,按照用户需要的来。
常用几种事件字典:
onvif主要功能:

#include "onvifevent.h"
OnvifEvent::OnvifEvent(QObject *parent) : QObject(parent)
{
device = (OnvifDevice *)parent;
//事件定时器请求事件地址
timerEvent = new QTimer(this);
connect(timerEvent, SIGNAL(timeout()), this, SLOT(getEvent()));
timerEvent->setInterval(10 * 60 * 1000);
//消息定时器请求事件内容
timerMessage = new QTimer(this);
connect(timerMessage, SIGNAL(timeout()), this, SLOT(pullMessage()));
timerMessage->setInterval(1 * 60 * 1000);
}
void OnvifEvent::receiveEvent(const OnvifEventInfo &event)
{
if (!event.dataName.isEmpty()) {
emit receiveEvent(device->onvifAddr, event);
//正确格式 2020-10-10T08:40:14Z|LogicalState>|1
//过滤格式 2020-10-10T08:23:11.000000Z|State|true>
if (event.time.length() != 20) {
return;
}
}
pullMessage();
}
QString OnvifEvent::getEvent(const QString &timeout)
{
//读取文件传入带用户认证的通用头部数据和其他参数构建要发送的数据
QString file = OnvifHelper::getFile(":/onvifsend/CreatePullPointSubscription.xml");
file = file.arg(device->getHeadData()).arg(timeout);
//发送网络请求
QByteArray dataSend = file.toUtf8();
QNetworkReply *reply = device->request->post(device->eventUrl, dataSend, OnvifRequest::timeout + 500);
//拿到请求结果并处理数据
QByteArray dataReceive;
bool ok = device->checkData(reply, dataReceive, "订阅事件服务");
if (ok) {
//解析事件请求地址
OnvifQuery query;
if (query.setData(dataReceive)) {
eventAddr = query.getEventAddr();
QTimer::singleShot(100, this, SLOT(pullMessage()));
}
}
//启动事件定时器
if (!timerEvent->isActive()) {
timerEvent->start();
}
//启动消息定时器
if (!timerMessage->isActive()) {
//timerMessage->start();
}
return eventAddr;
}
void OnvifEvent::pullMessage(const QString &timeout)
{
QMutexLocker locker(&mutex);
if (eventAddr.isEmpty()) {
return;
}
emit receiveInfo(QString("请求事件 -> %1").arg(eventAddr));
//读取文件传入带用户认证的通用头部数据和其他参数构建要发送的数据
QString uuid = OnvifHelper::getUuid();
QString file = OnvifHelper::getFile(":/onvifsend/PullMessages.xml");
file = file.arg(device->getUserToken()).arg(uuid).arg(eventAddr).arg(timeout);
//发送网络请求
QByteArray dataSend = file.toUtf8();
device->request->post2(eventAddr, dataSend);
}
我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby数组,我们在StackOverflow上找到一
我想用ruby编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序
当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。 准备工作: 1、U盘一个(尽量使用8G以上的U盘)。 2、一台正常联网可使用的电脑。 3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。 4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。 U盘启动盘制作步骤: 注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/
我从Ubuntu服务器上的RVM转移到rbenv。当我使用RVM时,使用bundle没有问题。转移到rbenv后,我在Jenkins的执行shell中收到“找不到命令”错误。我内爆并删除了RVM,并从~/.bashrc'中删除了所有与RVM相关的行。使用后我仍然收到此错误:rvmimploderm~/.rvm-rfrm~/.rvmrcgeminstallbundlerecho'exportPATH="$HOME/.rbenv/bin:$PATH"'>>~/.bashrcecho'eval"$(rbenvinit-)"'>>~/.bashrc.~/.bashrcrbenvversions
在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q
需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc