OpenCV --- 基于 OpenCV 的百度路况研究记录 (四)
背景
本篇主要内容:
- 搭建离线地址解析服务
主要内容
继上篇研究内容之后,重新思考了之前抛出的问题: 如何获取某个省或市的道路信息?
之前对于该问题的解法有 2 种:
使用总队或者支队提供的道路信息,然后根据分析出来的经纬度和提供的道路信息进行匹配
调用互联网接口,进行经纬度转道路地址
分析这 2 中方式之后,其弊端很明显:
第一种方式:
无法确定总队或者支队是否能够提供道路信息;
提供的数据又是否足够详细全面,要知道在百度地图 17 等级下,解析出来的道路是很详细的
姑且算是提供了,格式又是否能够统一? 能否做到一套代码解决普遍问题?
第二种方式:
需要个人申请 key ,才能调用 API
解析 API 每日有次数限制, 5000次/天,对于该城市版分析服务来说,远远不够
经过一番分析和折腾后,于内网搭建了离线版的地址解析服务,提供 API,将经纬度转化为道路信息, API 返回数据如下:

支持返回的数据很详细: 省,市,行政区划,邮编,道路名,附近的建筑物,公交站牌,商场等
该服务 数据范围覆盖全国, 支持多线程调用, 单次 API 调用耗时为 10 ms - 30 ms 左右, 对机器的磁盘要求高
最后,我录了个短视频看下实际的使用效果:
OpenCV --- 基于 OpenCV 的百度路况研究记录 (三)
背景
本篇研究的内容有:
分析得到的大量拥堵点抽稀处理
拥堵区域骨架提取
部分优化算法和性能
抽稀处理
根据之前的处理得到一张瓦片的一块拥堵区域时,需要对其进行结构化数据的分析:将坐标转化为百度坐标系的坐标,坐标转经纬度,拥堵距离计算,
但是一块区域有很多的拥堵点,如果要对每个点进行操作计算的话,会导致性能问题,而且对于密集的点来说
意义不大,没有必要这么做,如果说能够给这些点进行稀释处理,仅仅分析稀释后点,那么既能保证数据的正确性,又能提升算法的性能
算法的基本思想: 连接起点 A 和终点 B, 找出某一点到线段 AB 距离 S 最大的点 P, 如果 S 小于手动设置的阈值 H, 则舍弃其他点,直接连接 A B, 抽稀完成
如 S > H , 则以 P 为终点, 分别计算 2 端 AP 和 PB 上点到相应线段的最大距离,再重复上述步骤, 直到所有的距离均小于 S , 抽稀完成
抽稀结果示例:
上图中,已经将上面的拥堵部分大量点稀释的只剩下 3 个点了,这三个点还是位于原来的轨迹上, 可能看的不太清楚,放大了看

示例 2 :
对于抽稀最大直观效果,我通过下面 2 张动图来演示:
抽稀前:
抽稀后:
骨架提取
骨架提取是指从原来的图中层层剥离点,最后仍然要保持原来的形状
算法基本思想:
效果示例:
我以这张拥堵瓦片图来看, 我提取出左上角的拥堵部分来处理

轮廓提取:

填充内部:
上述 2 中图进行加运算, 得到整个拥堵部分,再进行骨架提取:

