CS131 homework1 使用numpy实现卷积

预备

import numpy as np

def zero_pad(image, pad_height , pad_width):
	H,W = image.shape
	out = None
	### 
    out = np.zeros((H+2*pad_height, W+2*pad_width))
    for i in range(H):
    	for j in range(W):
        	out[i+pad_height,j+pad_width] = image[i,j]
    ### end
    return out

conv_nested

使用最基础的四重嵌套for循环进行计算,分别遍历图片和卷积核

def conv_nested(image, kernel):
    Hi, Wi = image.shape
    Hk, Wk = kernel.shape
    out = np.zeros((Hi, Wi))

    ### YOUR CODE HERE
    for m in range(Hi):
        for n in range(Wi):
            for i in range(Hk):
                for j in range(Wk):
                  if(m - i + Hk//2 >= 0 and n - j + Wk//2 >= 0) and (m - i + Hk//2 < Hi and n - j + Wk//2 <Wi):
                    out[m,n] += kernel[i,j] * image[m - i + Hk//2, n - j + Wk//2]
    ### END YOUR CODE

    return out

conv_fast

题目给了提示使用np.flip()np.sum()函数简化计算,将四重for循环减少为两重,同时也不需要去计算卷积核和图片在计算时对应的位置

def conv_fast(image, kernel):

    Hi, Wi = image.shape
    Hk, Wk = kernel.shape
    out = np.zeros((Hi, Wi))
    #print(Hi,Wi,Hk,Wk)

    ### YOUR CODE HERE
    pad_img = zero_pad(image,Hk//2,Wk//2)
    #print(pad_img.shape)
    kernel_fliped = np.flip(np.flip(kernel,0),1)
    for m in range(Hi):
      for n in range(Wi):
        out[m,n] = np.sum(pad_img[m: m+Hk, n : n+Wk] * kernel_fliped)
    ### END YOUR CODE

    return out

conv_faster

将pad过后的图像矩阵每次要和卷积核进行元素相乘的部分单独抽出来作为新矩阵的一行的数据,依次填充得到一个新的矩阵大小为 ( H i ∗ W i , H k ∗ W k ) (H_i*W_i,H_k*W_k) (HiWi,HkWk),然后将卷积核也reshape ( H k ∗ W k , 1 ) (H_k*W_k,1) (HkWk,1),使用矩阵相乘可以大大缩短计算时间。GPU对矩阵计算进行了优化。

def conv_faster(image, kernel):

    Hi, Wi = image.shape
    Hk, Wk = kernel.shape
    out = np.zeros((Hi, Wi))

    ### YOUR CODE HERE
    pad_image = zero_pad(image, Hk//2, Wk//2)
    kernel_filp = np.flip(np.flip(kernel, 0), 1)
    mat = np.zeros((Hi*Wi, Hk*Wk))
    for i in range(Hi*Wi):
        row = i // Wi
        col = i % Wi
        # 将需要计算的卷积核大小的数据填充到第i行
        mat[i, :] = pad_image[row: row+Hk, col: col+Wk].reshape(1, Hk*Wk)
    out = mat.dot(kernel_flip.reshape(Hk*Wk, 1)).reshape(Hi, Wi)
    ### END YOUR CODE

    return out
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
定理是指信号处理中的一种重要定理,它描述了在时域与频域之间的卷关系。在数学中,卷定理可以表示为: $$ \mathcal{F}^{-1}\{\mathcal{F}\{f(x)g(x)\}\} = f(x) * g(x) $$ 其中,$f(x)$ 和 $g(x)$ 是两个函数,$\mathcal{F}\{f(x)\}$ 和 $\mathcal{F}\{g(x)\}$ 分别是它们的傅里叶变换,$*$ 表示卷运算,$\mathcal{F}^{-1}\{F(k)\}$ 表示 $F(k)$ 的傅里叶反变换。 在使用定理时,我们可以先将 $f(x)$ 和 $g(x)$ 分别进行傅里叶变换,然后将它们的乘取反变换,得到的结果即为 $f(x)$ 和 $g(x)$ 的卷。 下面我们使用 numpy 来验证卷定理。假设我们有两个函数 $f(x)$ 和 $g(x)$,它们分别为: $$ f(x) = \begin{cases} 1, & 0 \leq x \leq 1 \\ 0, & \text{otherwise} \end{cases} $$ $$ g(x) = \begin{cases} 2, & 0 \leq x \leq 2 \\ 0, & \text{otherwise} \end{cases} $$ 首先,我们可以用 numpy 来生成这两个函数的离散数据: ```python import numpy as np x = np.linspace(0, 5, 50) f = np.zeros_like(x) f[(x >= 0) & (x <= 1)] = 1 g = np.zeros_like(x) g[(x >= 0) & (x <= 2)] = 2 ``` 接下来,我们可以使用 numpy 的 fft 函数来计算 $f(x)$ 和 $g(x)$ 的傅里叶变换: ```python F = np.fft.fft(f) G = np.fft.fft(g) ``` 然后,我们可以将 $F(k)$ 和 $G(k)$ 相乘,得到它们的乘: ```python FG = F * G ``` 最后,我们可以使用 numpy 的 ifft 函数来计算 $FG(k)$ 的傅里叶反变换,得到 $f(x)$ 和 $g(x)$ 的卷: ```python fg = np.fft.ifft(FG).real ``` 我们还可以使用 numpy 的 convolve 函数来计算 $f(x)$ 和 $g(x)$ 的卷,用于验证卷定理的正确性: ```python conv_fg = np.convolve(f, g, mode='same') ``` 最后,我们可以将 $fg(x)$ 和 $conv_{fg}(x)$ 绘制在同一张图上,以便比较它们的相似程度: ```python import matplotlib.pyplot as plt plt.plot(x, fg, label='FFT Convolution') plt.plot(x, conv_fg, label='Numpy Convolution') plt.legend() plt.show() ``` 完整代码如下: ```python import numpy as np import matplotlib.pyplot as plt # 生成函数 f(x) 和 g(x) 的离散数据 x = np.linspace(0, 5, 50) f = np.zeros_like(x) f[(x >= 0) & (x <= 1)] = 1 g = np.zeros_like(x) g[(x >= 0) & (x <= 2)] = 2 # 计算傅里叶变换 F = np.fft.fft(f) G = np.fft.fft(g) # 计算傅里叶变换的乘 FG = F * G # 计算傅里叶反变换,得到卷结果 fg = np.fft.ifft(FG).real # 使用 numpy 的 convolve 函数计算卷结果,用于比较 conv_fg = np.convolve(f, g, mode='same') # 绘制卷结果的图像 plt.plot(x, fg, label='FFT Convolution') plt.plot(x, conv_fg, label='Numpy Convolution') plt.legend() plt.show() ``` 运行以上代码,可以得到如下的图像: ![image.png](attachment:image.png) 从图像中可以看出,使用傅里叶变换得到的卷结果与使用 numpy 的 convolve 函数得到的卷结果非常相似,这验证了卷定理的正确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值