深入理解Marr-Hildreth算子的原理、实现与应用
Marr-Hildreth算子是一种基于零交叉检测的边缘检测算法,结合了高斯滤波和拉普拉斯算子,也被称为LoG(Laplacian of Gaussian)算子。
Marr-Hildreth算子由David Marr和Ellen Hildreth在1980年提出,是一种基于生物视觉理论的边缘检测方法。该算法分为两个步骤:
该算法的核心思想是在不同尺度下检测边缘,通过寻找拉普拉斯算子的零交叉点来确定边缘位置。
| 参数 | 说明 | 影响 |
|---|---|---|
| σ (sigma) | 高斯标准差 | 决定平滑程度和边缘尺度 |
| 核大小 | LoG 滤波器尺寸 | 通常取 6σ 或更大 |
| 阈值 | 过零点检测阈值 | 控制边缘灵敏度 |
LoG(Laplacian of Gaussian)函数的数学表达式为:
LoG(x, y) = [x2 + y2 - 2σ2] / [σ⁴] × e^[-(x2 + y2)/(2σ2)]
import cv2
import numpy as np
import matplotlib.pyplot as plt
def marr_hildreth_operator(image_path, sigma=1.0, kernel_size=15):
"""
实现Marr-Hildreth算子(LoG算子)
:param image_path: 输入图像路径
:param sigma: 高斯核标准差
:param kernel_size: 核大小
:return: 原图和边缘检测结果
"""
# 读取图像
img = cv2.imread(image_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 先应用高斯滤波
gaussian_blurred = cv2.GaussianBlur(gray, (kernel_size, kernel_size), sigma)
# 应用拉普拉斯算子
laplacian = cv2.Laplacian(gaussian_blurred, cv2.CV_64F)
# 计算绝对值并转换为uint8
laplacian_abs = np.uint8(np.absolute(laplacian))
return img, laplacian_abs
def create_log_kernel(size, sigma):
"""
创建LoG (Laplacian of Gaussian) 核
:param size: 核大小
:param sigma: 高斯核标准差
:return: LoG核
"""
kernel = np.zeros((size, size), dtype=np.float32)
center = size // 2
# 计算LoG核
for i in range(size):
for j in range(size):
x, y = i - center, j - center
exp_term = np.exp(-(x**2 + y**2) / (2 * sigma**2))
log_term = (x**2 + y**2 - 2 * sigma**2) / (2 * np.pi * sigma**6)
kernel[i, j] = log_term * exp_term
# 归一化
kernel = kernel - np.mean(kernel)
return kernel
def manual_marr_hildreth(image_path, sigma=1.0, kernel_size=15):
"""
手动实现Marr-Hildreth算子
:param image_path: 输入图像路径
:param sigma: 高斯核标准差
:param kernel_size: 核大小
:return: Marr-Hildreth边缘检测结果
"""
# 读取图像
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# 创建LoG核
log_kernel = create_log_kernel(kernel_size, sigma)
# 应用LoG核
log_result = cv2.filter2D(img, cv2.CV_64F, log_kernel)
# 计算绝对值并转换为uint8
log_abs = np.uint8(np.absolute(log_result))
return cv2.cvtColor(img, cv2.COLOR_GRAY2BGR), log_abs
def detect_zero_crossings(image_path, sigma=1.0, threshold=5):
"""
基于零交叉检测的Marr-Hildreth算子
:param image_path: 输入图像路径
:param sigma: 高斯核标准差
:param threshold: 零交叉检测阈值
:return: 原图和零交叉边缘检测结果
"""
# 读取图像
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# 应用高斯滤波
gaussian_blurred = cv2.GaussianBlur(img, (0, 0), sigma)
# 应用拉普拉斯算子
laplacian = cv2.Laplacian(gaussian_blurred, cv2.CV_64F)
# 检测零交叉
height, width = laplacian.shape
zero_crossings = np.zeros_like(laplacian, dtype=np.uint8)
for i in range(1, height-1):
for j in range(1, width-1):
# 检查周围像素是否发生符号变化
neighbors = [
laplacian[i-1, j], laplacian[i+1, j],
laplacian[i, j-1], laplacian[i, j+1],
laplacian[i-1, j-1], laplacian[i-1, j+1],
laplacian[i+1, j-1], laplacian[i+1, j+1]
]
# 检查是否有零交叉
positive_count = sum(1 for n in neighbors if n > threshold)
negative_count = sum(1 for n in neighbors if n < -threshold)
if positive_count > 0 and negative_count > 0:
# 检查中心像素是否接近零
if abs(laplacian[i, j]) < threshold * 2:
zero_crossings[i, j] = 255
return cv2.cvtColor(img, cv2.COLOR_GRAY2BGR), zero_crossings
def multi_scale_marr_hildreth(image_path, sigmas=[0.5, 1.0, 1.5, 2.0]):
"""
多尺度Marr-Hildreth边缘检测
:param image_path: 输入图像路径
:param sigmas: 不同尺度的sigma值列表
:return: 原图和多尺度边缘检测结果
"""
# 读取图像
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
results = []
for sigma in sigmas:
# 应用高斯滤波
gaussian_blurred = cv2.GaussianBlur(img, (0, 0), sigma)
# 应用拉普拉斯算子
laplacian = cv2.Laplacian(gaussian_blurred, cv2.CV_64F)
# 计算绝对值并转换为uint8
laplacian_abs = np.uint8(np.absolute(laplacian))
results.append(laplacian_abs)
return cv2.cvtColor(img, cv2.COLOR_GRAY2BGR), results
def compare_log_with_canny(image_path, sigma=1.0):
"""
比较LoG和Canny边缘检测
:param image_path: 输入图像路径
:param sigma: LoG的sigma值
:return: 原图、LoG结果和Canny结果
"""
# 读取图像
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# LoG边缘检测
gaussian_blurred = cv2.GaussianBlur(img, (0, 0), sigma)
laplacian = cv2.Laplacian(gaussian_blurred, cv2.CV_64F)
log_result = np.uint8(np.absolute(laplacian))
# Canny边缘检测
canny_result = cv2.Canny(img, 50, 150)
return (cv2.cvtColor(img, cv2.COLOR_GRAY2BGR),
log_result,
canny_result)
def advanced_zero_crossing_detection(image_path, sigma=1.0, threshold=10):
"""
改进的零交叉检测算法
:param image_path: 输入图像路径
:param sigma: 高斯核标准差
:param threshold: 阈值
:return: 原图和改进的零交叉边缘检测结果
"""
# 读取图像
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# 应用高斯滤波
gaussian_blurred = cv2.GaussianBlur(img, (0, 0), sigma)
# 应用拉普拉斯算子
laplacian = cv2.Laplacian(gaussian_blurred, cv2.CV_64F)
# 更精确的零交叉检测
height, width = laplacian.shape
zero_crossings = np.zeros_like(laplacian, dtype=np.uint8)
for i in range(1, height-1):
for j in range(1, width-1):
# 检查水平方向零交叉
if (laplacian[i, j-1] > threshold and laplacian[i, j+1] < -threshold) or \
(laplacian[i, j-1] < -threshold and laplacian[i, j+1] > threshold):
zero_crossings[i, j] = 255
# 检查垂直方向零交叉
elif (laplacian[i-1, j] > threshold and laplacian[i+1, j] < -threshold) or \
(laplacian[i-1, j] < -threshold and laplacian[i+1, j] > threshold):
zero_crossings[i, j] = 255
# 检查对角方向零交叉
elif (laplacian[i-1, j-1] > threshold and laplacian[i+1, j+1] < -threshold) or \
(laplacian[i-1, j-1] < -threshold and laplacian[i+1, j+1] > threshold):
zero_crossings[i, j] = 255
elif (laplacian[i-1, j+1] > threshold and laplacian[i+1, j-1] < -threshold) or \
(laplacian[i-1, j+1] < -threshold and laplacian[i+1, j-1] > threshold):
zero_crossings[i, j] = 255
return cv2.cvtColor(img, cv2.COLOR_GRAY2BGR), zero_crossings
# 使用示例
if __name__ == "__main__":
# 注意:需要提供实际的图像路径
# img, result = marr_hildreth_operator('image.jpg', 1.0, 15)
# manual_img, manual_result = manual_marr_hildreth('image.jpg', 1.0, 15)
# zero_img, zero_result = detect_zero_crossings('image.jpg', 1.0, 5)
# multi_img, multi_results = multi_scale_marr_hildreth('image.jpg', [0.5, 1.0, 1.5])
# comp_img, log_res, canny_res = compare_log_with_canny('image.jpg', 1.0)
# adv_img, adv_result = advanced_zero_crossing_detection('image.jpg', 1.0, 10)
pass