【计算机视觉】三、图像处理——实验:图像去模糊和去噪、提取边缘特征

文章目录

  • [0. 实验环境](#0. 实验环境)
  • [1. 理论基础](#1. 理论基础)
    • [1.1 滤波器(卷积核)](#1.1 滤波器(卷积核))
    • [1.2 PyTorch:卷积操作](#1.2 PyTorch:卷积操作)
  • [2. 图像处理](#2. 图像处理)
    • [2.1 图像读取](#2.1 图像读取)
    • [2.2 查看通道](#2.2 查看通道)
    • [2.3 图像处理](#2.3 图像处理)
  • [3. 图像去模糊](#3. 图像去模糊)
  • [4. 图像去噪](#4. 图像去噪)
    • [4.1 添加随机噪点](#4.1 添加随机噪点)
    • [4.2 图像去噪](#4.2 图像去噪)

0. 实验环境

本实验使用了PyTorch深度学习框架,相关操作如下:

shell 复制代码
conda create -n DL python==3.11
shell 复制代码
conda activate DL
shell 复制代码
conda install pytorch torchvision torchaudio pytorch-cuda=12.1 -c pytorch -c nvidia
shell 复制代码
conda install matplotlib
shell 复制代码
conda install pillow numpy
软件包 本实验版本
matplotlib 3.8.0
numpy 1.26.3
pillow 10.0.1
python 3.11.0
torch 2.1.2
torchaudio 2.1.2
torchvision 0.16.2

1. 理论基础

二维卷积运算是信号处理和图像处理中常用的一种运算方式,当给定两个二维离散信号或图像 f ( x , y ) f(x, y) f(x,y) 和 g ( x , y ) g(x, y) g(x,y),其中 f ( x , y ) f(x, y) f(x,y) 表示输入信号或图像, g ( x , y ) g(x, y) g(x,y) 表示卷积核。二维卷积运算可以表示为: h ( x , y ) = ∑ m ∑ n f ( m , n ) ⋅ g ( x − m , y − n ) h(x, y) = \sum_{m}\sum_{n} f(m, n) \cdot g(x-m, y-n) h(x,y)=m∑n∑f(m,n)⋅g(x−m,y−n)其中 ∑ m ∑ n \sum_{m}\sum_{n} ∑m∑n 表示对所有 m , n m, n m,n 的求和, h ( x , y ) h(x, y) h(x,y) 表示卷积后的输出信号或图像。

在数学上,二维卷积运算可以理解为将输入信号或图像 f ( x , y ) f(x, y) f(x,y) 和卷积核 g ( x , y ) g(x, y) g(x,y) 进行对应位置的乘法 ,然后将所有乘积值相加得到输出信号或图像 h ( x , y ) h(x, y) h(x,y) 。这个过程可以用于实现一些信号处理和图像处理的操作,例如模糊、边缘检测、图像增强等。

详见:【深度学习】Pytorch 系列教程(七):PyTorch数据结构:2、张量的数学运算(5):二维卷积及其数学原理

1.1 滤波器(卷积核)

在图像处理中,卷积经常作为特征提取的有效方法.一幅图像在经过卷积操作后得到结果称为特征映射 (Feature Map)。图5.3给出在图像处理中几种常用的滤波器,以及其对应的特征映射.图中最上面的滤波器是常用的高斯滤波器 ,可以用来对图像进行平滑去噪 ;中间和最下面的滤波器可以用来提取边缘特征

python 复制代码
# 高斯滤波~平滑去噪
conv_kernel1 = torch.tensor([[1/16, 1/8, 1/16],
                            [1/8, 1/4, 1/8],
                            [1/16, 1/8, 1/16]], dtype=torch.float).unsqueeze(0).unsqueeze(0)
# 提取边缘特征
conv_kernel2 = torch.tensor([[0, 1, 0],
                            [1, -4, 1],
                            [0, 1, 0]], dtype=torch.float).unsqueeze(0).unsqueeze(0)
conv_kernel3 = torch.tensor([[0, 1, 1],
                            [-1, 0, 1],
                            [-1, -1, 0]], dtype=torch.float).unsqueeze(0).unsqueeze(0)
print(conv_kernel1.size())
  • 上述均为3x3的单通道卷积核,需要拓展为四维张量(PyTorch就是这么设计的~)

1.2 PyTorch:卷积操作

python 复制代码
def conv2d(img_tensor, conv_kernel):
    convolved_channels = []
    for i in range(3):
        channel_input = img_tensor[:, i, :, :]  # 取出每个通道的输入
        convolved = F.conv2d(channel_input, conv_kernel, padding=1)  
        convolved_channels.append(convolved)

    # 合并各通道卷积后的结果
    output = torch.cat(convolved_channels, dim=1)
    # 将张量转换为NumPy数组,进而转换为图像
    output_img = output.squeeze().permute(1, 2, 0).numpy().astype(np.uint8)
    output_img = Image.fromarray(output_img)
    return output_img

2. 图像处理

2.1 图像读取

python 复制代码
img = Image.open('1.jpg')  
# img = img.resize((128, 128))  # 调整图像大小

img_tensor = torch.tensor(np.array(img), dtype=torch.float).permute(2, 0, 1).unsqueeze(0)

print(img_tensor.shape)
  • 将图像转换为PyTorch张量:将通道顺序从HWC转换为CHW,并在第一个维度上增加一个维度~卷积操作使用四维张量

2.2 查看通道

本部分内容纯属没事儿闲的~

python 复制代码
img = Image.open('1.jpg')  
img_tensor = torch.tensor(np.array(img), dtype=torch.float).permute(2, 0, 1).unsqueeze(0)
channel1 = img_tensor[:, 0, :, :]  # 提取每个通道
channel2 = img_tensor[:, 1, :, :] 
channel3 = img_tensor[:, 2, :, :]  
plt.figure(figsize=(12, 12)) 
plt.subplot(1, 4, 1)
plt.imshow(img)
plt.axis('off')
plt.subplot(1, 4, 2)
channel1_img = channel1.squeeze().numpy().astype(np.uint8)
channel1_img = Image.fromarray(channel1_img)
plt.imshow(channel1_img)
plt.axis('off')
plt.subplot(1, 4, 3)
channel2_img = channel2.squeeze().numpy().astype(np.uint8)
channel2_img = Image.fromarray(channel2_img)
plt.imshow(channel2_img)
plt.axis('off')
plt.subplot(1, 4, 4)
channel3_img = channel3.squeeze().numpy().astype(np.uint8)
channel3_img = Image.fromarray(channel3_img)
plt.imshow(channel3_img)
plt.axis('off')

2.3 图像处理

python 复制代码
def plot_img(img_tensor): 
    output_img1 = conv2d(img_tensor, conv_kernel1)
    output_img2 = conv2d(img_tensor, conv_kernel2)
    output_img3 = conv2d(img_tensor, conv_kernel3)
    
    plt.subplot(2, 2, 1)
    plt.title('原始图像', fontproperties=font)
    plt.imshow(img)
    plt.axis('off')  
    plt.subplot(2, 2, 2)
    plt.title('平滑去噪', fontproperties=font)
    plt.imshow(output_img1)
    plt.axis('off')  
    plt.subplot(2, 2, 3)
    plt.imshow(output_img2)
    plt.title('边缘特征1', fontproperties=font)  
    plt.axis('off')  
    plt.subplot(2, 2, 4)
    plt.imshow(output_img3)
    plt.title('边缘特征2', fontproperties=font)  
    plt.axis('off')  
    plt.show()
python 复制代码
font = FontProperties(fname='C:\Windows\Fonts\simkai.ttf', size=16)  # 使用楷体
plt.figure(figsize=(12, 12))  # 设置图大小12*12英寸
plot_img(img_tensor)  
  • 如图所示,图像提取边缘特征效果明显
  • 但图片过于高清,plt输出的(12英寸)原始图像、平滑去噪图像都很模糊~,下面会先降低像素,然后进行去模糊去噪实验
  • 原图为

3. 图像去模糊

python 复制代码
img = Image.open('2.jpg')  
img = img.resize((480, 480))  # 调小图像~先使原图变模糊
img_tensor = torch.tensor(np.array(img), dtype=torch.float).permute(2, 0, 1).unsqueeze(0)
conv_kernel4 = torch.tensor([[0, 0, 0],
                            [0, 2, 0],
                            [0, 0, 0]], dtype=torch.float).unsqueeze(0).unsqueeze(0)
conv_kernel5 = torch.ones(3, 3).unsqueeze(0).unsqueeze(0)/9
# print(conv_kernel4-conv_kernel5)
font = FontProperties(fname='C:\Windows\Fonts\simkai.ttf', size=32) 
plt.figure(figsize=(32, 32))  
plt.subplot(2, 2, 1)
plt.title('原始图像', fontproperties=font)
plt.imshow(img)
plt.axis('off')  
plt.subplot(2, 2, 2)
plt.title('线性滤波-2', fontproperties=font)
plt.imshow(conv2d(img_tensor, conv_kernel4))
plt.axis('off')  
plt.subplot(2, 2, 3)
plt.imshow(conv2d(img_tensor, conv_kernel5))
plt.title('均值滤波器:模糊', fontproperties=font)  
plt.axis('off')  
plt.subplot(2, 2, 4)
plt.imshow(conv2d(img_tensor, conv_kernel4-conv_kernel5))
plt.title('锐化滤波器:强调局部差异', fontproperties=font)  
plt.axis('off')  
plt.show()

4. 图像去噪

4.1 添加随机噪点

python 复制代码
img = Image.open('1.jpg')  
img = img.resize((640, 640))  # 调小图像~先使原图变模糊
img_tensor = torch.tensor(np.array(img), dtype=torch.float).permute(2, 0, 1).unsqueeze(0)


noise = torch.randn_like(img_tensor)    # 与图像相同大小的随机标准正态分布噪点
noisy_img_tensor = img_tensor + noise   # 将噪点叠加到图像上
noisy_img = noisy_img_tensor.squeeze(0).permute(1, 2, 0).to(dtype=torch.uint8)
noisy_img = Image.fromarray(noisy_img.numpy())

4.2 图像去噪

python 复制代码
# conv_kernel1 = torch.tensor([[1/16, 1/8, 1/16],
#                             [1/8, 1/4, 1/8],
#                             [1/16, 1/8, 1/16]], dtype=torch.float).unsqueeze(0).unsqueeze(0)
# # 生成随机3x3高斯分布
# random_gaussian = torch.randn(3, 3).unsqueeze(0).unsqueeze(0)
# print(random_gaussian)
font = FontProperties(fname='C:\Windows\Fonts\simkai.ttf', size=32)  # 使用楷体
plt.figure(figsize=(32, 32))  
plt.subplot(1, 3, 1)
plt.title('原始图像', fontproperties=font)
plt.imshow(img)
plt.axis('off')  
plt.subplot(1, 3, 2)
plt.title('噪点图像', fontproperties=font)
plt.imshow(noisy_img)
plt.axis('off')  
plt.subplot(1, 3, 3)
plt.title('去噪图像', fontproperties=font)
plt.imshow(conv2d(noisy_img_tensor, conv_kernel1))
plt.axis('off') 
plt.show()
相关推荐
赛丽曼12 分钟前
Python中的TCP
python
小白~小黑13 分钟前
软件测试基础二十(接口测试 Postman)
python·自动化·postman
codists13 分钟前
《Django 5 By Example》阅读笔记:p76-p104
python·django·编程人
欧阳枫落21 分钟前
python 2小时学会八股文-数据结构
开发语言·数据结构·python
天天要nx25 分钟前
D64【python 接口自动化学习】- python基础之数据库
数据库·python
Mr.简锋29 分钟前
opencv常用api
人工智能·opencv·计算机视觉
liyuanbhu33 分钟前
Halcon HImage 与 Qt QImage 的相互转换(修订版)
qt·计算机视觉·halcon
可均可可1 小时前
C++之OpenCV入门到提高005:005 图像操作
c++·图像处理·opencv·图像操作
feifeikon1 小时前
Python Day5 进阶语法(列表表达式/三元/断言/with-as/异常捕获/字符串方法/lambda函数
开发语言·python
杰仔正在努力2 小时前
python成长技能之枚举类
开发语言·python