DIP——添加运动模糊与滤波

news2024/12/17 8:48:00

1.运动模糊
为了模拟图像退化的过程,在这里创建了一个用于模拟运动模糊的点扩散函数,具体模糊的方向取决于输入的motion_angle。如果运动方向接近水平,则模糊效果近似水平,如果运动方向接近垂直,则模糊效果近似垂直。具体操作如下。首先创建二维数组PSF,并将其所有元素初始化为零,作为点扩散函数的初始值。之后计算图像的中心位置。然后,计算运动方向的斜率的正切值以及余切值。根据运动方向的斜率的正切值以及余切值去判断运动方向。如果斜率的正切值小于等于1,表示运动方向接近水平,所采取的操作是在点扩散函数的相应位置设置值为1,形成一条近似水平的模糊效果。这个相应位置的计算方式是中心加上偏移量。垂直方向同理。运动模糊这一块的代码具体如下。

def motion_process(image_size, motion_angle):
    # 创建一个大小为image_size的二维数组PSF,并将其所有元素初始化为零,作为点扩散函数的初始值。
    PSF = np.zeros(image_size)
    print(image_size)
    # 计算图像的中心位置,由于数组索引是从0开始的,所以需要减1。
    center_position = (image_size[0] - 1) / 2
    print(center_position)
    # 计算运动方向的斜率的正切值。这里的motion_angle是以度为单位的运动方向角度。
    slope_tan = math.tan(motion_angle * math.pi/ 180)
    # 计算斜率的余切值。
    slope_cot = 1/slope_tan
    # 如果斜率的正切值小于等于1,表示运动方向接近水平。
    if slope_tan <=1:
        for i in range(15):
            # 计算相对于中心位置的水平偏移。round函数用于将浮点数四舍五入为整数。
            offset = round(i * slope_tan) #((center_position-i)*slope_tan)
            # 在点扩散函数的相应位置设置值为1,形成一条近似水平的模糊效果。
            PSF [int (center_position + offset), int(center_position - offset)] = 1
        # 将点扩散函数进行归一化,确保其总和为1。
        return PSF/PSF.sum() #对点扩散函数进行归一化亮度
    # 如果斜率的正切值大于1,表示运动方向接近垂直。
    else:
        for i in range(15):
            # 计算相对于中心位置的垂直偏移。
            offset = round(i * slope_cot)
            # :在点扩散函数的相应位置设置值为1,形成一条近似垂直的模糊效果。
            PSF[int(center_position - offset),int(center_position + offset)] = 1
        #     将点扩散函数进行归一化,确保其总和为1。
        return PSF / PSF.sum()

之后,对点扩散函数(PSF)进行二维傅里叶变换。这里加上e是为了避免除零错误。之后 将输入图像的傅里叶变换与点扩散函数的傅里叶变换进行逐元素相乘,在将结果进行逆傅里叶变换,得到模糊处理后的图像。最后用fftshift将频谱移到图像中心,然后取绝对值,得到最终的模糊图像。
总结一下,第一步是为了得到点扩散函数,可以理解为一个模糊的模板,这一步,是在进行时域卷积,频域乘积,对输入图像和模糊模板进行卷积,得到输出。
得到模糊图像的代码如下。

def make_blurred(input, PSF, eps):
    # 对输入图像进行二维傅里叶变换。
    input_fft = fft.fft2(input)  # 进行二维数组的傅里叶变换
    # 对点扩散函数(PSF)进行二维傅里叶变换,并添加一个小的常数eps以避免除零错误。这是在频域进行卷积操作的准备步骤。
    PSF_fft = fft.fft2(PSF) + eps
    # input_fft * PSF_fft, 将输入图像的傅里叶变换与点扩散函数的傅里叶变换进行逐元素相乘,这相当于在时域中进行卷积。
    # 之后对相乘结果进行逆傅里叶变换,得到模糊处理后的图像。
    blurred = fft.ifft2(input_fft * PSF_fft)
    # 用fftshift将频谱移到图像中心,然后取绝对值,得到最终的模糊图像。
    blurred = np.abs(fft.fftshift(blurred))
    return blurred

