深入理解双边滤波的原理、实现与应用
双边滤波是一种非线性滤波技术,能够在平滑图像的同时很好地保持边缘信息,广泛用于图像去噪和美颜。
双边滤波结合了空间邻近度和像素值相似度的双重考虑,为每个像素的邻域内的其他像素分配权重。与传统的高斯滤波只考虑空间距离不同,双边滤波还考虑像素值的差异。
| 参数 | 说明 | 典型值 |
|---|---|---|
| d | 邻域直径 | 9 |
| σ_color | 颜色空间标准差 | 75 |
| σ_space | 坐标空间标准差 | 75 |
双边滤波的公式为:
I'(p) = (1/Wp) × Σ I(q) × Gs(||p-q||) × Gr(|I(p)-I(q)|)
其中:
import cv2
import numpy as np
import matplotlib.pyplot as plt
def bilateral_filter_builtin(image_path, d=15, sigma_color=80, sigma_space=80):
"""
使用OpenCV内置函数实现双边滤波
:param image_path: 输入图像路径
:param d: 邻域直径
:param sigma_color: 颜色空间的标准差
:param sigma_space: 坐标空间的标准差
:return: 原图和滤波后的图像
"""
# 读取图像
img = cv2.imread(image_path)
# 应用双边滤波
filtered = cv2.bilateralFilter(img, d, sigma_color, sigma_space)
return img, filtered
def manual_bilateral_filter(image_path, d=15, sigma_color=80, sigma_space=80):
"""
手动实现双边滤波
:param image_path: 输入图像路径
:param d: 邻域直径
:param sigma_color: 颜色空间的标准差
:param sigma_space: 坐标空间的标准差
:return: 双边滤波后的图像
"""
# 读取图像
img = cv2.imread(image_path)
img_float = img.astype(np.float64)
height, width, channels = img.shape
# 计算边界填充大小
pad_size = d // 2
# 对图像进行边界填充
padded_img = np.pad(img_float, ((pad_size, pad_size), (pad_size, pad_size), (0, 0)), mode='edge')
# 创建输出图像
filtered = np.zeros_like(img_float)
# 计算空间权重
space_coeff = -0.5 / (sigma_space * sigma_space)
color_coeff = -0.5 / (sigma_color * sigma_color)
# 应用双边滤波
for i in range(height):
for j in range(width):
# 计算当前像素的权重中心
center_pixel = padded_img[i + pad_size, j + pad_size]
# 初始化权重和加权总和
weight_sum = np.zeros(channels)
weighted_sum = np.zeros((channels,))
# 遍历邻域
for ki in range(-pad_size, pad_size + 1):
for kj in range(-pad_size, pad_size + 1):
neighbor_pixel = padded_img[i + pad_size + ki, j + pad_size + kj]
# 计算空间距离权重
spatial_dist_sq = ki * ki + kj * kj
spatial_weight = np.exp(spatial_dist_sq * space_coeff)
# 计算颜色距离权重
color_dist_sq = np.sum((center_pixel - neighbor_pixel) ** 2)
color_weight = np.exp(color_dist_sq * color_coeff)
# 总权重
total_weight = spatial_weight * color_weight
# 累加权重和加权像素值
weight_sum += total_weight
weighted_sum += neighbor_pixel * total_weight
# 计算加权平均
filtered[i, j] = weighted_sum / weight_sum
return img, filtered.astype(np.uint8)
def edge_preserving_smoothing(image_path, d=15, sigma_color=80, sigma_space=80):
"""
边缘保持平滑(双边滤波的应用)
:param image_path: 输入图像路径
:param d: 邻域直径
:param sigma_color: 颜色空间的标准差
:param sigma_space: 坐标空间的标准差
:return: 原图和边缘保持平滑后的图像
"""
# 读取图像
img = cv2.imread(image_path)
# 应用双边滤波以保持边缘的同时平滑图像
smoothed = cv2.bilateralFilter(img, d, sigma_color, sigma_space)
return img, smoothed
def detail_enhancement(image_path, d=9, sigma_color=75, sigma_space=75):
"""
细节增强(通过减去平滑图像)
:param image_path: 输入图像路径
:param d: 邻域直径
:param sigma_color: 颜色空间的标准差
:param sigma_space: 坐标空间的标准差
:return: 原图和细节增强后的图像
"""
# 读取图像
img = cv2.imread(image_path)
img_float = img.astype(np.float64)
# 应用双边滤波获得平滑版本
smooth = cv2.bilateralFilter(img, d, sigma_color, sigma_space)
# 计算细节(原图减去平滑图)
detail = img_float - smooth.astype(np.float64)
# 增强细节(可调整增强系数)
enhanced = img_float + 0.5 * detail
# 确保像素值在有效范围内
enhanced = np.clip(enhanced, 0, 255)
return img, enhanced.astype(np.uint8)
def texture_filtering(image_path, d=20, sigma_color=50, sigma_space=50):
"""
纹理过滤(保留主要结构,去除细节纹理)
:param image_path: 输入图像路径
:param d: 邻域直径
:param sigma_color: 颜色空间的标准差
:param sigma_space: 坐标空间的标准差
:return: 原图和纹理过滤后的图像
"""
# 读取图像
img = cv2.imread(image_path)
# 使用较大的参数来过滤纹理
filtered = cv2.bilateralFilter(img, d, sigma_color, sigma_space)
return img, filtered
def cartoon_effect(image_path):
"""
卡通效果(结合双边滤波和边缘检测)
:param image_path: 输入图像路径
:return: 原图和卡通效果图像
"""
# 读取图像
img = cv2.imread(image_path)
# 步骤1:多次应用双边滤波以获得平滑效果
filtered = img
for _ in range(2):
filtered = cv2.bilateralFilter(filtered, 9, 200, 200)
# 步骤2:转换为灰度图并应用边缘检测
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 9)
# 步骤3:将边缘图转换为彩色
edges_colored = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
# 步骤4:将边缘图与平滑图结合
cartoon = cv2.bitwise_and(filtered, edges_colored)
return img, cartoon
# 使用示例
if __name__ == "__main__":
# 注意:需要提供实际的图像路径
# img, result = bilateral_filter_builtin('image.jpg', 15, 80, 80)
# manual_img, manual_result = manual_bilateral_filter('image.jpg', 15, 80, 80)
# smooth_img, smooth_result = edge_preserving_smoothing('image.jpg', 15, 80, 80)
# enhance_img, enhance_result = detail_enhancement('image.jpg', 9, 75, 75)
# texture_img, texture_result = texture_filtering('image.jpg', 20, 50, 50)
# cartoon_img, cartoon_result = cartoon_effect('image.jpg')
pass
| 参数 | 说明 | 典型值 |
|---|---|---|
| d | 邻域直径 | 9 |
| σ_color | 颜色空间标准差 | 75 |
| σ_space | 坐标空间标准差 | 75 |