JoyLau's Blog

JoyLau 的技术学习与思考

背景

我新办了个电信宽带,并且搞到了公网 IP, 但是原来的长城宽带没到期我还想继续用,而且办的电信宽带有 iTV, 我还想看电视
但是现在从墙里的多媒体集线箱到我卧室的线有 2 根,一根电话线,一根超 5 类网线
看我如何改造操作

现状

  1. 一根电话线(4 根铜线)
  2. 一根超 5 类网线

需求

  1. 同时使用 电信宽带和原来的长城宽带
  2. 能看 iTV 电视, iTV 的线不与电信宽带共享速率, 也就是电信宽带和 iTV 都直接接到电信的光猫上

分析

  • 百兆网类,网络数据的传输使用的 B 类网线接法的 1,2,3,6 根线
  • 4,5,7,8 其实并没有参与数据传输,只是保持数据的稳定性以及抗干扰
序号 1 2 3 4 5 6 7 8
颜色 白橙 白绿 白蓝 绿 白棕

进行拆分

序号 1 2 3 6
颜色 白橙 白绿 绿
序号 4 5 7 8
颜色 白蓝 白棕

做法

  • 8 根铜线的超五类网线分拆为 2 个 4 根线的网线
  • 这 2 根线分别直接连接电信光猫,一根连接光猫的 LAN1 口, 一根连接 LAN2 口
  • 电话线也按 1,2,3,6 的接法连接长城宽带

材料

  • 水晶头
  • 网线钳
  • 网线直通连接器
  • 软路由

CV type 的转换

CV_8UC3 转 CV_8UC1 : convertTo 或者 cvtColor
CV_8UC1 转 CV_8UC3 : cvtColor (灰度相同,通道已经转化, CV_GRAY2RGB)

Mat 初始化

Mat.zeros: 创建全 0 矩阵
Mat.ones: 创建全 1 矩阵
Mat.eye: 创建单位矩阵

零碎

  1. 判断点与多边形的关系: pointPolygonTest
  2. ROI 区域: Rect(col,row,width,height)
    1. col: x 坐标 (坐标以 0 开始, 左上角 0,0)
    2. row: y 坐标
    3. width: 宽度
    4. height: 高度

背景

本篇主要内容:

  1. 搭建离线地址解析服务

主要内容

继上篇研究内容之后,重新思考了之前抛出的问题: 如何获取某个省或市的道路信息?

之前对于该问题的解法有 2 种:

  1. 使用总队或者支队提供的道路信息,然后根据分析出来的经纬度和提供的道路信息进行匹配

  2. 调用互联网接口,进行经纬度转道路地址

分析这 2 中方式之后,其弊端很明显:

第一种方式:

  1. 无法确定总队或者支队是否能够提供道路信息;

  2. 提供的数据又是否足够详细全面,要知道在百度地图 17 等级下,解析出来的道路是很详细的

  3. 姑且算是提供了,格式又是否能够统一? 能否做到一套代码解决普遍问题?

第二种方式:

  1. 需要个人申请 key ,才能调用 API

  2. 解析 API 每日有次数限制, 5000次/天,对于该城市版分析服务来说,远远不够

经过一番分析和折腾后,于内网搭建了离线版的地址解析服务,提供 API,将经纬度转化为道路信息, API 返回数据如下:

支持返回的数据很详细: 省,市,行政区划,邮编,道路名,附近的建筑物,公交站牌,商场等

该服务 数据范围覆盖全国, 支持多线程调用, 单次 API 调用耗时为 10 ms - 30 ms 左右, 对机器的磁盘要求高

最后,我录了个短视频看下实际的使用效果:

背景

本篇研究的内容有:

  1. 分析得到的大量拥堵点抽稀处理

  2. 拥堵区域骨架提取

  3. 部分优化算法和性能

抽稀处理

根据之前的处理得到一张瓦片的一块拥堵区域时,需要对其进行结构化数据的分析:将坐标转化为百度坐标系的坐标,坐标转经纬度,拥堵距离计算,

但是一块区域有很多的拥堵点,如果要对每个点进行操作计算的话,会导致性能问题,而且对于密集的点来说