2.逆滤波
对图像和点扩散函数(PSF)分别进行傅里叶变换,同时将将PSF的频域表示进行平移,将其中心移到图像中心。这是为了避免逆滤波后的图像进行旋转。简单而言,就是将频域中的输入图像和PSF的傅里叶变换进行逐元素相除,然后进行逆傅里叶变换,就实现了逆滤波操作。具体代码如下。

def inverse (input, PSF, eps):
    input_fft = fft.fft2(input) # 进行二维数组的傅里叶变换,将图像转换到频域
    PSF_fft =fft.fft2(PSF)+ eps # 噪声功率,这是已知的,考虑epsilon

    # 为避免逆滤波后的图像进行旋转,将PSF的中心移到图像中心
    PSF_fft_shifted = fft.fftshift(PSF_fft)  # 将PSF的中心移到图像中心
    # 对频域中的输入图像和PSF的傅里叶变换进行逐元素相除,然后进行逆傅里叶变换。这一步实现了逆滤波操作。
    result = fft.fft2(input_fft / PSF_fft_shifted)
    # 对逆滤波得到的频域结果进行频谱中心平移,取其绝对值,得到逆滤波后的时域图像。
    result = np.abs(fft.fftshift(result))

    return result

3.维纳滤波
同理,对图像和点扩散函数(PSF)分别进行傅里叶变换。之后,计算维纳滤波的频域滤波器。将输入图像的傅里叶变换与维纳滤波器的傅里叶变换逐元素相乘,然后进行逆傅里叶变换,得到维纳滤波后的时域结果。具体代码如下。

def wiener(input,PSF,eps,K=0.01): # 维纳滤波,K=0.01
    # 对输入图像进行二维傅里叶变换,将图像转换到频域。
    input_fft = fft.fft2(input)
    # 点扩散函数(PSF)进行傅里叶变换,同时考虑了噪声功率 eps。这一步是为了在频域中进行维纳滤波操作的准备。
    PSF_fft = fft.fft2(PSF) + eps
    # 计算维纳滤波的频域滤波器。np.conj()是复共轭操作,这里计算的是维纳滤波器的分母,其中 K 是维纳滤波的参数,用于控制噪声增强的程度。
    PSF_fft_1 = np.conj(PSF_fft) /(np.abs(PSF_fft)** 2 + K)
    # 将输入图像的傅里叶变换与维纳滤波器的傅里叶变换逐元素相乘,然后进行逆傅里叶变换,得到维纳滤波后的时域结果。
    result = fft.ifft2(input_fft * PSF_fft_1)
    # 将维纳滤波后的频域结果进行频谱中心平移,取其绝对值,得到维纳滤波后的时域图像。
    result = np.abs(fft.fftshift(result))
    return result

4.函数调用与绘图
这块比较简单,直接附上代码

