引言
雾天图像由于能见度降低,往往会导致图像对比度较低,影响后续计算机视觉任务的效果。本文介绍一种基于暗通道先验的方法,通过计算图像的暗通道均值,快速判断图像是否为雾天。
暗通道先验的理论基础
暗通道先验由 He 等人在论文《Single Image Haze Removal Using Dark Channel Prior》中提出,其核心假设是:在无雾自然图像的大多数非天空区域,至少在一个颜色通道上,总会有一些像素值接近于零。因此,雾天图像的暗通道均值会显著高于无雾图像。
暗通道定义为:
J
dark
(
x
)
=
min
y
∈
Ω
(
x
)
(
min
c
∈
{
r
,
g
,
b
}
J
c
(
y
)
)
J_{\text{dark}}(x) = \min_{y\in\Omega(x)} \left(\min_{c \in \{r,g,b\}} J^c(y)\right)
Jdark(x)=y∈Ω(x)min(c∈{r,g,b}minJc(y))
- J ( x ) 是输入图像; J(x) 是输入图像; J(x)是输入图像;
- Ω ( x ) 是以像素 x 为中心的局部窗口; \Omega(x) 是以像素 x 为中心的局部窗口; Ω(x)是以像素x为中心的局部窗口;
- min c ∈ { r , g , b } 是对 R / G / B 三个通道取最小值。 \min_{c \in \{r, g, b\}} 是对 R/G/B 三个通道取最小值。 minc∈{r,g,b}是对R/G/B三个通道取最小值。
代码实现
以下是基于暗通道先验判定雾天图像的主要实现步骤:
1. 计算暗通道
通过对图像的每个像素点,在局部窗口内取最小值,并在三个颜色通道上取最小值,得到暗通道图像。
2. Resize 提高效率
为了减少计算量,可以在计算暗通道之前对图像进行缩放。缩小图像分辨率不会显著影响暗通道的均值结果,但能显著提升计算效率。
3.判断雾天
通过统计暗通道的均值,设置阈值进行判定。当暗通道均值高于阈值时,认为是雾天图像。
以下是核心代码:
class FogDetector:
def __init__(self, dark_channel_threshold=0.4, resize_factor=0.5):
"""
初始化检测器
:param dark_channel_threshold: 暗通道阈值,低于该值判定为无雾图像
:param resize_factor: 缩放比例,用于降低图像分辨率以提升计算效率
"""
self.dark_channel_threshold = dark_channel_threshold
self.resize_factor = resize_factor
def get_dark_channel(self, image, patch_size=15):
"""
计算图像的暗通道
:param image: 输入的 BGR 图像
:param patch_size: 暗通道计算的窗口大小
:return: 暗通道图
"""
# 转换为浮点型,归一化到 [0,1]
image = image.astype(np.float32) / 255.0
# 获取最小通道
min_channel = np.min(image, axis=2)
# 使用最小滤波计算暗通道
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (patch_size, patch_size))
dark_channel = cv2.erode(min_channel, kernel)
return dark_channel
def is_foggy(self, image_path):
"""
判断图像是否有雾
:param image_path: 图像路径
:return: 如果图像有雾返回 True,无雾返回 False
"""
# 读取图像
image = cv2.imread(image_path)
if image is None:
print(f"无法读取图像: {image_path}")
return True # 默认有雾,丢弃图像
# 缩放图像以提升计算效率
new_width = int(image.shape[1] * self.resize_factor)
new_height = int(image.shape[0] * self.resize_factor)
resized_image = cv2.resize(image, (new_width, new_height), interpolation=cv2.INTER_AREA)
# 计算暗通道
dark_channel = self.get_dark_channel(resized_image)
# 统计暗通道的平均值
dark_channel_mean = np.mean(dark_channel)
# 打印调试信息
print(f"暗通道均值: {dark_channel_mean} - 图像: {image_path}")
# 判断是否有雾
return dark_channel_mean > self.dark_channel_threshold
使用方式
假设我们有一个图像文件夹 your_image_folder,需要对其中的图像进行雾天检测:
fog_detector = FogDetector(dark_channel_threshold=0.4)
image_folder = "your_image_folder"
for image_name in os.listdir(image_folder):
image_path = os.path.join(image_folder, image_name)
if fog_detector.is_foggy(image_path):
print(f"图像 {image_name} 为雾天图像")
else:
print(f"图像 {image_name} 为无雾图像")
参数说明
- dark_channel_threshold:设置暗通道均值的阈值,越高越严格。
- resize_factor:缩放比例,用于提高计算效率,设置为 0.5 表示将图像宽高各缩小一半。