python-opencv学习笔记:判断是否雾天与图像能见度测算
Posted submarineas
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python-opencv学习笔记:判断是否雾天与图像能见度测算相关的知识,希望对你有一定的参考价值。
引言
本篇是最近碰到的一个关于雾天能见度的问题,然后查阅到很多资料,顺便记录一下思考过程,进行总结归类成笔记。主要参考资料是华为杯2020年E题论文,结合一下自己的实际情况,做出了改进与延伸,文献在最后引出。
相关定义说明
能见度定义:
1. 大气能见度: 能见度是气象、公路行车、飞机飞行中常见指标,单位通常是米。在气象上的能见度定义为:标准视力眼睛观察到水平方向以天空为背景的黑体目标物(0.50)标注为你轮廓的最大水平距离。
2. 雾: 在水汽充足、微风及大气稳定的情况下,相对湿度达到100%时,空气中的水汽便会凝结成细微的水滴悬浮于空中,使地面水平的能见度下降,这种天气现象称为雾。
3. 团雾: 是受局部地区微气候环境的影响,在大雾中数十米到上百米的局部范围内,出现的更“浓”、能见度更低的雾。团雾外视线良好,团雾内一片朦胧。
4. 目标物和背景的亮度对比: 在大气中目标物能见与否,取决于本身亮度,又与它同背景的亮度差异有关。比如,亮度暗的目标物在亮的背景衬托下,清晰可见。或者亮的目标物在暗的背景下,同样清晰可见。表示这种差异的指标是亮度的对比值K。设 为目标物的固有亮度, 为背景的固有亮度,则亮度的对比值定义为:
K = ∣ B 0 ′ − B 0 ∣ B 0 ′ , if B 0 ′ ≥ B 0 ; K = ∣ B 0 ′ − B 0 ∣ B 0 , if B 0 ′ < B 0 K=\\frac\\left|B_0^\\prime-B_0\\right|B_0^\\prime \\text , if \\quad B_0^\\prime \\geq B_0 ; \\quad K=\\frac\\left|B_0^\\prime-B_0\\right|B_0 \\text , if B_0^\\prime<B_0 K=B0′∣B0′−B0∣, if B0′≥B0;K=B0∣B0′−B0∣, if B0′<B0
5 能见度测量基本方程:
F
=
F
0
e
−
σ
z
F=F_0 e^-\\sigma z
F=F0e−σz
这里 F F F和 F 0 F_0 F0分别表示观测和入射的光照强度,参数 σ \\sigma σ称为衰减系数,与雾的厚度有关: σ \\sigma σ越大表明雾越浓。气象光学视程(MOR)
MOR = log ( F / F 0 ) − σ = log ( 0.05 ) − σ \\operatornameMOR=\\frac\\log \\left(F / F_0\\right)-\\sigma=\\frac\\log (0.05)-\\sigma MOR=−σlog(F/F0)=−σlog(0.05)
能见度分级:
高速公路能见度等级划分与影响程度:
等级 | 能见度 L 范围/m | 影响程度 |
---|---|---|
0级 | L > 500 | - |
1级 | 200<L<500 | 交通预警 |
2级 | 100<L<500 | 预警或交通管制 |
3级 | 50<L<100 | 交通管制 |
4级 | L < 50 | 全线或者局部封闭 |
根据《中华人民共和国气象行业标准》,为了满足高速公路检测场景的服务需求,对雾霾引起的低能见度进行了相应的等级划分,该标准将能见度范围划分为 5 个级别,具体分类如下表所示。当能见度大于 200 米时,即能见度等级为 0 级或 1 级时,高速管理部门无需对车流量和车辆行驶速度进行监管处理,在能见度小于 200 米时,监控人员需要滴交通路况进行管控甚至封路。
是否判断有雾
什么是雾?
在水汽充足、微风及大气稳定的情况下,相对湿度达到100%时,空气中的水汽便会凝结成细微的水滴悬浮于空中,使地面水平的能见度下降,这种天气现象称为雾(Fog)。多出现于春季二至四月间。 形成的条件: 一是冷却,二是加湿,增加水汽含量。 种类有辐射雾、平流雾、混合雾、蒸发雾等。
上面是百度百科中的定义,如果从图片和视频的角度上去分析,雾其实是一种灰色的会让画面产生朦胧感,或者是模糊的一种物质,判断是否有雾的算法是有很多方式,我们可以通过亮度对比,以及基于图像方差或者均值,换种角度,雾气也可以说是一种模糊化产物,那也能通过模糊检测的方式定义这种结构,所以,现在最主流的方法是基于暗通道先验理论,下面将对其分别进行介绍。
图像平均强度
图像强度表示的是单通道图像像素的强度(值的大小),在灰度图像中,它是图像的灰度。在RGB颜色空间中,可以理解把它为是R通道的像素灰度值,G通道的像素灰度值,或是B通道的像素灰度值,也就是RGB中含三个image intensity。
那么我们可以根据在灰度图像中,求出它的平均强度,然后选取相应的阈值来判断是否有雾,并做到筛选或者过滤,基本逻辑为:
im_grey = im.convert('LA')
for i in range(0, width):
for j in range(0, height):
total += im.getpixel((i, j))[0]
mean = total / (width * height)
转移到RGB色域,选用120作为强度的阈值,我们可以作为参数进行不断调整:
import os
results = []
for dirpath, dirnames, filenames in os.walk(r"E:\\BaiduNetdiskDownload\\fog_test"):
for filenames in [f for f in filenames if f.endswith('.jpg')]:
# print(dirpath,dirnames,filenames,"......sss")
filename = os.path.join(dirpath,filenames)
img = cv2.imread(filename)
avg_color_per_row = np.average(img, axis=0)
avg_color = np.average(avg_color_per_row, axis=0)
results.append(sum(avg_color / 3))
np_results = np.array(results)
plt.hist(np_results, bins=100)
plt.show()
但在我的测试中,以及查询到的资料来看,该方法事实上还是不能很好的过滤有雾和无雾,至少我检测的路面情况来看,两张同样大小的720 * 576的同场景图片,只是一张很明显有雾,一张无,但是results的结果为[128.92051591582342, 122.75210925443668],所以,我大概估计如果说图片亮度较高,而且颜色比较艳丽突出,我们可以尝试选用图像的平均强度作为衡量标准,不然效果不佳。
那么图片平均强度不行,是否可以选用平均方差呢?
图像方差
**方差(variance) ** 是在概率论和统计方差衡量随机变量或一组数据时离散程度的度量。概率论中方差用来度量随机变量和其数学期望(即均值)之间的偏离程度。统计中的方差(样本方差)是每个样本值与全体样本值的平均数之差的平方值的平均数。在许多实际问题中,研究方差即偏离程度有着重要意义。
在图像中,方差是计算每个像元的灰度值减去图像平均灰度值的平方和除以总的像素个数。其实就是将数学中常见的实际抽样问题变成了一张图像关于灰度值的方差问题。而雾其实也算是灰的,那么在实际检测中效果如何呢?我这里选用了四张图片进行方差分析,结果如下:
from PIL import Image
import glob
def slow_horizontal_variance(im):
'''Return average variance of horizontal lines of a grayscale image'''
width, height = im.size
if not width or not height: return 0
vars = []
pix = im.load()
for y in range(height):
row = [pix[x,y] for x in range(width)]
mean = sum(row)/width
variance = sum([(x-mean)**2 for x in row])/width
vars.append(variance)
return sum(vars)/height
for fn in glob.glob(r'E:\\BaiduNetdiskDownload\\qq_test\\*.jpg'):
im = Image.open(fn).convert('L')
var = slow_horizontal_variance(im)
fog = var < 200 # FOG THRESHOLD
print('%5.0f - %5s - %s' % (var, fog and 'FOGGY' or 'SHARP', fn))
图片的水平均值方差结果如下:
Horizontal mean variance is 142 |
Horizontal mean variance is 504 |
Horizontal mean variance is 86 |
Horizontal mean variance is 327 |
结果上看,效果确实还算不错,比直接做均值是有很明显的提升,但第二幅图和第四幅图感觉还是有点差强人意,这只能说作为一种直接判断灰度的方式,方差有其比较好的地方,但如果雾还没由白转灰,比如上面没有被判定为雾的图片,虽说我阈值设置得比较小,但在我测试其它图片的时候,发现200到300已经算是最能区分雾的情况了。
那么介绍了均值,以及标准差,自然而然一个不得不说的因素是平均梯度,这种也能作为衡量雾气,或者图片模糊等情况的一个指标,这三者的关系是:
- 均值反映了图像的亮度,均值越大说明图像亮度越大,反之越小;
- 标准差反映了图像像素值与均值的离散程度,标准差越大说明图像的质量越好;
- 平均梯度反映了图像的清晰度和纹理变化,平均梯度越大说明图像越清晰;
所以这里,根据网上查找到的资料,使用拉普拉斯算子进行梯度求取。
图像平均梯度
平均梯度有许多种算子供使用,但拉普拉斯算子是最简单的各向同性微分算子,具有旋转不变性。一个二维图像函数的拉普拉斯变换是各向同性的二阶导数,定义为:
∇
2
f
(
x
,
y
)
=
∂
2
f
∂
x
2
+
∂
2
f
∂
y
2
\\nabla^2 f(x, y)=\\frac\\partial^2 f\\partial x^2+\\frac\\partial^2 f\\partial y^2
∇2f(x,y)=∂x2∂2f+∂y2∂2f
在一个二维函数f(x,y)中,x,y两个方向的二阶差分分别为:
∂
2
f
∂
x
2
=
f
(
x
+
1
,
y
)
+
f
(
x
−
1
,
y
)
−
2
f
(
x
,
y
)
∂
2
f
∂
y
2
=
f
(
x
,
y
+
1
)
+
f
(
x
,
y
−
1
)
−
2
f
(
x
,
y
)
\\beginaligned &\\frac\\partial^2 f\\partial x^2=f(x+1, y)+f(x-1, y)-2 f(x, y) \\\\ &\\frac\\partial^2 f\\partial y^2=f(x, y+1)+f(x, y-1)-2 f(x, y) \\endaligned
∂x2∂2f=f(x+1,y)+f(x−1,y)−2f(x,y)∂y2∂2f=f(x,y+1)+f(x,y−1)−2f(x,y)
为了更适合于数字图像处理,将该方程表示为离散形式: 以上是关于python-opencv学习笔记:判断是否雾天与图像能见度测算的主要内容,如果未能解决你的问题,请参考以下文章
∇
2
f
=
[
f
(
x
+
1
,
y
)
+
f
(
x
−
1
,
y
)
+
f
(
x
,
y
+
1
)
+
f
(
x
,
y
−
1
)
]
−
4
f
(
x
,
y
)
\\nabla^2 f=[f(x+1, y)+f(x-1, y)+f(x, y+1)+f(x, y-1)]-4 f(x, y)
∇2f=[f(x+1,y)+f(x−