意义不大,没有必要这么做,如果说能够给这些点进行稀释处理,仅仅分析稀释后点,那么既能保证数据的正确性,又能提升算法的性能

算法的基本思想: 连接起点 A 和终点 B, 找出某一点到线段 AB 距离 S 最大的点 P, 如果 S 小于手动设置的阈值 H, 则舍弃其他点,直接连接 A B, 抽稀完成

如 S > H , 则以 P 为终点, 分别计算 2 端 AP 和 PB 上点到相应线段的最大距离,再重复上述步骤, 直到所有的距离均小于 S , 抽稀完成

抽稀结果示例:

上图中,已经将上面的拥堵部分大量点稀释的只剩下 3 个点了,这三个点还是位于原来的轨迹上, 可能看的不太清楚,放大了看


示例 2 :

对于抽稀最大直观效果,我通过下面 2 张动图来演示:

抽稀前:

抽稀后:

骨架提取

骨架提取是指从原来的图中层层剥离点,最后仍然要保持原来的形状

算法基本思想:

效果示例:

我以这张拥堵瓦片图来看, 我提取出左上角的拥堵部分来处理

轮廓提取:

填充内部:

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

已经得到最小化的骨架了,基本上都是 1 像素值,这对后续的处理很有利,再放大点看:

最后,我录了个视频,以展示目前的演示效果:

背景

本篇就之前对于拥堵路段为曲线状且涉及多个路段时分析的结果差强人意的情况进行了算法重构

简介

之前算法核心是 找出分段拥堵,并提取信息
之前算法的缺陷是使用霍夫变换提取瓦片中的直线时, 无法很好的控制参数, 导致在临近的曲线情况下分析结果不正确
简单示意图:

在二维的坐标系中, 控制直线的是参数 m(斜率) 和 b(截距)

转化为极坐标系再化简后,控制直线的参数是 θ (极角) 和 r(极径)

原来的思路是曲线是有很多小部分的直线段构成的,如若能够将曲线分成适合的若干线段,那么同样可以将整个曲线提取出来,继而提取其他信息

这种思路得考虑三种主要的参数:

  1. threshold:识别某部分为一条直线时必须达到的值

  2. min_theta:检测到的直线的最小角度

  3. max_theta:检测到的直线的最大角度

然而经过多次测试,按照这个想法进行处理,结果并不好, 出现更多的结果是

  1. 曲线 a 会被他的相邻曲线 b 干扰,继续分析的结果是会从 a 与 b 的相邻端直接跳到 b 曲线上,接着分析的线路走向就会直接沿着 b 走下去, 就是上次截图所示的结果

  2. 曲线 a 会有多处幅度较大的弯曲时,会沿着角度大的地方直接放射出去, 例如下面所测试的

做法

下面测试的参数

threshold: 65

min_theta: 0

max_theta: 5

对于形态各异的瓦片图来说,很难调整出一个适当的参数.

于是我开始重整思路, 但是思路的核心还是不变: 找出分段拥堵

目前的思路是:

  1. 读入瓦片原图(RGBA)

  2. 进行色彩空间转换: 将带透明通道的 RGBA 转换为 BGR, 再将 BRG 转化为 HSV 色彩空间,方便颜色的提取

  3. 在 HSV 的色彩空间上提取出黄色(缓行)和红色(拥堵), 并各自区分保存

  4. 得到的图像信息二值化, 方便下一步处理

  5. 在二值化的图像上提取黄色和红色的边缘信息, 分析边缘信息得到分段拥堵的外包矩形

  6. 已有的黄,红拥堵段做外包矩形的位置定位,得出分段拥堵信息

  7. 大量坐标点抽稀处理

开发一系列流程截图如下:

图示的顺序依次对应思路的步骤, 在最后一张图中,已经将分析出来的分段拥堵信息再绘制到原图上, 准确度很高

对于之前算法没有解决的瓦片,这个算法暂时算是解决了,那么面对更加复杂的拥堵情况呢?

为此我特地抽取了北京天安门附近的拥堵瓦片图

这张图里反应的拥堵情况应该很具有代表性了,下面再用此算法对这张图进行分析:

值得一提的是, 前一张图片处理耗时时间是: 0.08534727 s; 而后一张图片处理的时间是: 0.084427357 s, 时间基本无差.

背景

城市版交通路况的分析基于高速公路路况的基础上以合肥为试点城市进行的研究课题.

记录

目前该研究课题已完成:

  1. 筛选出合肥市在百度地图 17 等级下的路况瓦片 62354 张
  2. 对合肥二环路内圈的路况进行分析,目前分析出的路况开发截图

分析结果: 用蓝色的线表示,画线时未区分颜色,实际分析已区分

目前已分析提取出的数据有:

  1. 拥堵段 2 端点的经纬度(百度,WGS84坐标系)

  2. 拥堵段距离,精确到到 0.1 m

  3. 拥堵段的拥堵状态 (缓行,拥堵,严重拥堵)

  4. 拥堵段的 WKT 空间信息, 单段 拥堵为 lineString格式, 近距离多段拥堵为 multiLineString 格式, 此信息可直接绘制在地图上

  5. 提取出瓦片的拥堵信息,再根据我们自己项目中使用的地图的比例尺渲染成适合我们地图的路况图层

目前该研究课题存在的问题:

  1. 有些复杂路口分析不正确,例如:

进行分析后,会变成下面这样:

还有这样的:

结果 :

目前的分析算法对于单张瓦片多处拥堵,且拥堵路段呈直线状分析结果准确,对于拥堵路段为曲线状且涉及多个路段时分析的结果不如人意,这是目前分析算法的原因,尚待改进.

性能问题,我目前测试了合肥二环路内圈的路况耗时日志结果如下:

该测试结果是我在笔记本上运行的结果,其中参数配置是:

  1. CPU : 2.8 GHz Intel Core i7-4 * 2核心, RAM: 16 GB 2133 MHz LPDDR3 , Graphics Card: Radeon Pro 555 2 GB

  2. 程序运行核心线程数 2 , 最大线程数 5, 运行过程中 CPU 使用率 50% ~ 60%

  3. 测试时间 4 月 16 日下午 16 点左右

测试结果: 单机运行, 12685 张图片耗时 714 s, 平均处理速度 18 张/秒 左右

相对于安徽高速,城市版的瓦片分析已经从 Java 的图片处理切换到 OpenCV,有个因素是 OpenCV 绝大数 API 是支持图形卡加速的,我本机的开发环境是开启了图形卡加速,但是一般的服务器是没有图形卡的.

未知因素: 获取合肥市内路网信息,获取后可进一步分析出以下信息:

  1. 获取详细的拥堵文字描述信息

  2. 按照某一条路进行分组,方便对一条路上多段拥堵进行合并

  3. 分析出拥堵路段涉及的行政区划

  4. 分析出该次拥堵的状态(首次拥堵,持续拥堵,结束拥堵),及拥堵持续时间

注解

在类上加入注解
@JsonInclude(JsonInclude.Include.NON_EMPTY)

解释

Include.Include.ALWAYS: 默认
Include.NON_DEFAULT: 属性为默认值不序列化
Include.NON_EMPTY: 属性为 空(””) 或者为 NULL 都不序列化
Include.NON_NULL: 属性为NULL 不序列化

页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const formData = new FormData();

fileList.forEach(file => {
formData.append('file', file.originFileObj);
});


// 每个表单是否填写完成
let params = [];

.....


let data = {};
data.filePath = "";
data.markers = params;
formData.append("params", data);

$.ajax({
url: "/marker/file",
type: "POST",
processData: false,
contentType: false,
data: formData,
success: function (data) {
},
error: function (err) {
}
});

spring boot 处理

1
2
3
4
@PostMapping("/file")
public Object markerFile(@RequestParam("file") MultipartFile multipartFile, Params params){
return markerService.marker(multipartFile,params);
}

注意

  1. antd 上传组件里,真正的文件是 file.originFileObj
  2. params 是复杂的对象的话, spring boot 接受的 Params 对象需要使用 String 字符串进行序列化成对象; 或者将 Params 对象的属性分开来写, 如果某个属性又是复杂对象的话通用需要序列化
0%