卷积的意义及其应用
卷积的定义
我们将形如
∫ − ∞ ∞ f ( τ ) g ( x − τ ) d τ \int^\infty_{-\infty} f(τ)g(x-τ)dτ ∫−∞∞f(τ)g(x−τ)dτ
的式子称之为f(x)与g(x)的卷积记为
h ( x ) = ( f ∗ g ) ( x ) h(x) = (f * g)(x) h(x)=(f∗g)(x)
我们可以将它转化成离散形式的式子,like:
∑ i = − ∞ ∞ x ( i ) h ( n − i ) \sum^\infty_{i=-\infty}x(i)h(n-i) i=−∞∑∞x(i)h(n−i)
这是一个很明显的将一个序列倒置,然后相乘的操作。我们就用如此的思想来引入我们的第一种引用——联合概率分布
卷积的应用——联合概率分布
我们想象两颗骰子,当我们掷出它们的时候对于每个骰子的六个面,有如下概率序列
[ 1 6 , 1 6 , 1 6 , 1 6 , 1 6 , 1 6 ] [\frac{1}{6}, \frac{1}{6}, \frac{1}{6}, \frac{1}{6}, \frac{1}{6}, \frac{1}{6}] [61,61,61,61,61,61]
它们的序号计数从1开始
两个骰子的点数概率序列我们分别命名为
P ( x ) , Q ( x ) P(x), Q(x) P(x),Q(x)
那么之前的离散型卷积我们可以选择一个位置写成如下形式,并且根据实际情况调节上下界,式子如
h ( 4 ) = ∑ i = 1 3 P ( i ) Q ( 4 − i ) h(4) = \sum^{3}_{i=1}P(i)Q(4-i) h(4)=i=1∑3P(i)Q(4−i)
这个描述的是两颗骰子投出4点的概率。
现在我们假设存在两个概率密度函数,定义域为x∈R,那么
∫ − ∞ ∞ f ( τ ) g ( x − τ ) d τ \int^\infty_{-\infty} f(τ)g(x-τ)dτ ∫−∞∞f(τ)g(x−τ)dτ
这个式子就可以很清晰的表示他俩的联合分布的密度函数了。
我么可以用python代码实现它
import numpy as npdef dice_probability(num_dice):# 构建骰子的点数概率分布dice = np.ones(6) / 6# 迭代卷积运算result = dicefor _ in range(num_dice - 1):result = np.convolve(result, dice)return result# 输入两个骰子进行卷积计算
num_dice = 2
probabilities = dice_probability(num_dice)# 打印点数概率分布序列
for i, p in enumerate(probabilities, num_dice):print(f"点数 {i}: 概率 {p:.4f}")
卷积的应用——信号处理
卷积还有另一个重要的作用,那就是信号处理。
我们假设存在一个线性信号系统,在其中有冲击函数f(t)和一个响应函数g(t)。
这个时候我们再去观察
∫ − ∞ ∞ f ( τ ) g ( x − τ ) d τ \int^\infty_{-\infty} f(τ)g(x-τ)dτ ∫−∞∞f(τ)g(x−τ)dτ
我们不难知道其中的g(x-τ)其实是在x时,τ时接受的冲击的响应余留多少
我们知晓这个观点,那我们就可以写一个简单的python程序来计算这个冲击函数对应的真正的响应函数,(之前的g(t)其实是对于单位冲击而言的),代码如下
import numpy as np
import matplotlib.pyplot as pltdef continuous_convolution(signal_1, signal_2, dt):conv = np.convolve(signal_1, signal_2) * dtt = np.arange(0, (len(signal_1) + len(signal_2) - 1) * dt, dt)return t, conv# 定义输入信号的冲击函数和单位冲击响应函数
t_impulse = np.arange(-5, 5, 0.01)
impulse = np.zeros_like(t_impulse)
impulse[np.abs(t_impulse) < 0.001] = 1t_response = np.arange(0, 10, 0.01)
response = np.exp(-t_response)# 进行连续卷积计算
t_total, total_response = continuous_convolution(impulse, response, 0.01)# 裁剪信号长度以匹配卷积结果
total_response = total_response[:len(t_total)]# 创建一个包含三个子图的图形窗口
fig, axs = plt.subplots(1, 3, figsize=(12, 4))# 绘制冲击函数的图像
axs[0].plot(t_impulse, impulse)
axs[0].set_xlabel('Time')
axs[0].set_ylabel('Amplitude')
axs[0].set_title('Impulse Function')# 绘制单位冲击响应函数的图像
axs[1].plot(t_response, response)
axs[1].set_xlabel('Time')
axs[1].set_ylabel('Amplitude')
axs[1].set_title('Unit Impulse Response')# 绘制总响应函数的图像
axs[2].plot(t_total[:-1], total_response)
axs[2].set_xlabel('Time')
axs[2].set_ylabel('Amplitude')
axs[2].set_title('Total Response')# 调整子图之间的间距
plt.tight_layout()# 展示图像
plt.show()
结果如下
卷积为我们忠实的展现了其在线性信号系统响应模拟上的能力
卷积的应用——图像处理
我们终于循序渐进的到了这一步,卷积——>卷积核。熟悉CNN网络的同学一定对这个词并不陌生,至于为什么把这个放到信号处理/概率后面来讲,因为卷积核实际上就是一个滤波器!!!!是对图像像素矩阵的滤波器!!!,每一次的更新迭代卷积核里的参数,是为了更方便的提取特征,换句话说,卷积核里的值,其实就是对每个像素点可能对这个问题提供贡献的概率的概率分布,每次迭代是迭代它的权重,我甚至可以将这个分布按我所想进行设计,比如说我要我可以将一个图片迅速的转化成速写
代码如下
import numpy as np
from PIL import Image# 定义卷积操作函数
def convolve(image, kernel):image_height, image_width = image.shapekernel_height, kernel_width = kernel.shapeoutput = np.zeros((image_height, image_width))# 滑动窗口进行卷积操作for i in range(image_height - kernel_height + 1):for j in range(image_width - kernel_width + 1):window = image[i:i + kernel_height, j:j + kernel_width]output[i, j] = np.sum(window * kernel)return output# 定义速写风格的卷积核
sketch_kernel = np.array([[0, -1, 0],[-1, 5, -1],[0, -1, 0]])# 从外部读取图像
image_path = "OIP-C.jpg" # 替换为你的图像路径
image = Image.open(image_path).convert("L") # 使用convert("L")将彩色图像转为灰度图像# 将图像转为numpy数组
image_array = np.array(image)# 执行卷积操作
sketch_image = convolve(image_array, sketch_kernel)# 显示结果
image.show() # 显示原始图像
Image.fromarray(sketch_image).show() # 显示速写风格图像
下面的顺序为,原图,灰度化的原图,经卷积核的图
是不是要比灰度图更像铅笔画的呢,模糊的树丛也不模糊了?
这就是卷积核的作用,改变每个像素的权重参数,使其变成一个和卷积核的联合分布