3. 基于Sobel算子的对焦评价函数
任务目标
实现基于Sobel算子的对焦评价函数:对图像分别计算水平与垂直方向的Sobel梯度,将梯度幅值平方累加作为清晰度得分。该得分在图像合焦时达到峰值,离焦时下降。同时验证该评价函数对高斯噪声的鲁棒性,即噪声存在时仍能保持对焦峰值的可区分性。
环境依赖
Python 3.8+,OpenCV(cv2)、NumPy。无需额外数据集,使用合成图像序列模拟离焦过程。
核心实现
import cv2
import numpy as np
def sobel_focus_score(img_gray):
"""Sobel对焦评价:水平+垂直梯度幅值平方和"""
gx = cv2.Sobel(img_gray, cv2.CV_64F, 1, 0, ksize=3)
gy = cv2.Sobel(img_gray, cv2.CV_64F, 0, 1, ksize=3)
return float(np.sum(gx**2 + gy**2))
def simulate_defocus(sharp_img, sigma):
"""用高斯模糊模拟不同离焦程度,sigma越大越模糊"""
return cv2.GaussianBlur(sharp_img, (0, 0), sigma)
def add_gaussian_noise(img, noise_sigma):
"""添加高斯噪声,返回uint8图像"""
noise = np.random.normal(0, noise_sigma, img.shape)
noisy = np.clip(img.astype(np.float64) + noise, 0, 255)
return noisy.astype(np.uint8)
def test_robustness():
"""生成清晰图像→模拟离焦序列→分别测无噪声/有噪声的评分曲线"""
# 合成高纹理测试图(棋盘+随机块,保证梯度丰富)
np.random.seed(42)
base = np.zeros((256, 256), dtype=np.uint8)
base[::16, :] = 255
base[:, ::16] = 255
base[64:192, 64:192] = np.random.randint(0, 255, (128, 128), dtype=np.uint8)
sharp = cv2.GaussianBlur(base, (0, 0), 0.8) # 轻微平滑消除锯齿
sigmas = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0] # 离焦程度递增
print("离焦sigma | 无噪声得分 | 含噪声得分(σ=10)")
print("-" * 45)
for s in sigmas:
blurred = simulate_defocus(sharp, s)
score_clean = sobel_focus_score(blurred)
# 对每个离焦程度独立添加噪声并计算得分(取3次平均降波动)
noisy_scores = []
for _ in range(3):
noisy_img = add_gaussian_noise(blurred, 10)
noisy_scores.append(sobel_focus_score(noisy_img))
score_noisy = np.mean(noisy_scores)
print(f"{s:8.1f} | {score_clean:12.1f} | {score_noisy:14.1f}")
if __name__ == "__main__":
test_robustness()
运行方式
python sobel_focus.py
验证方法与判定标准
运行后观察终端输出的两列得分:
- 单调性验证:无噪声列应随离焦sigma增大而单调递减,sigma=0时得分最高,证明评价函数能区分合焦与离焦。
- 鲁棒性验证:含噪声列(σ=10)应保持与无噪声列相同的单调递减趋势,且sigma=0处仍为最大值。若噪声导致峰值偏移或曲线出现非单调,则说明鲁棒性不足。
- 通过条件:两列数据均满足“sigma=0得分最高,且随sigma增大严格递减”,即判定对焦评价函数有效且对噪声鲁棒。
注意:由于噪声随机性,含噪声列每次运行数值略有波动,但单调趋势应稳定。若需更严格验证,可增大噪声测试次数(如10次)取平均。
关键说明
Sobel核尺寸固定为3×3,梯度平方累加放大了边缘响应,使合焦峰值更尖锐。测试图像采用棋盘格叠加随机纹理,确保各方向梯度丰富,避免因图像内容平坦导致评价失效。实际相机对焦场景中,图像序列由镜头移动产生,本案例用高斯模糊模拟离焦是标准近似方法。