二维卷积定理的验证(上)

二维卷积定理的验证(上)

0. 写在前面

在进行图像处理时,我们经常会用到卷积计算,但是当卷积核较大时,卷积计算将相当耗时。

事实上,可以通过卷积定理,来使用傅里叶变换手段实现卷积计算。也即是卷积定理。

即本文要探讨和验证的内容。

1. 二维卷积定理

卷积定理是傅里叶变换满足的一个重要性质。函数卷积的傅里叶变换是函数傅里叶变换的乘积。本文验证二维卷积定理,用于处理图像。

图像的二维卷积定理表达式如下
F ( f ( x , y ) ∗ g ( x , y ) ) = F ( f ( x , y ) ) ⋅ F ( g ( x , y ) ) F(f(x,y)*g(x,y)) = F(f(x,y))·F(g(x,y)) F(f(x,y)g(x,y))=F(f(x,y))F(g(x,y))
其中, F F F 表示傅里叶变换操作, ∗ * 表示卷积操作。

式(1)中的两侧结果皆为复数,不利于展现,因此将上述等式变换如下
f ( x , y ) ∗ g ( x , y ) = F − 1 [ F ( f ( x , y ) ) ⋅ F ( g ( x , y ) ) ] f(x,y)*g(x,y) = F^{-1}[F(f(x,y))·F(g(x,y))] f(x,y)g(x,y)=F1[F(f(x,y))F(g(x,y))]
此时,等式左侧和右侧结果皆可以用图像来展现。

本文的目标是验证二维卷积定理,即验证等式(2)成立

2. 名词说明

2.1 卷积

根据 padding 的类型,可以将卷积分为

  • ‘full‘。滑动步长为 1,图片尺寸大小为 w × h w\times h w×h ,卷积核尺寸大小为 m × n m\times n m×n,卷积后图像大小为 ( w + m − 1 ) × ( h + n − 1 ) (w+m-1)\times (h+n-1) (w+m1)×(h+n1)

  • ’same’。滑动步长为 1,图片尺寸大小为 w × h w\times h w×h,卷积核尺寸大小为 m × n m\times n m×n,卷积后图像大小为 w × h w\times h w×h

  • ‘valid’。滑动步长为 s s s,图片尺寸大小为 w × h w\times h w×h,卷积核尺寸大小为 m × n m\times n m×n,卷积后图像大小为 ( w − m s + 1 ) × ( h − n s + 1 ) (\frac{w-m}{s}+1)\times (\frac{h-n}{s}+1) (swm+1)×(shn+1)

卷积的具体实现步骤为:

  1. 对图片进行 padding 操作。通常是根据选择的卷积类型进行补零操作,即在第一行之前和最后一行之后、第一列之前和最后一列之后进行补零,以满足卷积的尺寸要求。
  2. 将卷积核绕其中心旋转180度。
  3. 在图像上滑动旋转后的卷积核,卷积核与图像进行逐项乘积求和,最终得到全图的卷积结果。

2.2 傅里叶变换与反变换

需要注意的是,因为图像的大小为 w × h w\times h w×h ,而卷积核的大小为 m × n m\times n m×n。 因此在进行傅里叶变换操作时,需要将两者大小统一,且跟前述卷积结果的图片尺寸大小相统一时,最终结果才有可能是相等的。

举例说明:

如果图片大小为 w × h w\times h w×h , 卷积核大小为 m × n m\times n m×n

对于等式左侧,进行卷积时,采用 “full” 方式,则卷积后 f ( x , y ) ∗ g ( x , y ) f(x,y)*g(x,y) f(x,y)g(x,y) 的结果尺寸大小即为 ( w + m − 1 ) × ( h + n − 1 ) (w+m-1)\times (h+n-1) (w+m1)×(h+n1);因此,对于等式右侧,在进行傅里叶变换前,就需要对图像和卷积核进行补零填充操作,以使得其最终结果尺寸也为 ( w + m − 1 ) × ( h + n − 1 ) (w+m-1)\times (h+n-1) (w+m1)×(h+n1)

3. 验证实现

3.1 使用 ”full“ 卷积

代码如下

import numpy as np
from scipy import signal

# 原始图像 f(x)
gray = np.uint16(np.random.randint(100, size=(7,7)))

# 卷积核 g(x)
kenel = np.ones((3,3))/9

# ----- Conv = f(x)*g(x) ----- #
# f(x)*g(x)
Conv = signal.convolve2d(gray, kenel, mode='full') # 使用full卷积类型,得到(M+N-1)X(M+N-1)大小


