4. 声呐图像预处理与增强
前视声呐、侧扫声呐或多波束成像声呐输出的原始图像,与光学相机图像有本质差异:它记录的是回波强度而非反射光,成像过程受波束宽度、传播损失、混响、多径和底质特性共同影响。典型原始声呐图往往呈现三个特征:整体偏暗、目标与背景灰度接近(低对比度)、叠加大量斑点噪声与条纹干扰。如果直接把这样的图像送入边缘检测或目标识别环节,检测算子会把噪声当成边缘,分割阈值也难以稳定选取。因此,预处理与增强是避障感知链路中不可跳过的一环,其目标不是"把图变好看",而是让后续算法能稳定地提取目标轮廓与障碍物区域。
一、声呐图像的三类典型退化
理解退化机理才能选对方法。第一类是斑点噪声(speckle):声呐回波由大量随机散射体叠加而成,相干成像导致相邻像素灰度随机起伏,表现为颗粒状明暗斑,属于乘性噪声,用简单的均值滤波会同时抹平目标边缘。第二类是低对比度与亮度不均:声波随距离衰减,图像近端亮、远端暗,目标回波强度差异被压缩在很窄的灰度区间内。第三类是条纹与旁瓣干扰:波束旁瓣、水面/水底反射和多径效应会在图像中形成亮线或弧形伪影,容易被误判为障碍物。
针对这三类退化,工程上通常按"去噪 → 灰度拉伸 → 边缘增强"的顺序处理,但顺序并非绝对,例如强条纹干扰可先做方向性滤波再降噪。下图给出了一条完整的声呐图像增强处理链,以及每一级处理前后的典型图像特征变化:
二、滤波去噪:先分清噪声类型再选算子
声呐图像的斑点噪声是乘性噪声,模型可近似写为 g(x,y) = f(x,y)·n(x,y),其中 f 为真实回波强度,n 为随机调制因子。对这类噪声,线性均值滤波虽然能压低方差,但会把目标边缘一起模糊,导致后续边缘检测的定位精度下降。实践中更常用三类方法:
- 中值滤波:对 3×3 或 5×5 邻域取中值,对孤立的亮斑/暗斑(椒盐型干扰)抑制效果好,计算量小,适合实时性要求高的前视声呐。缺点是窗口过大时细小目标会被吞掉。
- Lee 滤波:针对乘性噪声设计,按局部方差与均值的比值自适应调整权重,在均匀区域强平滑、在边缘区域弱平滑,是声呐图像去斑的经典选择。
- 双边滤波:同时考虑空间距离与灰度差,能在去噪的同时较好保持目标轮廓,代价是计算量高于中值滤波,适合离线或算力充裕的平台。
选择原则可以概括为:如果干扰以孤立亮点为主,优先中值滤波;如果整幅图颗粒感明显且目标较大,用 Lee 滤波;如果目标轮廓的保持比平滑程度更重要,用双边滤波。实际调参时,窗口尺寸应与目标在图像中的像素尺度匹配——目标只有十几个像素宽时,5×5 以上的窗口就可能把它抹掉。
三、灰度变换:把被压缩的差异拉开
声呐图像远端回波弱,灰度常集中在低值区,直接做全局直方图均衡往往把噪声也一并放大。更稳妥的做法是组合使用:
- 对数变换
s = c·log(1+r):压缩高灰度、扩展低灰度,正好对应声呐近端强回波、远端弱回波的分布,能提升远处目标的可见度。 - CLAHE(限制对比度自适应直方图均衡):把图像分成若干小块分别均衡,并用 clipLimit 限制对比度放大倍数,避免均匀水域区域噪声被过度增强。典型参数为 tile 8×8、clipLimit 2.0,可按图像尺寸微调。
- Gamma 校正
s = 255·(r/255)^γ:γ<1 提亮暗部,γ>1 压暗亮部,用于整体亮度偏置的快速修正。
判断灰度变换是否有效的依据不是"看起来更亮",而是目标区域与背景区域的灰度差是否增大、直方图是否从窄峰展宽为可分离的双峰或多峰。可以在处理前后各取一块目标区和一块纯背景区,计算两者均值之差,差值明显增大说明变换方向正确。
四、边缘增强:为检测算子准备干净的梯度
去噪和灰度拉伸之后,目标轮廓通常仍偏软。边缘增强的常用手段包括 Sobel 梯度、Canny 边缘检测、形态学顶帽变换和非锐化掩模。对声呐图像而言,有两点需要特别注意:其一,Canny 的双阈值对噪声敏感,应在去噪之后使用,且高阈值不宜设得过低,否则混响区域会产生大量伪边缘;其二,形态学顶帽变换(原图减去开运算结果)能突出比背景亮的孤立目标,对检测沉底或悬浮的小目标很有效,结构元素尺寸应略大于目标尺度。
五、实战任务:一段可复现的增强流程
下面给出一个基于 Python + OpenCV 的示例流程,输入为一幅单通道 8 位前视声呐灰度图(示例参数为合理假设,实际使用时按设备输出调整)。流程依次完成中值去噪、CLAHE 增强、Sobel 边缘增强,并输出处理前后的对比指标。
import cv2
import numpy as np
img = cv2.imread("sonar_raw.png", cv2.IMREAD_GRAYSCALE)
# 1) 中值滤波去斑点,窗口 3x3
denoised = cv2.medianBlur(img, 3)
# 2) CLAHE 灰度增强,tile 8x8,clipLimit 2.0
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
enhanced = clahe.apply(denoised)
# 3) Sobel 梯度幅值作为边缘增强图
gx = cv2.Sobel(enhanced, cv2.CV_32F, 1, 0, ksize=3)
gy = cv2.Sobel(enhanced, cv2.CV_32F, 0, 1, ksize=3)
mag = cv2.magnitude(gx, gy)
edge = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)
# 4) 定量对比:目标区与背景区灰度差
def region_mean(im, x, y, w, h):
return float(im[y:y+h, x:x+w].mean())
tgt_before = region_mean(img, 120, 90, 40, 30) # 目标区示例坐标
bg_before = region_mean(img, 20, 20, 40, 30) # 背景区示例坐标
tgt_after = region_mean(enhanced, 120, 90, 40, 30)
bg_after = region_mean(enhanced, 20, 20, 40, 30)
print("增强前目标-背景差:", tgt_before - bg_before)
print("增强后目标-背景差:", tgt_after - bg_after)
cv2.imwrite("sonar_enhanced.png", enhanced)
cv2.imwrite("sonar_edge.png", edge)
运行后应重点观察三件事:一是增强图中目标轮廓是否连续、是否出现新的亮斑伪影;二是"增强后目标-背景差"是否明显大于增强前(示例中若从约 15 灰度级提升到 40 以上,说明对比度改善有效);三是边缘图中混响区是否产生大片伪边缘。若伪边缘过多,应回头提高 Canny 高阈值或增大中值滤波窗口;若目标被抹掉,则应减小滤波窗口或降低 CLAHE 的 clipLimit。参数调整应遵循"一次只改一个变量、用同一幅图对比"的原则,保证结果可复现。