基于核函数的卷积操作 —— 理解卷积原理
文章目录
- 一、核函数
- 1.1、基于 OpenCV 的核函数
- (1)结构元素(矩形核 + 椭圆核 + 十字形核):cv2.getStructuringElement()
- (2)高斯核:cv2.getGaussianKernel()
- 1.2、基于 Numpy 的核函数
- (1)滤波器 - 核函数 —— 均值、高斯、锐化
- (2)形态学变化 - 核函数 —— 腐蚀 + 膨胀 + 开运算 + 闭运算 + 梯度计算 + 顶帽 + 黑帽
- (3)边缘检测算子 - 核函数 —— Roberts、Sobel、Scharr、Prewitt、Laplacian
- 二、项目实战:基于核函数的卷积操作(例如:高斯滤波)
- 1.1、OpenCV 内置函数
- 1.2、自定义核函数 + cv2.filter2D()
- 1.3、自定义核函数 + NumPy手写卷积
卷积操作与形态学操作的区别
- 卷积操作(Convolution):对图像和滤波核进行数学上的加权和。卷积核中的值表示对不同像素的加权程度。对每个像素,卷积操作通过将滤波核与图像局部区域的值相乘并求和来得到输出像素。
- 形态学操作:不涉及加权和,它是基于局部区域内的结构特征来修改图像的形态。核的所有值都为 1 时,形态学操作会检查该局部区域是否满足特定条件(例如局部区域是否包含非零像素),然后根据该条件来改变中心像素。
一、核函数
核函数(Kernel) 是用于图像处理的一种小型矩阵,通常用于卷积操作,以执行滤波、边缘检测、形态学变换等任务。核函数通过滑动窗口的方式作用于图像的像素区域,并计算加权和,从而实现不同的图像处理效果。
方法 | 代码示例 | 适用场景 |
---|---|---|
OpenCV 内置函数 | cv2.GaussianBlur() | 简单快速,性能优化 |
自定义核函数 + cv2.filter2D() | cv2.filter2D(img, -1, kernel) | 自定义卷积核 |
自定义核函数 + NumPy手写卷积 | convolve(image, kernel) | 研究卷积原理 |
1.1、基于 OpenCV 的核函数
(1)结构元素(矩形核 + 椭圆核 + 十字形核):cv2.getStructuringElement()
常见的核形状包括:
- 矩形核:常用于简单的形态学操作,如腐蚀、膨胀。
- 椭圆核:适用于需要平滑操作的任务,可以避免矩形核导致的形状不规则。
- 十字形核:用于处理具有交叉结构的图像特征,保留纵横方向的连接。
import cv2
# 创建 3x3 的矩形结构元素(全1)
kernel_rect = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
print(kernel_rect)
# 创建 5x5 的椭圆结构元素(全1)
kernel_ellipse = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (100, 100))
print(kernel_ellipse)
# 创建 5x5 的十字形结构元素(全1)
kernel_cross = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))
print(kernel_cross)
# 可视化图像(灰度0~255)
import matplotlib.pyplot as plt
plt.subplot(1, 3, 1), plt.imshow(kernel_rect, cmap='gray'), plt.title('kernel_rect'), plt.axis('off')
plt.subplot(1, 3, 2), plt.imshow(kernel_ellipse, cmap='gray'), plt.title('kernel_ellipse'), plt.axis('off')
plt.subplot(1, 3, 3), plt.imshow(kernel_cross, cmap='gray'), plt.title('kernel_cross'), plt.axis('off')
plt.show()
"""
[[1 1 1]
[1 1 1]
[1 1 1]]
[[0 0 1 0 0]
[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]
[0 0 1 0 0]]
[[0 0 1 0 0]
[0 0 1 0 0]
[1 1 1 1 1]
[0 0 1 0 0]
[0 0 1 0 0]]
"""
(2)高斯核:cv2.getGaussianKernel()
import cv2
import matplotlib.pyplot as plt
# 设置高斯核的标准差
sigma = 1.0
# 生成高斯滤波核
kernel_size = 3
gaussian_kernel = cv2.getGaussianKernel(kernel_size, sigma)
gaussian_kernel = gaussian_kernel @ gaussian_kernel.T # 得到2D高斯核
# 可视化图像(灰度0~255)
plt.imshow(gaussian_kernel, cmap='gray')
plt.title(f"Gaussian Kernel (size={kernel_size}, sigma={sigma})")
plt.colorbar()
plt.show()
1.2、基于 Numpy 的核函数
(1)滤波器 - 核函数 —— 均值、高斯、锐化
滤波核(常见卷积核)
- 均值滤波核(cv2.boxFilter() / cv2.blur())
- 高斯滤波核(cv2.GaussianBlur() / cv2.getGaussianKernel())
- 中值滤波核(cv2.medianBlur(),不是基于固定核,而是基于窗口排序取中值)
- 双边滤波核(cv2.bilateralFilter(),结合空间权重和颜色相似度)
import numpy as np
# 生成 3x3 均值核
mean_kernel = np.ones((3, 3), np.float32) / 9
# 生成 3x3 高斯核
gaussian_kernel = np.array([[1, 2, 1],
[2, 4, 2],
[1, 2, 1]], dtype=np.float32) / 16
# 生成 3x3 锐化核
sharpen_kernel = np.array([[0, -1, 0],
[-1, 5, -1],
[0, -1, 0]], dtype=np.float32)
# 可视化图像(灰度0~255)
import matplotlib.pyplot as plt
plt.subplot(1, 3, 1), plt.imshow(mean_kernel, cmap='gray'), plt.title('mean_kernel'), plt.axis('off')
plt.subplot(1, 3, 2), plt.imshow(gaussian_kernel, cmap='gray'), plt.title('gaussian_kernel'), plt.axis('off')
plt.subplot(1, 3, 3), plt.imshow(sharpen_kernel, cmap='gray'), plt.title('sharpen_kernel'), plt.axis('off')
plt.show()
(2)形态学变化 - 核函数 —— 腐蚀 + 膨胀 + 开运算 + 闭运算 + 梯度计算 + 顶帽 + 黑帽
形态学变换核(结构元素)
- 矩形核(cv2.MORPH_RECT)
- 椭圆核(cv2.MORPH_ELLIPSE)
- 十字形核(cv2.MORPH_CROSS)
- 自定义形态学核(cv2.getStructuringElement() 可生成任意大小)
import numpy as np
kernel = np.ones((3, 3), dtype=np.uint8)
"""形态学变化中的核函数通常设置为全1的矩阵(如 np.ones)"""
# 例如:
# 较小的核函数(如3x3)通常用于处理小的噪声,
# 较大的核函数(如5x5或7x7)适用于较大区域的处理。
# 举例:
# 【腐蚀】作用:用于去除图像中的小噪点、减少白色区域、突出结构元素的主要形状。
# 【腐蚀】计算:使用一个核函数作为滑动窗口,遍历图像的每个像素,并计算该像素及其邻域的最小值。
# 对于二值图像:如果核覆盖区域中的所有“1”像素都匹配原图中的“1”,则中心像素保持“1”;否则,中心像素变为“0”。
# 对于灰度图像:将核覆盖区域中的所有像素取最小值,并赋值给中心像素。
# 不同核函数的作用:
# 腐蚀(Erosion):使物体边缘收缩,去除小噪声,细小物体会消失。
# 膨胀(Dilation):使物体边缘扩展,填补空洞,连接物体。
# 开运算(Opening):去除小噪声、细节部分保留。
# 闭运算(Closing):填补图像中的小孔洞或黑点,前景更加连续。
# 梯度(Gradient):增强图像边缘,突出物体轮廓。
# 顶帽(Top Hat):提取小的亮区或细节。
# 黑帽(Black Hat):提取小的暗区或缺失区域。
(3)边缘检测算子 - 核函数 —— Roberts、Sobel、Scharr、Prewitt、Laplacian
边缘检测算子(微分滤波)
- Roberts 算子(二阶微分)
- Prewitt 算子(基于 Sobel 的近似)
- Sobel 算子(cv2.Sobel())
- Scharr 算子(cv2.Scharr(),增强 Sobel)
- Laplacian 算子(cv2.Laplacian(),二阶微分)
- Canny 边缘检测(非核方式)是一个多阶段的边缘检测算法,包含了高斯去噪、梯度计算、非极大值抑制、边缘连接等步骤。Canny算子是通过一系列复杂的处理步骤来实现边缘检测。
import numpy as np
# Roberts算子
roberts_kernel_x = np.array([[ 1, 0],
[ 0, -1]], dtype=np.float32)
roberts_kernel_y = np.array([[ 0, 1],
[-1, 0]], dtype=np.float32)
# Sobel算子
sobel_kernel_x = np.array([[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]], dtype=np.float32)
sobel_kernel_y = np.array([[-1, -2, -1],
[ 0, 0, 0],
[ 1, 2, 1]], dtype=np.float32)
# Scharr算子
scharr_kernel_x = np.array([[-3, 0, 3],
[-10, 0, 10],
[-3, 0, 3]], dtype=np.float32)
scharr_kernel_y = np.array([[-3, -10, -3],
[ 0, 0, 0],
[ 3, 10, 3]], dtype=np.float32)
# Prewitt算子
prewitt_kernel_x = np.array([[-1, 0, 1],
[-1, 0, 1],
[-1, 0, 1]], dtype=np.float32)
prewitt_kernel_y = np.array([[-1, -1, -1],
[ 0, 0, 0],
[ 1, 1, 1]], dtype=np.float32)
# Laplacian算子
laplacian_kernel = np.array([[0, 1, 0],
[1, -4, 1],
[0, 1, 0]], dtype=np.float32)
# 可视化图像(灰度0~255)
import matplotlib.pyplot as plt
plt.subplot(2, 5, 1), plt.imshow(roberts_kernel_x, cmap='gray'), plt.title('roberts_kernel_x'), plt.axis('off')
plt.subplot(2, 5, 6), plt.imshow(roberts_kernel_y, cmap='gray'), plt.title('roberts_kernel_y'), plt.axis('off')
plt.subplot(2, 5, 2), plt.imshow(sobel_kernel_x, cmap='gray'), plt.title('sobel_kernel_x'), plt.axis('off')
plt.subplot(2, 5, 7), plt.imshow(sobel_kernel_y, cmap='gray'), plt.title('sobel_kernel_y'), plt.axis('off')
plt.subplot(2, 5, 3), plt.imshow(scharr_kernel_x, cmap='gray'), plt.title('scharr_kernel_x'), plt.axis('off')
plt.subplot(2, 5, 8), plt.imshow(scharr_kernel_y, cmap='gray'), plt.title('scharr_kernel_y'), plt.axis('off')
plt.subplot(2, 5, 4), plt.imshow(prewitt_kernel_x, cmap='gray'), plt.title('prewitt_kernel_x'), plt.axis('off')
plt.subplot(2, 5, 9), plt.imshow(prewitt_kernel_y, cmap='gray'), plt.title('prewitt_kernel_y'), plt.axis('off')
plt.subplot(1, 5, 5), plt.imshow(laplacian_kernel, cmap='gray'), plt.title('laplacian_kernel'), plt.axis('off')
plt.show()
二、项目实战:基于核函数的卷积操作(例如:高斯滤波)
高斯滤波是一种用于平滑图像、去除噪声的滤波方法,其本质是利用高斯核对图像进行卷积运算。实现高斯滤波的方法主要有以下三种:
def gaussian_kernel(size, sigma):
""" 生成高斯核 """
ax = np.linspace(-(size // 2), size // 2, size)
xx, yy = np.meshgrid(ax, ax)
kernel = np.exp(-(xx**2 + yy**2) / (2 * sigma**2))
return kernel / np.sum(kernel) # 归一化
def convolve(image, kernel):
""" 手动实现 2D 卷积 """
h, w = image.shape
kh, kw = kernel.shape
pad_h, pad_w = kh // 2, kw // 2
# 填充图像
padded_image = np.pad(image, ((pad_h, pad_h), (pad_w, pad_w)), mode='constant', constant_values=0)
output = np.zeros_like(image)
# 逐像素卷积
for i in range(h):
for j in range(w):
region = padded_image[i:i+kh, j:j+kw] # 取区域
output[i, j] = np.sum(region * kernel) # 计算卷积
return output
if __name__ == '__main__':
import cv2
import numpy as np
img = cv2.imread('YH220_235.png', cv2.IMREAD_GRAYSCALE)
img = img[150:300, 150:300]
gaussian_blur = cv2.GaussianBlur(img, (5, 5), 1)
print(gaussian_blur[0:5, 0:5])
##################################################################################
gaussian_kernel_1d = cv2.getGaussianKernel(5, 1) # 1D 高斯核
gaussian_kernel_2d = gaussian_kernel_1d @ gaussian_kernel_1d.T # 生成 2D 高斯核
gaussian_blur_filter2D = cv2.filter2D(img, -1, gaussian_kernel_2d)
print(gaussian_blur_filter2D[0:5, 0:5])
##################################################################################
gaussian_kernel = gaussian_kernel(5, 1)
# print(gaussian_kernel)
gaussian_blur_numpy = convolve(img, gaussian_kernel)
print(gaussian_blur_numpy[0:5, 0:5])
##################################################################################
import matplotlib.pyplot as plt
plt.subplot(1, 4, 1), plt.imshow(img, cmap='gray'), plt.title('Original'), plt.axis('off')
plt.subplot(1, 4, 2), plt.imshow(gaussian_blur, cmap='gray'), plt.title('cv2.GaussianBlur'), plt.axis('off')
plt.subplot(1, 4, 3), plt.imshow(gaussian_blur_filter2D, cmap='gray'), plt.title('cv2.filter2D'), plt.axis('off')
plt.subplot(1, 4, 4), plt.imshow(gaussian_blur_numpy, cmap='gray'), plt.title('convolve'), plt.axis('off')
plt.show()
"""
# 像素值范围不一致
# cv2.GaussianBlur() 和 cv2.filter2D() 经过优化
# convolve() 手写卷积的核函数值范围、边界填充方式、数值计算上有所不同
[[128 144 168 171 158]
[140 154 174 175 161]
[160 170 184 179 161]
[170 176 183 174 153]
[157 160 165 157 139]]
[[129 144 168 171 159]
[140 154 174 175 161]
[160 170 184 179 161]
[170 176 183 174 153]
[157 160 165 157 139]]
[[ 55 91 113 117 109]
[ 86 137 164 164 151]
[107 160 183 178 161]
[116 166 183 174 153]
[111 151 164 156 139]]
"""
1.1、OpenCV 内置函数
OpenCV 提供了 cv2.GaussianBlur() 直接进行高斯滤波,避免手动构造高斯核。
import cv2
# 读取灰度图像
img = cv2.imread('YH220_235.png', cv2.IMREAD_GRAYSCALE)
img = img[150:300, 150:300]
# 使用 OpenCV 进行高斯滤波 (核大小 5x5, 标准差 1)
gaussian_blur = cv2.GaussianBlur(img, (5, 5), 1)
# 显示结果
import matplotlib.pyplot as plt
plt.subplot(1, 2, 1), plt.imshow(img, cmap='gray'), plt.title('Original'), plt.axis('off')
plt.subplot(1, 2, 2), plt.imshow(gaussian_blur, cmap='gray'), plt.title('Gaussian Blur'), plt.axis('off')
plt.show()
1.2、自定义核函数 + cv2.filter2D()
import cv2
# 读取灰度图像
img = cv2.imread('YH220_235.png', cv2.IMREAD_GRAYSCALE)
img = img[150:300, 150:300]
# 生成 5x5 高斯核(sigma = 1)
gaussian_kernel_1d = cv2.getGaussianKernel(5, 1) # 1D 高斯核
gaussian_kernel_2d = gaussian_kernel_1d @ gaussian_kernel_1d.T # 生成 2D 高斯核
# 使用 filter2D 进行高斯滤波
gaussian_blur = cv2.filter2D(img, -1, gaussian_kernel_2d)
# 显示结果
import matplotlib.pyplot as plt
plt.subplot(1, 2, 1), plt.imshow(img, cmap='gray'), plt.title('Original'), plt.axis('off')
plt.subplot(1, 2, 2), plt.imshow(gaussian_blur, cmap='gray'), plt.title('Gaussian Blur'), plt.axis('off')
plt.show()
1.3、自定义核函数 + NumPy手写卷积
def gaussian_kernel(size, sigma):
""" 生成高斯核 """
ax = np.linspace(-(size // 2), size // 2, size)
xx, yy = np.meshgrid(ax, ax)
kernel = np.exp(-(xx**2 + yy**2) / (2 * sigma**2))
return kernel / np.sum(kernel) # 归一化
def convolve(image, kernel):
""" 手动实现 2D 卷积 """
h, w = image.shape
kh, kw = kernel.shape
pad_h, pad_w = kh // 2, kw // 2
# 填充图像
padded_image = np.pad(image, ((pad_h, pad_h), (pad_w, pad_w)), mode='constant', constant_values=0)
output = np.zeros_like(image)
# 逐像素卷积
for i in range(h):
for j in range(w):
region = padded_image[i:i+kh, j:j+kw] # 取区域
output[i, j] = np.sum(region * kernel) # 计算卷积
return output
if __name__ == '__main__':
import cv2
import numpy as np
# 读取灰度图像
img = cv2.imread('YH220_235.png', cv2.IMREAD_GRAYSCALE)
img = img[150:300, 150:300]
# 生成 5x5 高斯核(sigma = 1)
gaussian_kernel = gaussian_kernel(5, 1)
print(gaussian_kernel)
# gaussian_kernel = np.array([[1, 2, 1],
# [2, 4, 2],
# [1, 2, 1]], dtype=np.float32) / 16
# 进行手动卷积
gaussian_blur = convolve(img, gaussian_kernel)
# 显示结果
import matplotlib.pyplot as plt
plt.subplot(1, 2, 1), plt.imshow(img, cmap='gray'), plt.title('Original'), plt.axis('off')
plt.subplot(1, 2, 2), plt.imshow(gaussian_blur, cmap='gray'), plt.title('Gaussian Blur'), plt.axis('off')
plt.show()