#--------- ifft{ F(f(x))·F(g(x)) } ---------#
# 傅里叶变换前进行 padding 填充,图像和卷积核都补零到 (M+N-1)x(M+N-1)大小。
img_pad = np.pad(gray, ((1, 1),(1, 1)), 'constant')
kenel_pad = np.pad(kenel, ((3, 3),(3, 3)), 'constant')

# F(f(x))
img_fft = np.fft.fftshift(np.fft.fft2(img_pad))

# F(g(x))
kenel_fft = np.fft.fftshift(np.fft.fft2(kenel_pad))

# ifft( F(f(x))·F(g(x)) )
FFT = np.fft.ifftshift(np.fft.ifft2(np.fft.fftshift(img_fft*kenel_fft)))



#--------- 打印结果 ---------#
print(" f(x) ↓")
print(gray)
print(" g(x) ↓")
print(kenel)

print("\n\n f(x)*g(x) ↓")
print(np.uint8(Conv))

print("\n ifft[F·G] ↓")
print(np.uint8(np.abs(FFT)))

结果如下

在这里插入图片描述

从(c)和(d)的数值结果可以看出,两者结果完全一致,也即 f ( x ) ∗ g ( x ) = i f f t ( F ⋅ G ) f(x)*g(x)=ifft(F·G) f(x)g(x)=ifft(FG) 。二维卷积定理成立。

3.2 使用“same”卷积

代码如下

import numpy as np
from scipy import signal

# 原始图像 f(x)
gray = np.uint16(np.random.randint(100, size=(7,7)))

# 卷积核 g(x)
kenel = np.ones((3,3))/9

# ----- Conv = f(x)*g(x) ----- #
# f(x)*g(x)
Conv = signal.convolve2d(gray, kenel, mode='same') # 使用full卷积类型,得到(M+N-1)X(M+N-1)大小


#--------- ifft{ F(f(x))·F(g(x)) } ---------#
# 傅里叶变换前进行 padding 填充,图像和卷积核都补零到 (M+N-1)x(M+N-1)大小。
img_pad = np.pad(gray, ((0, 0),(0, 0)), 'constant')
kenel_pad = np.pad(kenel, ((2, 2),(2, 2)), 'constant')

# F(f(x))
img_fft = np.fft.fftshift(np.fft.fft2(img_pad))

# F(g(x))
kenel_fft = np.fft.fftshift(np.fft.fft2(kenel_pad))

# ifft( F(f(x))·F(g(x)) )
FFT = np.fft.ifftshift(np.fft.ifft2(np.fft.fftshift(img_fft*kenel_fft)))



#--------- 打印结果 ---------#
print(" f(x) ↓")
print(gray)
print(" g(x) ↓")
print(kenel)

print("\n\n f(x)*g(x) ↓")
print(np.uint8(Conv))

print("\n ifft[F·G] ↓")
print(np.uint8(np.abs(FFT)))

结果如下

在这里插入图片描述

根据(c)和(d)的数值结果,在橘色方框内两者保持完全一致,而框外由于受到傅里叶变换时补零的影响,所以数值会出现不同的情况。

4. 结论

从上述实验中,可以看出:

  • padding 使用 “full” 方式时,等式左右两侧矩阵数值完全一致。但该种方式缺点是卷积图像结果矩阵尺寸发生改变。
  • padding 使用 “same” 方式时,等式左右两侧矩阵在一定范围内完全一致。但该种方式缺点是卷积图像结果中有部分不与傅里叶方式计算下等价。

但我们可以得到一个结论是,padding 的方式影响着最终结果

于是就发现了一个新的问题:即是否存在着某种边界处理方式,使得卷积图像结果矩阵尺寸没有变化,且所有值都可以与傅里叶方式计算下等价。

事实上,是存在的,因为 cv2.filter2D() 便是解决这一问题进而实现的。

至于,如何设置 padding 方式来解决这一问题,也即是下一篇博文的内容二维卷积定理的验证(下,cv2.filter2D())