image = cv2.imread('R.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
img_h =image.shape[0]
img_w =image.shape[1]
plt.figure(1)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 选择一个包含中文字符的字体
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
plt.xlabel("原始图像")
plt.gray()
plt.imshow(image) #显示原图像
plt.figure(2)
plt.gray()

# 进行运动模糊处理
PSF = motion_process((img_h, img_w), 60)
blurred = np.abs(make_blurred(image, PSF, 1e-3))
plt.subplot(231)
plt.xlabel(" 进行模糊 ")
plt.imshow(blurred)
result = inverse(blurred, PSF, 1e-3)
# 逆滤波,对图像进行滤波处理
result = np.flipud(result)  
result = np.fliplr(result)
plt.subplot(232)
plt.xlabel("对进行模糊的图像进行逆滤波")
plt.imshow(result)

result = wiener(blurred, PSF, 1e-3)  # 维纳滤波
plt.subplot(233)
plt.xlabel("对模糊后的图像进行维纳滤波(k=0.01)")
plt.imshow(result)

# 在模糊图像上进一步添加呈正态分布的噪声
blurred_noisy = blurred + 0.1 * blurred.std()*\
                np.random.standard_normal(blurred.shape)  # 添加噪声,standard_normal

 # 产生随机的函数
plt.subplot(234)
plt.xlabel("在模糊图像上引入噪声")
plt.imshow(blurred_noisy)  # 显示添加噪声且运动模糊的图像result=inverse(blurred_noisyPSF,0.1+1e-3) # 对添加噪声的图像进行逆滤波
plt.subplot(235)
plt.xlabel("对模糊和加噪的图片进行逆滤波")
plt.imshow(result)
result = wiener(blurred_noisy, PSF,0.1 + 1e-3)  # 对添加噪声的图像进行维纳滤波
plt.subplot(236)
plt.xlabel("对模糊和加噪的图片进行维纳滤波(k=0.01) ")
plt.imshow(result)
plt.tight_layout()
plt.show()

5.运行结果
在这里插入图片描述
在这里插入图片描述
6.总结
本次实验对原来的图像进行运动模糊后,分别采用逆滤波和维纳滤波进行对图像的恢复。之后在模糊图像的基础上进一步添加呈标准正态分布的噪声。再次,分别采用逆滤波和维纳滤波进行对图像的恢复。但是从实验结果来看,还是存在一定的振铃效应。
因为开头要导入一些必要的库。完整代码如下。

import matplotlib.pyplot as plt
import numpy as np
from numpy import fft
import math
import cv2

# 对退化过程进行建模
def motion_process(image_size, motion_angle):
    # 创建一个大小为image_size的二维数组PSF,并将其所有元素初始化为零,作为点扩散函数的初始值。
    PSF = np.zeros(image_size)
    print(image_size)
    # 计算图像的中心位置,由于数组索引是从0开始的,所以需要减1。
    center_position = (image_size[0] - 1) / 2
    print(center_position)
    # 计算运动方向的斜率的正切值。这里的motion_angle是以度为单位的运动方向角度。
    slope_tan = math.tan(motion_angle * math.pi/ 180)
    # 计算斜率的余切值。
    slope_cot = 1/slope_tan
    # 如果斜率的正切值小于等于1,表示运动方向接近水平。
    if slope_tan <=1:
        for i in range(15):
            # 计算相对于中心位置的水平偏移。round函数用于将浮点数四舍五入为整数。
            offset = round(i * slope_tan) #((center_position-i)*slope_tan)
            # 在点扩散函数的相应位置设置值为1,形成一条近似水平的模糊效果。
            PSF [int (center_position + offset), int(center_position - offset)] = 1
        # 将点扩散函数进行归一化,确保其总和为1。
        return PSF/PSF.sum() #对点扩散函数进行归一化亮度
    # 如果斜率的正切值大于1,表示运动方向接近垂直。
    else:
        for i in range(15):
            # 计算相对于中心位置的垂直偏移。
            offset = round(i * slope_cot)
            # :在点扩散函数的相应位置设置值为1,形成一条近似垂直的模糊效果。
            PSF[int(center_position - offset),int(center_position + offset)] = 1
        #     将点扩散函数进行归一化,确保其总和为1。
        return PSF / PSF.sum()

#
def make_blurred(input, PSF, eps):
    # 对输入图像进行二维傅里叶变换。
    input_fft = fft.fft2(input)  # 进行二维数组的傅里叶变换
    # 对点扩散函数(PSF)进行二维傅里叶变换,并添加一个小的常数eps以避免除零错误。这是在频域进行卷积操作的准备步骤。
    PSF_fft = fft.fft2(PSF) + eps
    # input_fft * PSF_fft, 将输入图像的傅里叶变换与点扩散函数的傅里叶变换进行逐元素相乘,这相当于在时域中进行卷积。
    # 之后对相乘结果进行逆傅里叶变换,得到模糊处理后的图像。
    blurred = fft.ifft2(input_fft * PSF_fft)
    # 用fftshift将频谱移到图像中心,然后取绝对值,得到最终的模糊图像。
    blurred = np.abs(fft.fftshift(blurred))
    return blurred

# 逆滤波的目标是尽可能地从经过模糊和添加噪声的图像中恢复原始图像
# 逆滤波
def inverse (input, PSF, eps):
    input_fft = fft.fft2(input) # 进行二维数组的傅里叶变换,将图像转换到频域
    PSF_fft =fft.fft2(PSF)+ eps # 噪声功率,这是已知的,考虑epsilon

    # 为避免逆滤波后的图像进行旋转,将PSF的中心移到图像中心
    PSF_fft_shifted = fft.fftshift(PSF_fft)  # 将PSF的中心移到图像中心
    # 对频域中的输入图像和PSF的傅里叶变换进行逐元素相除,然后进行逆傅里叶变换。这一步实现了逆滤波操作。
    result = fft.fft2(input_fft / PSF_fft_shifted)
    # 对逆滤波得到的频域结果进行频谱中心平移,取其绝对值,得到逆滤波后的时域图像。
    result = np.abs(fft.fftshift(result))

    return result
def wiener(input,PSF,eps,K=0.01): # 维纳滤波,K=0.01
    # 对输入图像进行二维傅里叶变换,将图像转换到频域。
    input_fft = fft.fft2(input)
    # 点扩散函数(PSF)进行傅里叶变换,同时考虑了噪声功率 eps。这一步是为了在频域中进行维纳滤波操作的准备。
    PSF_fft = fft.fft2(PSF) + eps
    # 计算维纳滤波的频域滤波器。np.conj()是复共轭操作,这里计算的是维纳滤波器的分母,其中 K 是维纳滤波的参数,用于控制噪声增强的程度。
    PSF_fft_1 = np.conj(PSF_fft) /(np.abs(PSF_fft)** 2 + K)
    # 将输入图像的傅里叶变换与维纳滤波器的傅里叶变换逐元素相乘,然后进行逆傅里叶变换,得到维纳滤波后的时域结果。
    result = fft.ifft2(input_fft * PSF_fft_1)
    # 将维纳滤波后的频域结果进行频谱中心平移,取其绝对值,得到维纳滤波后的时域图像。
    result = np.abs(fft.fftshift(result))
    return result

image = cv2.imread('R.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
img_h =image.shape[0]
img_w =image.shape[1]
plt.figure(1)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 选择一个包含中文字符的字体
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
plt.xlabel("原始图像")
plt.gray()
plt.imshow(image) #显示原图像
plt.figure(2)
plt.gray()

# 进行运动模糊处理
PSF = motion_process((img_h, img_w), 60)
blurred = np.abs(make_blurred(image, PSF, 1e-3))
plt.subplot(231)
plt.xlabel(" 进行模糊 ")
plt.imshow(blurred)
result = inverse(blurred, PSF, 1e-3)
# 逆滤波,对图像进行滤波处理
result = np.flipud(result)
result = np.fliplr(result)
plt.subplot(232)
plt.xlabel("对进行模糊的图像进行逆滤波")
plt.imshow(result)

result = wiener(blurred, PSF, 1e-3)  # 维纳滤波
plt.subplot(233)
plt.xlabel("对模糊后的图像进行维纳滤波(k=0.01)")
plt.imshow(result)

# 在模糊图像上进一步添加呈正态分布的噪声
blurred_noisy = blurred + 0.1 * blurred.std()*\
                np.random.standard_normal(blurred.shape)  # 添加噪声,standard_normal

 # 产生随机的函数
plt.subplot(234)
plt.xlabel("在模糊图像上引入噪声")
plt.imshow(blurred_noisy)  # 显示添加噪声且运动模糊的图像result=inverse(blurred_noisyPSF,0.1+1e-3) # 对添加噪声的图像进行逆滤波
plt.subplot(235)
plt.xlabel("对模糊和加噪的图片进行逆滤波")
plt.imshow(result)
result = wiener(blurred_noisy, PSF,0.1 + 1e-3)  # 对添加噪声的图像进行维纳滤波
plt.subplot(236)
plt.xlabel("对模糊和加噪的图片进行维纳滤波(k=0.01) ")
plt.imshow(result)
plt.tight_layout()
plt.show()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1299238.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

风力发电对讲 IP语音对讲终端IP安防一键呼叫对讲 医院对讲终端SV-6005网络音频终端

风力发电对讲 IP语音对讲终端IP安防一键呼叫对讲 医院对讲终端SV-6005网络音频终端 目 录 1、产品规格 2、接口使用 2.1、侧面接口功能 2.2、背面接口功能 2.3、面板接口功能 3、功能使用 1、产品规格 输入电源&#xff1a; 12V&#xff5e;24V的直流电源 网络接口&am…

【Go实现】实践GoF的23种设计模式:适配器模式

上一篇&#xff1a;【Go实现】实践GoF的23种设计模式&#xff1a;备忘录模式 简单的分布式应用系统&#xff08;示例代码工程&#xff09;&#xff1a;https://github.com/ruanrunxue/Practice-Design-Pattern–Go-Implementation 简介 适配器模式&#xff08;Adapter&#xf…

《形式语言与自动机理论(第4版)》笔记(三)

文章目录 [toc]前导《形式语言与自动机理论&#xff08;第4版&#xff09;》笔记&#xff08;一&#xff09;《形式语言与自动机理论&#xff08;第4版&#xff09;》笔记&#xff08;二&#xff09; 第四章&#xff1a;正则表达式4.1|启示4.2|正则表达式的形式定义正则表达式性…

软件设计师——计算机组成原理(二)

&#x1f4d1;前言 本文主要是【计算机组成原理】——软件设计师——计算机组成原理的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 …

iOS分段控件UISegmentedControl使用

在故事板中添加UISegmentedControl 具体添加步聚如下: 选择Xcode的View菜单下的Show Library (或者Shift+Common+L) 打开控件库如下 在控件库中输入seg搜索控件,在出现Segmented Control后,将其拖到View Controller Scene中 到这里,添加分段控件UI已完成, 接下来将控件与变量…

配置OSS后如何将服务器已有文件上传至OSS,推荐使用ossutil使用

1.下载安装ossutil sudo -v ; curl https://gosspublic.alicdn.com/ossutil/install.sh | sudo bash2.交互式配置生成配置文件 ossutil config 根据提示分别设置配置文件路径、设置工具的语言、Endpoint、AccessKey ID、AccessKey Secret和STSToken参数&#xff0c;STSToken留…

软件接口安全设计规范

《软件项目接口安全设计规范》 1.token授权机制 2.https传输加密 3.接口调用防滥用 4.日志审计里监控 5.开发测试环境隔离&#xff0c;脱敏处理 6.数据库运维监控审计

万界星空科技低代码平台:搭建MES系统的优势

低代码MES系统&#xff1a;制造业数字化转型的捷径 随着制造业的数字化转型&#xff0c;企业对生产管理系统的需求逐渐提高。传统的MES系统实施过程复杂、成本高昂&#xff0c;已经无法满足现代企业的快速发展需求。而低代码搭建MES系统的出现&#xff0c;为企业提供了一种高…

24、文件上传漏洞——Apache文件解析漏洞

文章目录 一、环境简介一、Apache与php三种结合方法二、Apache解析文件的方法三、Apache解析php的方法四、漏洞原理五、修复方法 一、环境简介 Apache文件解析漏洞与用户配置有密切关系。严格来说&#xff0c;属于用户配置问题&#xff0c;这里使用ubantu的docker来复现漏洞&am…

MySQL的锁机制

1.简介 MySQL的隔离性是由锁机制来保证的。锁是计算机协调多个进程或线程并发地访问某一资源你的机制。当多线程并发地访问某个数据时&#xff0c;尤其是在涉及金钱等安全敏感性数据的时候&#xff0c;需要保证数据在任意时刻最多只有一个线程可以对其进行修改&#xff0c;从而…

springboot mybatis手动事务

创建springboot项目 搭建最简单的SpringBoot项目-CSDN博客 引入mybatis和数据库依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><…

MacOS环境配置一系列问题的汇总,方便以后自己查看

环境配置一系列问题的汇总&#xff0c;方便以后自己查看 man brew报错“No manual entry for brew” 解决方法记录&#xff1a; 解决问题之前尝试的方法&#xff1a; Linking manuals from Homebrew1 https://apple.stackexchange.com/questions/111061/linking-manuals-f…

虚拟机安装 hyper—v 沙盒

一、下载系统镜像 1、确认电脑内存在8G及以上并提前准备完整的系统镜像 安装Hyper-V并重启电脑后打开程序选择虚拟机 选择安装位置并设置保留第一代的虚拟参数即可开始分配内存&#xff0c;根据自己的需求进行设置 右键虚拟机启动并开始运行&#xff0c;进行镜像系统的安装便完…

力扣 4. 寻找两个正序数组的中位数

题目 给定两个大小分别为 m 和 n 的正序&#xff08;从小到大&#xff09;数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。 算法的时间复杂度应该为 O(log (mn)) 。 My class Solution {public double findMedianSortedArrays(int[] nums1, int[] nums2) {i…

科学计算入门

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

04-详解Eureka注册中心的作用,具体配置,服务注册和服务发现

Eureka注册中心的作用 Eureka架构 远程调用的两个问题 服务的ip地址和端口号写死: 生产环境中服务的地址可能会随时发生变化,如果写死每次都需要重新修改代码多实例问题: 在高并发的情况下一个服务可以有多个实例形成一个集群,此时如果采用硬编码的方式只能访问服务的一个实…

【Java+MySQL】前后端连接小白教程

目录 &#x1f36d;【IntelliJ IDEA】操作 &#x1f36d;1. 连接MySQL数据库 &#x1f308;1.1 错误解决 &#x1f36d;2. 操作MySQL数据库 &#x1f308;2.1 双击查看表数据 &#x1f308;2.2 编写SQL脚本 &#x1f36d;【IntelliJ IDEA】 IntelliJ IDEA是由JetBrains公司…

[后端卷前端2]

绑定class 为什么需要样式绑定呢? 因为有些样式我们希望能够动态展示 看下面的例子: <template><div><p :class"{active:modifyFlag}">class样式绑定</p></div> </template><script>export default {name: "goo…

ffprobe命令行超详细使用详解

本文做为阅读ffprobe源码的前课程。为了之后方便理解ffprobe的源码,咱们先从ffprobe的命令学习。 课程内容如下: 文章目录 一、ffprobe主要选项说明1、每次使用ffprobe都打印编译环境的信息,太烦了2、如何分析媒体文件中存在的流信息3、如何指定查询某路流信息4、查看输入文…

蒙特霍尔问题(选择三扇门后的车与羊)及其贝叶斯定理数学解释

1. 蒙特霍尔问题 有一个美国电视游戏节目叫做“Let’s Make a Deal”&#xff0c;游戏中参赛者将面对3扇关闭的门&#xff0c;其中一扇门背后有一辆汽车&#xff0c;另外两扇门后是山羊&#xff0c;参赛者如果能猜中哪一扇门后是汽车&#xff0c;就可以得到它。 通常&#xf…