55. 可分离卷积核

灰度变换与直方图索引

一、滤波器

  • 空间滤波器是由邻域和定义的操作构成的,滤波器规定了滤波时采用的邻域形状及该区域内像素值的处理方法。
    滤波器也被称为 “核”、“模板”、“窗口”、“掩模”、“算子”,一般在信号处理中称为 “滤波器”,在数学领域称为 “核”。
    线性滤波器就是指基于线性核的滤波,也就是卷积运算。

二、可分离卷积核

  • 如果卷积核 w 可以被分解为两个或多个较小尺寸卷积核 w1、w2…,即:w = w 1 ★ w 2 ,则成为可分离卷积核。

  • 秩为 1 的矩阵可以分解为一个列向量与一个行向量的乘积,因此秩为 1 的卷积核是可分离卷积核。

  • 可分离卷积核 w 与图像 f 的卷积(same 卷积),等于先用 f 与 w1 卷积,再用 w2 对结果进行卷积:


  • 随着图像尺寸与卷积核尺寸的增大,用分离的卷积核依次对图像进行卷积操作,可以有效地提高运算速度。
    因此,在二维图像处理中,经常将一个可分离卷积核分解为一维水平核 kernalX 和一维垂直核 kernalY 的乘积。

三、函数

  • 函数 sepFilter2D 实现可分离核(模板)对图像进行线性滤波。

cv.sepFilter2D( src, ddepth, kernelX, kernelY[, dst[, anchor[, delta[, borderType]]]]) → dst # OpenCV4

该函数先用一维水平核 kernalX 对图像的行进行滤波,再用一维垂直核 kernalY 对图像的列进行滤波。

  • src:卷积处理的输入图像,可以是灰度图像,也可以是多通道的彩色图像
  • dst:卷积处理的输出图像,大小和类型与 src 相同
  • ddepth:目标图像每个通道的深度(数据类型),ddepth=-1 表示与输入图像的数据类型相同
  • kernelX:水平卷积核向量,一维实型数组
  • kernelY:垂直卷积核向量,一维实型数组
  • anchor:卷积核的锚点位置,默认值 (-1, -1) 表示以卷积核的中心为锚点
  • delta:输出图像的偏移量,可选项,默认值为 0
  • borderType:边界扩充的类型

四、例程

  • 1.68:可分离核的卷积操作
import numpy as np
# 1.68:可分离核的卷积操作
imgList = list(range(0, 36))
imgTest = np.array(imgList).reshape(6, 6)

# 可分离卷积核: kernXY = kernX * kernY
kernX = np.array([[-1, 3, -1]], np.float32)  # (1,3)
kernY = np.transpose(kernX)  # (3,1)
kernXY = kernX * kernY
print(kernX.shape, kernY.shape, kernXY.shape)

from scipy import signal
# 二维卷积核直接对图像进行卷积操作
imgConv_XY = signal.convolve2d(imgTest, kernXY, mode='same', boundary='fill')
# 可分离卷积核分解为一维水平核 kernalX 和一维垂直核 kernalY 分别进行卷积操作
imgConv_X = signal.convolve2d(imgTest, kernX, mode='same', boundary='fill')
imgConv_X_Y = signal.convolve2d(imgConv_X, kernY, mode='same', boundary='fill')

print("\n比较 imgConv_XY 与 imgConv_X_Y 是否相等:\t", (imgConv_XY == imgConv_X_Y).all())
print("\nimgConv_kernXY:\n", imgConv_XY)
print("\nimgConv_kernX_kernY:\n", imgConv_X_Y)

运行结果
  • 1.69:可分离核的图像卷积
import cv2
import numpy as np
from matplotlib import pyplot as plt

# 1.69:可分离核的图像卷积
img = cv2.imread(r"e:/opencv/bgra.png", flags=1) 

# 可分离卷积核: kernXY = kernX * kernY
kernX = np.array([[-1, 3, -1]], np.float32)  # (1,3)
kernY = np.transpose(kernX)  # (3,1)
kernXY = kernX * kernY

# (1) 可分离卷积核分解为一维水平核 kernalX 和一维垂直核 kernalY 分步进行卷积操作
imgConvY = cv2.filter2D(img, -1, kernY,
   anchor=(0,0), borderType=cv2.BORDER_CONSTANT)
imgConv_X_Y = cv2.filter2D(imgConvY, -1, kernX,
   anchor=(0,0), borderType=cv2.BORDER_CONSTANT)
# (2) 二维卷积核 kernXY 直接对图像进行卷积操作
imgConv_XY = cv2.filter2D(img, -1, kernXY,
anchor=(0, 0), borderType=cv2.BORDER_CONSTANT)
# (3) 一维水平核 kernalX 和一维垂直核 kernalY 进行可分离卷积核的卷积操作
imgConvSep_XY = cv2.sepFilter2D(img, -1, kernX, kernY,
anchor=(0,0), borderType=cv2.BORDER_CONSTANT)

print("\n比较 imgConv_XY 与 imgConv_X_Y 是否相等:\t", (imgConv_XY == imgConv_X_Y).all())
print("\n比较 imgConvSep_XY 与 imgConv_XY 是否相等:\t", (imgConvSep_XY == imgConv_XY).all())

plt.figure(figsize=(9, 6))
plt.subplot(131), plt.axis('off'), plt.title('cv2.filter2D(kernXY)')
plt.imshow(cv2.cvtColor(imgConv_XY, cv2.COLOR_BGR2RGB))
plt.subplot(132), plt.axis('off'), plt.title('cv2.filter2D (kernX->kernY)')
plt.imshow(cv2.cvtColor(imgConv_X_Y, cv2.COLOR_BGR2RGB))
plt.subplot(133), plt.axis('off'), plt.title('cv2.sepFilter2D(kernX,kernY)')
plt.imshow(cv2.cvtColor(imgConvSep_XY, cv2.COLOR_BGR2RGB))
plt.tight_layout()
plt.show()

五、资料

youcans_的博客:
https://blog.csdn.net/youcans/article/details/121848350
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容