<think>好的,我现在需要帮助用户理解图像处理中的二维卷积概念和实现方法。用户已经提供了一些参考资料,我需要结合这些资料来组织回答。 首先,我要明确二维卷积的定义。二维卷积是一种在图像处理中常用的操作,主要用于滤波、特征提取等。根据引用[1],conv2()函数在MATLAB中用于二维卷积,这说明不同工具有不同的实现方式,但核心概念一致。 接下来,我应该解释二维卷积的基本原理。用户可能想知道卷积核如何与图像相互作用。比如,卷积核在图像上滑动,进行乘积累加操作。这部分需要详细说明,可能涉及到数学表达式。根据系统指令,行内数学表达式要用$...$格式,例如$I'(i,j) = \sum_{m}\sum_{n} K(m,n) \cdot I(i-m, j-n)$,这里需要确保语法正确。 然后,实现方法部分需要分步骤说明。用户提供的引用中有PythonOpenCV的例子。比如引用[2]提到使用signal.convolve2d,而引用[3]和[4]提到了OpenCV的函数和自定义实现。我需要将这些方法分类,可能分为手动实现、使用NumPy/SciPy以及OpenCV库三种方式。每个方法需要简要说明步骤,并给出代码示例,例如使用SciPy的示例代码。 此外,边界处理是一个重要点。引用[2]和[4]提到了不同的边界处理方式,比如'symm'和补零,需要解释这些处理方式的影响。比如边界填充会影响输出图像的尺寸,或者导致边缘信息丢失,这也是优化时需要注意的地方。 用户可能关心的性能问题也需要提及。例如,手动实现的效率较低,适合教学,而库函数优化更好,适合实际应用。引用[3]中的cv.filter2D可能使用了更高效的算法,如FFT加速,这点可以强调。 在注意事项部分,要提到卷积核设计的重要性,比如Sobel算子用于边缘检测,高斯核用于平滑。同时,边界处理的不同方式会影响结果,如same和valid模式的区别,以及填充策略的选择。 最后,生成相关问题需要考虑用户可能进一步的需求,比如数学原理、优化方法、不同工具的实现比较,以及实际应用案例。这些问题应该覆盖理论、实现细节和应用场景,帮助用户深入学习和解决问题。 需要确保整个回答结构清晰,分点明确,代码示例正确,并且引用标识自然添加在相关内容末尾。同时,按照系统指令,所有数学公式正确使用LaTeX格式,独立公式用$$...$$,如卷积数学定义可能需要单独成段。 现在检查是否有遗漏的部分,比如是否所有引用都正确使用,是否有代码示例的格式问题,以及是否涵盖了用户提供的所有参考资料中的关键点。确保回答准确且易于理解,帮助用户全面了解二维卷积的实现方法。</think>### 图像处理中的二维卷积实现方法 #### 一、二维卷积概念 二维卷积是图像处理中的核心操作,通过卷积核(滤波器)与图像局部区域的加权求和实现特定效果(如模糊、锐化、边缘检测)。数学定义为: $$ I'(i,j) = \sum_{m=-k}^{k} \sum_{n=-k}^{k} K(m,n) \cdot I(i-m, j-n) $$ 其中$K$为卷积核,$I$为输入图像,$I'$为输出图像[^1]。 #### 二、实现方法 1. **手动实现(基础原理)** - **步骤**: 1. 将图像和卷积核翻转(参考互相关与卷积的区别)[^3] 2. 滑动卷积核,逐像素计算局部区域的加权和 3. 处理边界时补充零或对称扩展(如`boundary='symm'`)[^2] - **代码片段**(Python示例): ```python def manual_conv2d(image, kernel): h, w = image.shape k_h, k_w = kernel.shape pad = (k_h//2, k_w//2) padded = np.pad(image, pad, mode='constant') output = np.zeros_like(image) for i in range(h): for j in range(w): output[i,j] = np.sum(padded[i:i+k_h, j:j+k_w] * kernel) return output ``` 2. **使用NumPy/SciPy库** - **SciPy函数**:`scipy.signal.convolve2d` ```python import scipy.signal grad = scipy.signal.convolve2d(image, kernel, boundary='symm', mode='same') ``` - `mode='same'`保证输出尺寸与输入相同[^2] 3. **OpenCV实现** - **函数**:`cv2.filter2D()` ```python import cv2 flipped_kernel = cv2.flip(kernel, -1) # 翻转卷积核(真卷积) result = cv2.filter2D(image, -1, flipped_kernel, borderType=cv2.BORDER_REFLECT) ``` - 默认实现互相关,需手动翻转核实现真卷积 #### 三、关键注意事项 1. **卷积核设计**:不同核实现不同效果(如Sobel算子检测边缘[^4]) 2. **边界处理策略**: - 补零(`BORDER_CONSTANT`) - 对称扩展(`BORDER_REFLECT`) - 影响边缘区域的计算精度 3. **性能优化**: - 小核直接计算,大核可使用FFT加速 - GPU加速(如使用CuPy库) #### 四、典型应用场景 - 边缘检测(Sobel、Prewitt算子) - 图像平滑(高斯滤波) - 特征提取(CNN中的卷积层)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值