随着信息时代的发展变迁,荧幕里呈现的 智慧城市 慢慢出现了在现实生活中,很大程度上便利了平常的管理和维护。在智慧城市的大背景下,智慧交通监管可视化系统 是其重要的组成部分,经过一条条道路监控的串联,引伸出一座智慧城市的管控,而在众多数据的维护中,实时数据、设备状态 以及视频监控 是极为重要的。其中视频监控一直是做为主体的部分,而在 互联网 和 物联网 齐头并进的形式下,“中国天网” 应运而生,这实际上是一项城市监控系统,但它不是个仅一台摄像头的设备,而是足足有1.7亿个监控摄像头,而在将来三年内,还将再安装4亿个摄像头。交通做为城市发展的动脉,与人们下平常息息相关,而在这一系列的监管做用下,成为了一个“公安治安视频监控系统”,关乎人们平常的安全治安管理。html
城市交通的主要方式体如今城市道路、公交、轨道交通等设施上,但随着城市化进程的加快和经济社会发展的推进下,机动车保有量迅速增长,城市交通问题日益严峻。面对这一现状,为了缓和城市交通的各类问题,采起了多种解决方案,例如建设一系列信号灯控制,路口卡口监控、视频监控等多种方法的系统维护,有着必定程度上的效果,可是各个系统都独立着解决其对应的问题,没法从总体的交通态势上进行综合掌控,而实现城市化智慧交通的管理系统能够很好地应对这一问题。介于 2D 组态和 3D 组态上,Hightopo(如下简称 HT )的 HT for Web 产品上的有着丰富的组态化可供选择,本文将介绍如何运用 HT 丰富的 2/3D 组态 搭建出一个路口监控系统的解决方案。前端
本文将从一下几个方面介绍智慧交通可视化监控系统的实现过程:node
一、车辆生成以及在红绿灯控制下的运行;ios
二、摄像头的仿真和实景监控;ajax
三、路口监控信息的实时数据以及维护;算法
在智慧交通监控系统里,呈现了拟真的红绿灯控制下实时车辆行驶的场景,搭配上可控制的天气环境切换面板,能够模拟在各类天气下的路口运行状态;还实现了路口摄像头的监控状态,点击路口的每一个摄像头能够查看此摄像头监控范围内路口的实时运行,提供仿真和实景两种状态的切换;其次还添加了许多实时数据的监控面板,对接真实接口数据起到实时路口监控的最大效益化。json
HT 经过丰富的 2D 组态和 3D 组态的交融结合使用上,整理出许多工业互联网上的解决方案,在智慧城市推进的背景下,智慧交通管理系统可视化决策系统也是极为重要的部分,对于道路以及路口的监测中,面向交管智慧中心大屏环境,其三维场景上可经过 HT for Web 产品轻量化 HTML5/WebGL 建模的方案,实现快速建模、运行时轻量化到甚至手机终端浏览器便可 3D 可视化运维的良好效果;二维图纸上拥有矢量图标在放大后图像不会失真,支持大屏、多屏、超大分辨率等显示情景。axios
集成地理信息系统、视频监控系统、交管部门各业务系统数据,对交通路况车流量、事故处理报告等要素进行综合监测,并支持点选查看具体警力、机动目标、交通事件、监控视频等详细信息,帮助管理者实时掌握交通总体运行态势。数组
支持对摄像头、流量检测设备、交通讯号灯等交通基础资源的数量、空间位置分布、实时状态等信息进行监测和可视化管理,支持设备详细信息查询,支持对未正常工做的设备进行告警,增强管理者对设备状态的监测与感知,提高交通基础设施的运维管理效率。promise
支持集成前端视频巡检系统,有效结合视频智能分析、智能定位、智能研判技术,对道路拥堵点位、隐患点位、事故点位等状况进行可视化监测,实现异常事件的实时告警、快速显示,并可智能化调取异常点位周边监控视频,有效提高接处警效率。
支持集成路口信号灯、视频监控等系统数据,对路口交通流量、流速、车辆及道路异常事件、信号灯状态等信息进行实时监测,并可结合专业的模型算法,比对历史最佳通行速度及最佳通行量,对路口交通态势进行可视化分析研判,为信号配时调优和路口交通组织优化提供科学的决策依据,有效提高交通运行效率。
充分整合交管部门现有数据资源,提供多种可视化分析、交互手段,对海量历史违法违章案件数据进行可视化串并分析,深度挖掘案件时空分布规律,为交管部门进行缘由分析、主动防范等业务应用提供支持。
在路口的仿真的运行系统下,场景中有这许许多多来往运行的车辆,是经过动态加载车辆模型而且设置管道运行动画,而这些车辆固然须要符合信号灯的运行规则,须要运用一些控制手段,让这些车辆遵纪守法。
如下是经过设置一些车辆的基础属性以及根据 type 类型判断加载对应的车辆模型的伪代码:
loadCar(type) { // 建立车辆新节点 let car = new ht.Node(); // 根据车辆类型建立加载对应车辆模型 switch (type) { case 'familyCar': car.s('shape3d', 'models/HT模型库/交通/车辆/家用车.json'); break; case 'truck': car.s('shape3d', 'models/HT模型库/交通/车辆/卡车.json'); break; case 'jeep': car.s('shape3d', 'models/HT模型库/交通/车辆/吉普车.json'); break; ... default: console.log('NO THIS TYPE CAR!'); break; } // 设置车辆不可选择和不可移动 car.s({ '3d.selectable': false, '3d.movable': false }); // 设置锚点 --- 车的头部 car.setAnchor3d(1, 0, 0.5); // 设置初始位置 car.setPosition3d(0, 100000, 0); let typeIndex = 1; // 判断是否此前生成了这种类型的车辆 this.g3dDm.each(data => { if (data.getTag() === type + typeIndex) { typeIndex++; } }) // 设置车辆节点标签 car.setTag(type + typeIndex); // 设置车辆节点的名字 car.setDisplayName(type); // 将车辆节点添加到数据模型中 this.g3dDm.add(car); }
经过管道动画的驱使,生成的车辆在信号灯的控制下行驶着,首先要经过 ht.Polyline 绘制出一条车辆的运行管道,其实现上有二维形式与三维的形式,是继承于 ht.Shape,当 shape3d 设置为 cylinder 时则显示为立体的三维管线效果。而当车辆加载以及管道绘制的完成,咱们就能够经过 HT 封装的动画函数 ht.Default.startAnim() 来趋势车辆沿着管道运行,实现管道动画的效果。
而关于管道动画的实现上,基于 ht.Default.startAnim() 封装了一个 move 的动画函数是节点沿着路径平滑移动的封装函数,主要参数为:
经过绘制一条运行路线的管道,ht.Default.getLineCacheInfo() 获得这条管道的点位和分割信息 cache,而后管道信息经过 ht.Default.getLineLength() 获得管道的长度,而且经过 ht.Default.getLineOffset() 来获取连线或者管道指定比例的偏移信息,从而达到移动的效果,是为了经过 node.lookAtX() 来获取节点下一个面对的朝向的位置信息,并设置节点此时的位置,从而达到节点沿着路径平滑移动的效果。
move(node, path, duration = 20000, animParams) { // path._cache_ 里面存着管道的节点信息 let cache = path._cache_; // 若是没有缓存信息,则获取 path._cache_ 里面存着管道的节点信息 if (!cache) { cache = path._cache_ = ht.Default.getLineCacheInfo(path.getPoints(), path.getSegments()); } // 获取管道缓存信息的长度 const len = ht.Default.getLineLength(cache); // 设置动画对象初始化 animParams = animParams || {}; // 设置 action 为 animParams 的动画执行函数 const action = animParams.action; // 动画执行部分 animParams.action = (v, t) => { // 获取管道运动的偏移信息 const offset = ht.Default.getLineOffset(cache, len * v); // 获取偏移位置上的点 const point = offset.point; // 设置节点看向的下一个位置 node.lookAtX([point.x, point.y, point.z], "forward "); // 设置节点的位置 node.p3(point.x, point.y, point.z); // 判断动画是否执行完 if (action) action(); }; // 循环调用动画执行函数 return loop(animParams.action, duration); } // 循环动画函数 loop(action, duration) { return ht.Default.startAnim({ duration: duration, action: action }); }
视频监控做为本系统重要的解决方案之一,提供了仿真和实景的两套风格实现,仿真的意义是经过简单的车辆模型模拟出交通流向而后经过绘制场景并共用一个数据模型来体现,实质意义上能够经过科幻风格突出监控的重点信息,例如设备维护以及一些违法的场景重现;而对于实景风格是经过对接实时的视频数据流,而后展现出路口的运行状态,以真实的原貌重现路口的每个动态信息。
2.1 拟真摄像头的实现原理
做为拟真方案的摄像头实现上,经过 HT 的渲染元素 renderHTML 加载出一个弹窗的三维小场景,而且与路口主场景共享一个数据模型 dataModel,实现数据变化以及动画的互通,而如今只须要去获取所点击摄像头的真实视角信息,经过全局事件派发将获取的真实视角,传到摄像头弹窗场景去改变对应视角的 眼睛 eye 和 中心点 center,就能达到获取摄像头在主场景中拟真的视角。为了使摄像头活动的时候具备动画的辨识度,在每一个摄像头前绘制了一个锥形的监控区域吸附在摄像头上,界定出摄像头的监控范围,达到智慧监控的效果。
在交互实现上,经过点击选中摄像头后,使这个摄像头的锥形区域变为直线,表示为选中状态同时标记选中的摄像头的选中先后顺序,而且经过派发事件驱使 2D 图纸上显示摄像头弹窗,在弹窗显示的同时,经过计算获得实时变更的中心点位置信息(center),只要实时经过全局派发事件把位置信息传输到摄像头弹窗场景,就能起到摄像头场景视角与主场景中所点击摄像头的视角同步;取消弹窗显示的交互方式是经过双击场景背景,恢复摄像头锥形区域而且派发事件去隐藏 2D图纸上的摄像头弹窗:
// 全局事件派发器 var G = {} window.G = G; G.event = new ht.Notifier(); handleInteractive(e) { const {kind, data} = e; if(kind === 'clickData') { // 判断点击节点是否带有标签,没有标签则 return let tag = data.getTag(); if(!tag) return; // 判断标签名为摄像头 if(tag.indexOf('camera') >= 0) { // 设置指定上一个点击的摄像头和当前点击的摄像头 this.lastClickCamera = this.nowClickCamera; this.nowClickCamera = data; // 若是以前有点击摄像头,则初始化摄像头锥体的大小 if (this.lastClickCamera !== null) { let clickRangeNode = this.lastClickCamera.getChildren()._as[0]; clickRangeNode.s3(300, 150, 500); } // 若是有点击摄像头,则设定所点击摄像头锥体的大小 if (this.nowClickCamera !== null) { let clickRangeNode = this.nowClickCamera.getChildren()._as[0]; clickRangeNode.s3(5, 5, 500); } // 获取点击摄像头的位置信息 var cameraP3 = nowClickCamera.p3(); // 获取点击摄像头的旋转信息 var cameraR3 = nowClickCamera.r3(); // 获取点击摄像头的大小信息 var cameraS3 = nowClickCamera.s3(); // 当前锥体起始位置 var realP3 = [cameraP3[0], cameraP3[1] + cameraS3[1] / 2, cameraP3[2] + cameraS3[2] / 2]; // 将当前眼睛位置绕着摄像头起始位置旋转获得正确眼睛位置 var realEye = getCenter(cameraP3, realP3, cameraR3); // 全局事件派发至摄像头场景改变视角的眼睛 eye 和中心点 center G.event.fire({ type: 'videoCreated', eye: realEye, center: getCenter(realEye, [realEye[0], realEye[1] ,realEye[2] + 5], cameraR3) }); // 视频弹窗显示派发 event.fire(SHOW_VIDEO, {g3dDm: this.g3dDm, cameraName:tag}); } } // 双击背景隐藏摄像头场景窗口,并初始化摄像头锥体的大小 if(kind === 'doubleClickBackground') { // 视频弹窗隐藏派发 event.fire(HIDE_VIDEO); // 若是以前有点击摄像头,则初始化摄像头锥体的大小 if (this.nowClickCamera !== null) { let clickRangeNode = this.nowClickCamera.getChildren()._as[0]; clickRangeNode.s3(300, 150, 500) } // 设置当前点击摄像头为空 this.nowClickCamera = null; } }
以上所涉及到方法 getCenter(),其实是经过去获取每一个摄像头节点在场景中对应的旋转角度,简化理解就是一个点 A 围绕着另一个点 B 旋转,即中心点位置(center)围绕着眼睛位置(eye)旋转,而咱们则须要去计算点 A 的位置(中心点位置 center),这里经过封装一个 getCenter 方法用于获取 3d 场景中点 A 绕着点 B 旋转 angle 角度以后获得的点 A 在 3d 场景中的位置,方法中采用了 HT 封装的 ht.Math 下面的方法,如下为实现的代码:
实现代码以下:
// pointA 为 pointB 围绕的旋转点 // pointB 为须要旋转的点 // r3 为旋转的角度数组 [xAngle, yAngle, zAngle] 为绕着 x, y, z 轴分别旋转的角度 const getCenter = function(pointA, pointB, r3) { const mtrx = new ht.Math.Matrix4(); const euler = new ht.Math.Euler(); const v1 = new ht.Math.Vector3(); const v2 = new ht.Math.Vector3(); mtrx.makeRotationFromEuler(euler.set(r3[0], r3[1], r3[2])); v1.fromArray(pointB).sub(v2.fromArray(pointA)); v2.copy(v1).applyMatrix4(mtrx); v2.sub(v1); return [pointB[0] + v2.x, pointB[1] + v2.y, pointB[2] + v2.z]; };
2.2 实景摄像头的实现原理
对于实景的实现上,咱们能够经过对接实时的视频数据流,如今主要经常使用的流媒体传输协议有:RTMP、RTSP、HLS 和 HTTP-FLV。
例如经过一个简单的 RTMP 视频流的对接就能够明白其实现的原理。对于的视频的载入,须要用到 video.js 的插件进行展现,因此先引入插件,而后对接视频流后,也是一样经过全局事件派发到 HT 的渲染元素 renderHTML 将视频流渲染到场景图纸中,如下是实现的伪代码:
// 引入 video.js 插件 <script src="./js/video.js"></script> // 经过全局事件派发到渲染元素 renderHTML 去渲染视频到场景图纸中 G.event.add(function(e){ if(e.type==='videoCreated'){ var div=e.div; div.innerHTML='<video id="video" class="video-js vjs-default-skin"><source src="rtmp://10.10.70.57/live/test" type="rtmp/flv"></video>'; window.player = videojs('video'); } });
对于一些路口的关键数据能够经过接口对接的形式展现出来,经过实时数据变更的监控,即时反馈道路路口的信息数据,包含一些事故统计、车流量分析、设备维护状态以及车辆违章。这些数据依赖展现的载体是经过 HT 的 2D 组态矢量图来实现的,矢量图适用于不少场合,其特色是放大后图像不会失真,能够适应不一样分辨率的屏幕都不会模糊,使得整个系统适用与不一样的屏幕下,包括在大屏的监控系统上也驾轻就熟。而经过矢量图的信息展现上,对比以往一些单纯数据展现的页面,本系统则是经过一些自定义的动画交互,可使得整个页面的上效果呈现上有一种沉浸式的体验,总体的客户体验能够大大地提高。
数据的展现形式有着多种多样的方式,能够经过一些图表插件,例如 eEcharts,HT 也有机制可让咱们使用它们,固然咱们也能够自定义封装一些组件,示例中的表格和圆环进度条就是一种很好地呈现方式,而在许多效果呈现上,HT也是拥有本身一套功能丰富的 UI 组态,若是感兴趣的话能够经过 HT主页 上来了解使用。
对于数据接口的获取,能够运用一些主流的方法:
ajax 和 axios 要实时获取接口数据得经过轮询调用接口的形式进行传输,而 WebSocket 能够双向进行数据传输,在选择运用上能够匹配本身的实现需求。本系统是采用经过 axios 调用接口获取实时数据。
示例中的柱状图和折线图,是经过 HT 里的机制下去使用 eEcharts 上一些图表进行自定义配置而实现的,继而经过对 axios 接口轮询调用载入数据,展示了实时的路口监控数据信息:
loadData() { // 获取图纸的数据模型 let dm = this.g2d.dm(); // 获取车流量接口的数据 axios.get('/traffic').then(res => { // 接入日车流量折线图的数据 this.lineChart1.a({ 'seriesData1': res.lineChartData1, 'axisData' : res.axisData }); // 接入车辆运行高峰折线图的数据 this.lineChart2.a({ 'seriesData1': res.lineChartData2, 'axisData' : res.axisData }) // 采用数字跳动的方式载入一些数据内容 setBindingDatasWithAnim(dm, res, 800, v => Math.round(v)); // 接入运行峰值的时刻 this.peakTime.s('text', res.peakTime); }); // 载入设备运行状态的数据 axios.get('/equipmentStatus').then(res => { setBindingDatasWithAnim(dm, res, 800, v => Math.round(v)); }); // 载入事故统计的数据 axios.get('/accident').then(res => { setBindingDatasWithAnim(dm, res, 800, v => Math.round(v)); // 接入每个月事故柱状图的数据 this.accidentBar.a({ axisData: res.axisData, seriesData1: res.seriesData1 }) }); }
关于表格的绘制,其实是封装了一个组件来实现的,而其中的交互动画,主要仍是运用了 HT 自带的动画函数 ht.Default.startAnim(),横向经过滚动 100 宽度并数据透明度慢慢浮现,纵向采用向下偏移一行表格行高 54 来添加新的警报信息。
addTableRow() { // 获取表格节点 let table = this.table; // 经过 axios 的 promise 请求接口数据 axios.get('getEvent').then(res => { // 获取表格节点滚动信息的数据绑定 let tableData = table.a('dataSource'); // 经过向 unshift() 方法可向滚动信息数组的开头添加一个或更多元素 tableData.unshift(res); // 初始化表格的纵向偏移 table.a('ty', -54); // 开启表格滚动动画 ht.Default.startAnim({ duration: 600, // 动画执行函数 action action: (v, t) => { table.a({ // 经过添加数据后,横向滚动 100 'firstRowTx': 100 * (1 - v), // 第一行行高出现的透明度渐变效果 'firstRowOpacity': v, // 纵向偏移 54 的高度 'ty': (v - 1) * 54 }); } }); }); }
城市大脑被炒的火热,红绿灯调控解决拥堵问题只是智慧交通的冰山一角,常态下的监测监管、分析研判,才是交通管理者真正得以指挥若定的有利保障,而这些,离不开让交通数据可见可感的“智慧交通可视化决策平台”。
智慧交通可视化系统经过实时数据的载入,能够有效即时地反映出路口所处的状态,使得以往散乱的各个系统串联起来造成一个完整的智慧交通系统,而在这个系统下串联出许多条道路的监控,这实际上是一个智慧城市的缩影,而在以往的经验积累上,HT 也完成了一套完整的智慧城市系统的解决方案,串联了许多城市数据以及设施建设的记录,能够起到合并许多个功能子系统进行实时的数据监控和展现:HT 智慧城市
2019 咱们也更新了数百个工业互联网 2D/3D 可视化案例集,在这里你能发现许多新奇的实例,也能发掘出不同的工业互联网:https://mp.weixin.qq.com/s/ZbhB6LO2kBRPrRIfHlKGQA
同时,你也能够查看更多案例及效果:https://www.hightopo.com/demos/index.html