2. 拉普拉斯算子对焦评价函数
任务目标
实现基于拉普拉斯算子的自动对焦评价函数:对同一场景在不同对焦位置采集的图像序列,计算每帧图像的拉普拉斯响应能量作为清晰度得分,并比较不同窗口大小(3×3、5×5)对评价曲线的影响。
实现原理
拉普拉斯算子计算图像二阶导数,对边缘和细节敏感。对焦准确的图像高频分量丰富,拉普拉斯响应值大;离焦图像被低通滤波,响应值小。评价函数定义为拉普拉斯响应图像的方差(或能量),窗口大小决定参与计算的邻域范围。
依赖环境
- Python 3.8+
- OpenCV(
pip install opencv-python) - NumPy(
pip install numpy)
完整实现
import cv2
import numpy as np
def laplacian_focus_score(image, ksize=3):
"""
拉普拉斯对焦评价函数
image: 灰度图 (H, W) uint8
ksize: 拉普拉斯核大小,支持 1/3/5
返回: 拉普拉斯响应方差(越大越清晰)
"""
if len(image.shape) == 3:
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
else:
gray = image
lap = cv2.Laplacian(gray, cv2.CV_64F, ksize=ksize)
return lap.var()
def simulate_focal_series(base_img, blur_levels):
"""
模拟对焦序列:用不同强度高斯模糊模拟离焦程度
base_img: 清晰图像
blur_levels: 模糊核大小列表,越大越模糊
返回: [(level, blurred_img), ...]
"""
series = []
for k in blur_levels:
if k == 0:
series.append((k, base_img.copy()))
else:
# 高斯核大小必须为奇数
ksize = k if k % 2 == 1 else k + 1
blurred = cv2.GaussianBlur(base_img, (ksize, ksize), 0)
series.append((k, blurred))
return series
def compare_windows(series):
"""
比较不同窗口大小下的评价曲线
series: [(level, img), ...]
返回: {ksize: [score_per_frame, ...]}
"""
results = {3: [], 5: []}
for _, img in series:
results[3].append(laplacian_focus_score(img, ksize=3))
results[5].append(laplacian_focus_score(img, ksize=5))
return results
if __name__ == "__main__":
# 生成测试图像:棋盘格+圆点,含丰富高频细节
img = np.zeros((256, 256), dtype=np.uint8)
img[::16, :] = 255
img[:, ::16] = 255
cv2.circle(img, (128, 128), 40, 255, 2)
cv2.circle(img, (64, 64), 20, 255, 1)
# 模拟从清晰到严重离焦的序列
blur_levels = [0, 3, 5, 7, 9, 11, 13]
series = simulate_focal_series(img, blur_levels)
# 计算两种窗口的评价分数
results = compare_windows(series)
# 打印结果(仅展示趋势,非实测数据)
print("模糊核大小 | ksize=3 分数 | ksize=5 分数")
for i, level in enumerate(blur_levels):
print(f" {level:2d} | {results[3][i]:10.1f} | {results[5][i]:10.1f}")
# 验证:清晰帧(level=0)分数应为序列中最大值
assert max(results[3]) == results[3][0], "3x3 窗口未在清晰帧取得最大分数"
assert max(results[5]) == results[5][0], "5x5 窗口未在清晰帧取得最大分数"
print("\n验证通过:两种窗口均在清晰帧(level=0)取得最大分数")
运行方式
python laplacian_focus.py
验证方法与判定标准
- 趋势验证:输出表中,模糊程度增加(level增大)时,两种窗口的分数应单调下降或总体下降,清晰帧(level=0)分数最高。
- 断言验证:程序末尾的
assert语句自动检查清晰帧是否为最大值,若通过则打印“验证通过”。 - 窗口差异观察:5×5窗口对噪声更平滑,分数曲线通常比3×3更平缓;3×3对细节更敏感,峰值更尖锐。实际对焦系统中,窗口越大抗噪性越好,但灵敏度下降。
关键说明
- 本案例使用高斯模糊模拟离焦,真实相机离焦的光学模型更复杂,但评价函数的单调性趋势一致。
cv2.Laplacian的ksize参数支持1、3、5,其中ksize=1时使用3×3核的快速近似,本案例仅比较3和5。- 实际相机对焦时,需在电机移动的每个位置采集一帧并计算分数,取分数最大的位置作为对焦点,即“爬山算法”的基础。