已经得到最小化的骨架了,基本上都是 1 像素值,这对后续的处理很有利,再放大点看:
最后,我录了个视频,以展示目前的演示效果:
OpenCV --- 基于 OpenCV 的百度路况研究记录 (二)
背景
本篇就之前对于拥堵路段为曲线状且涉及多个路段时分析的结果差强人意的情况进行了算法重构
简介
之前算法核心是 找出分段拥堵,并提取信息
之前算法的缺陷是使用霍夫变换提取瓦片中的直线时, 无法很好的控制参数, 导致在临近的曲线情况下分析结果不正确
简单示意图:
在二维的坐标系中, 控制直线的是参数 m(斜率) 和 b(截距)
转化为极坐标系再化简后,控制直线的参数是 θ (极角) 和 r(极径)
原来的思路是曲线是有很多小部分的直线段构成的,如若能够将曲线分成适合的若干线段,那么同样可以将整个曲线提取出来,继而提取其他信息
这种思路得考虑三种主要的参数:
threshold:识别某部分为一条直线时必须达到的值
min_theta:检测到的直线的最小角度
max_theta:检测到的直线的最大角度
然而经过多次测试,按照这个想法进行处理,结果并不好, 出现更多的结果是
曲线 a 会被他的相邻曲线 b 干扰,继续分析的结果是会从 a 与 b 的相邻端直接跳到 b 曲线上,接着分析的线路走向就会直接沿着 b 走下去, 就是上次截图所示的结果
曲线 a 会有多处幅度较大的弯曲时,会沿着角度大的地方直接放射出去, 例如下面所测试的
做法
下面测试的参数
threshold: 65
min_theta: 0
max_theta: 5
对于形态各异的瓦片图来说,很难调整出一个适当的参数.
于是我开始重整思路, 但是思路的核心还是不变: 找出分段拥堵
目前的思路是:
读入瓦片原图(RGBA)
进行色彩空间转换: 将带透明通道的 RGBA 转换为 BGR, 再将 BRG 转化为 HSV 色彩空间,方便颜色的提取
在 HSV 的色彩空间上提取出黄色(缓行)和红色(拥堵), 并各自区分保存
得到的图像信息二值化, 方便下一步处理
在二值化的图像上提取黄色和红色的边缘信息, 分析边缘信息得到分段拥堵的外包矩形
已有的黄,红拥堵段做外包矩形的位置定位,得出分段拥堵信息
大量坐标点抽稀处理
开发一系列流程截图如下:
图示的顺序依次对应思路的步骤, 在最后一张图中,已经将分析出来的分段拥堵信息再绘制到原图上, 准确度很高
对于之前算法没有解决的瓦片,这个算法暂时算是解决了,那么面对更加复杂的拥堵情况呢?
为此我特地抽取了北京天安门附近的拥堵瓦片图
这张图里反应的拥堵情况应该很具有代表性了,下面再用此算法对这张图进行分析:
值得一提的是, 前一张图片处理耗时时间是: 0.08534727 s; 而后一张图片处理的时间是: 0.084427357 s, 时间基本无差.
OpenCV --- 基于 OpenCV 的百度路况研究记录 (一)
背景
城市版交通路况的分析基于高速公路路况的基础上以合肥为试点城市进行的研究课题.
记录
目前该研究课题已完成:
- 筛选出合肥市在百度地图 17 等级下的路况瓦片 62354 张
- 对合肥二环路内圈的路况进行分析,目前分析出的路况开发截图

分析结果: 用蓝色的线表示,画线时未区分颜色,实际分析已区分
目前已分析提取出的数据有:
拥堵段 2 端点的经纬度(百度,WGS84坐标系)
拥堵段距离,精确到到 0.1 m
拥堵段的拥堵状态 (缓行,拥堵,严重拥堵)
拥堵段的 WKT 空间信息, 单段 拥堵为 lineString格式, 近距离多段拥堵为 multiLineString 格式, 此信息可直接绘制在地图上
提取出瓦片的拥堵信息,再根据我们自己项目中使用的地图的比例尺渲染成适合我们地图的路况图层
目前该研究课题存在的问题:
- 有些复杂路口分析不正确,例如:

进行分析后,会变成下面这样:
还有这样的:
结果 :
目前的分析算法对于单张瓦片多处拥堵,且拥堵路段呈直线状分析结果准确,对于拥堵路段为曲线状且涉及多个路段时分析的结果不如人意,这是目前分析算法的原因,尚待改进.
性能问题,我目前测试了合肥二环路内圈的路况耗时日志结果如下:
该测试结果是我在笔记本上运行的结果,其中参数配置是:
CPU : 2.8 GHz Intel Core i7-4 * 2核心, RAM: 16 GB 2133 MHz LPDDR3 , Graphics Card: Radeon Pro 555 2 GB
程序运行核心线程数 2 , 最大线程数 5, 运行过程中 CPU 使用率 50% ~ 60%
测试时间 4 月 16 日下午 16 点左右
测试结果: 单机运行, 12685 张图片耗时 714 s, 平均处理速度 18 张/秒 左右
相对于安徽高速,城市版的瓦片分析已经从 Java 的图片处理切换到 OpenCV,有个因素是 OpenCV 绝大数 API 是支持图形卡加速的,我本机的开发环境是开启了图形卡加速,但是一般的服务器是没有图形卡的.
未知因素: 获取合肥市内路网信息,获取后可进一步分析出以下信息:
获取详细的拥堵文字描述信息
按照某一条路进行分组,方便对一条路上多段拥堵进行合并
分析出拥堵路段涉及的行政区划
分析出该次拥堵的状态(首次拥堵,持续拥堵,结束拥堵),及拥堵持续时间
重剑无锋,大巧不工 SpringBoot --- 序列化返回对象时忽略空或者 null 属性
重剑无锋,大巧不工 SpringBoot --- 使用 Ajax FromData 上传文件并传参
页面
1 | const formData = new FormData(); |
spring boot 处理
1 | @PostMapping("/file") |
注意
- antd 上传组件里,真正的文件是 file.originFileObj
- params 是复杂的对象的话, spring boot 接受的 Params 对象需要使用 String 字符串进行序列化成对象; 或者将 Params 对象的属性分开来写, 如果某个属性又是复杂对象的话通用需要序列化
Ubuntu 优雅的远程桌面服务端配置
背景
上一篇文章记录了因为远程桌面连接把 Ubuntu 的 /home 弄坏了
好一番折腾。。。。
其实这个远程桌面我早就想重新配置了,今天我终于受不了它了,于是我觉得仔细研究一番找到适合我自己的方式来操作
以前的方式
之前我的远程配置是 xrdp + tightvncserver
然后我每次都是使用 Windows 上的 mstsc 来连接的
连接上后会出现 xrpd 的登录选项
每次我都选第一个 sesman-Xvnc 然后输入用户名密码即可
可这样的连接方式有个很不好的方面,就是这种方式是多用户的,想回家继续没干完的事情
连接上发现是一个新的桌面
都不知道做到什么地方了
这也就算了
最大的问题远程操作操作这就没响应了,鼠标的指针变成了 × 号,所有的东西都不能点,而且第二天到公司桌面卡死不动,只能重启桌面或重启系统,很多打开软件和工具都会还原
这是我最不能忍的地方
决定改变
我决定不使用这种方式来进行远程,远程 teamviewer 是比较合适的选择,但是工作由于连接的终端太多,被检测商用,每次连接都是只有 1 min 的操作时间
很尴尬…
最后决定使用轻量级的 vnc 服务来解决这个问题,并且搭配 xrdp 的 any vnc 来使用 mstsc 远程连接
重新配置
x11vnc
- 卸载以前的 vnc 服务端
1 | sudo apt remove tigervncserver |
- 安装
x11vnc,并进行配置
1 | sudo apt install x11vnc -y |
- 解决复制粘贴的问题
sudo apt install autocutsel安装 autocutselautocutsel -f后台运行
问题及解决
下载 vnc-view 新建一个连接发现连不上…
尴尬。。。
检查 5900 端口,是开放的
1 | joylau@joylau-work-192:~$ sudo netstat -tnlp | grep :5900 |
但是使用的进程是 vino-server ,这是 Ubuntu 自带程序开启的服务
原来端口被占用了
关闭服务 : 找到桌面共享,关闭 允许其他人查看您的桌面
重启 x11vnc 服务
连接成功
最后
现在有 4 中方式使用
- 使用
vnc-view使用是单用户的,类似teamviewer那样,2 边操作都能互相看见 - 使用
mstsc, 连接到xrdp后,再选中any vnc使用vnc协议连接,效果和第一种是一样的,只不过不需要客户端了 - 浏览器直接远程,这种最方便,下面有说明
- 以前的那种使用方式, 多用户的,估计我是不会再用了
补充
第三种多用户方式连接,没连接一次就生成一个新的桌面,这个很烦,想连接回上次的桌面,可修改配置 /etc/xrdp/xrdp.ini
1 | [globals] |
修改 port 为 固定端口号或者 ask-1
下次连接不修改即可
注:再记录下 sesman.ini 的配置
1 | [Globals] |
使用浏览器来远程桌面
像阿里云等云服务提供商一样直接在浏览器上进行远程操作
1 | docker run -e REMOTE_HOST=192.168.10.192 -e REMOTE_PORT=5900 -p 8081:8081 -d --restart always --name novnc dougw/novnc |
打开浏览器 http://host:8081/vnc.html
秀啊!!!
