FPGA图像处理之均值滤波

文章目录

  • 一、什么是图像滤波?
    • 1.1 噪声类型
    • 1.2 滤波类型
  • 二、均值滤波原理
    • 2.1 3*3窗口滑动过程
    • 2.2 图像扩展
  • 三、Matlab实现均值滤波
  • 四、FPGA实现均值滤波
    • 4.1 生成 3*3 矩阵
    • 4.2 仿真3*3矩阵
    • 4.3 计算均值
    • 4.4 仿真均值滤波


一、什么是图像滤波?

  图像滤波是一种图像处理技术,旨在通过对图像进行修改来改善图像质量或提取特定特征。滤波通常用于去除噪声、平滑图像、增强边缘或提取特征等。

1.1 噪声类型

  在图像数据采集、处理、传输等过程中图像数据会受到噪声损坏;因为噪声无处不在,严重的会直接影响用户视觉感受,因此在图像处理中降噪是非常关键的步骤,对于不同类型的噪声使用不同的滤波器会有更好的效果。以下是被不同类型噪声污染的图片,matlab代码:

% 读取原始图像
originalImage = imread('yuanyang.bmp'); % 替换为你的图像文件名% 将图像转换为灰度图像(如果是彩色图像)
if size(originalImage, 3) == 3originalImage = rgb2gray(originalImage);
end% 添加高斯噪声
gaussianNoiseImage = imnoise(originalImage, 'gaussian', 0, 0.01); % 均值0,方差0.01% 添加椒盐噪声
saltPepperNoiseImage = imnoise(originalImage, 'salt & pepper', 0.02); % 2% 椒盐噪声% 添加泊松噪声
poissonNoiseImage = imnoise(originalImage, 'poisson');% 添加斑点噪声
speckleNoiseImage = imnoise(originalImage, 'speckle', 0.04); % 方差0.04% 显示原始图像和不同类型的噪声图像
figure;subplot(2, 3, 1);
imshow(originalImage);
title('原始图像');subplot(2, 3, 2);
imshow(gaussianNoiseImage);
title('高斯噪声');subplot(2, 3, 3);
imshow(saltPepperNoiseImage);
title('椒盐噪声');subplot(2, 3, 4);
imshow(poissonNoiseImage);
title('泊松噪声');subplot(2, 3, 5);
imshow(speckleNoiseImage);
title('斑点噪声');

在这里插入图片描述

  1. 高斯噪声:服从高斯分布的随机噪声,通常表现为图像的亮度随机波动;通常由传感器噪声或其他随机因素引起。
  2. 椒盐噪声:图像中随机出现的黑色和白色像素,类似于撒盐和胡椒;通常由图像传输错误或传感器有坏点引起的。
  3. 泊松噪声:与光子计数相关的噪声,通常在低光照条件下出现;常见于医学成像和天文成像,在低亮度区域,噪声会显得更加明显。
  4. 斑点噪声:通常在医学影像中出现,表现为图像中的随机斑点。

1.2 滤波类型

  图像滤波通常涉及对图像中每个像素的值进行修改,通常是通过考虑该像素及其邻域像素的值。滤波器通常使用一个称为“卷积核”或“滤波器”的小矩阵来实现这一点。卷积核在图像上滑动,并对覆盖的像素值进行加权平均或其他运算,常见的图像滤波器有:

  1. 均值滤波器
  2. 高斯滤波器
  3. 中值滤波器
  4. 双边滤波器
  5. 拉普拉斯滤波器
  6. Sobel滤波器
  7. Canny滤波器

  不同滤波器对应的应用场景也不同,有的是做降噪,有的是提取图像特征,本篇文章先来介绍均值滤波器的实现。

二、均值滤波原理

  我们知道图像滤波就是通过判断当前像素周边的像素来修改,可以想象成一个矩形框。所以滤波关键的因素就是矩形框的大小以及矩形框里的像素值所占的权重。均值滤波的原理:就是用矩形框里面所有的像素值的平均值来替换矩形框中心的像素,如下图所示,表示一幅图像数据:

在这里插入图片描述

  上面是一幅10*6 大小的图像数据,假如这幅图像数据被椒盐噪声污染,我们污染后的像素点标志为红色,如下图所示:

在这里插入图片描述
  这些噪点在视觉上表现为亮度特别突出的点,比周围像素点的亮度高很多,因此才会影响到视觉效果。均值滤波的计算窗口有 33 、55、77等等,窗口越大计算量越大,效果也越好,这里用33的窗口来演示均值滤波。

2.1 3*3窗口滑动过程

在这里插入图片描述

  第一个3*3窗口从上到下,从左到右依次滑动,每次滑动窗口后计算并且修改中心值的像素值。如上图所示第一次窗口滑动计算了这9个像素的均值然后替换了中心点的像素值,这样第一个噪点就被平均了,不会那么突出了。这也是均值滤波的局限性,噪声并没有被消除而是被平均了;如果窗口很大,那么图片也会变得有点模糊,也会平滑图像的边缘特征。

在这里插入图片描述
  第二个窗口滑动后,计算替代了(1,2)的像素点,其它的以此类推。

在这里插入图片描述
  上图是窗口滑动到最后一行后,我们可以看到在经过33窗口滑动计算后,新的图像会少两行两列;如果是55的窗口,滑动后会少4行4列,因此在实际处理过程中需要对图像进行扩展来确保计算后的图像大小不变。

2.2 图像扩展

   通常图像扩展会通过补0或者补1,或者使用原值来填充,这里我们使用原值填充,就是判断当前计算的点为边缘时,不用计算直接用原值填充就行,我们需要在原始图像进行扩展2行2列,如下图所示:

在这里插入图片描述
   如上所示,我们用x值来填充原始图像,假如原始图像大小为NM,那么填充后的图像大小为(N+2) * (M+2),我们再用新的图像大小做33窗口的滑动,如下所示:

在这里插入图片描述
   第一次窗口滑动后计算了新图像左上角的像素。

在这里插入图片描述
  第二次窗口滑动计算了新图像的第一行左边第二个的像素,其它的依次类推。

在这里插入图片描述
  在滑动完最后一个窗口后,图像也就计算完成。原始图像大小为 NM 经过图像扩展变成 (N+2) * (M+2),再经过33窗口计算变成了 N*M,这样新的图像大小就和原始图像大小一致了。

三、Matlab实现均值滤波

  在Matlab里可以直接调用均值滤波的函数,再滤波之前需要将图像数据转成灰度图像,因为噪声污染的大多是是异常的亮度,跟颜色无关,在均值的时候也是平均亮度,matlab代码如下:

clc;
close all;
% 读取原始图像
originalImage = imread('yuanyang.bmp'); % 将图像转换为灰度图像(如果是彩色图像)
if size(originalImage, 3) == 3originalImage = rgb2gray(originalImage);
end% 添加噪声
noisyImage = imnoise(originalImage, 'salt & pepper', 0.02); % 添加椒盐噪声% 均值滤波
filterSize = 3; % 滤波器大小
meanFilteredImage = imfilter(noisyImage, fspecial('average', filterSize));% 显示原始图像、带噪声的图像和均值滤波后的图像
figure;subplot(1, 3, 1);
imshow(originalImage);
title('原始图像');subplot(1, 3, 2);
imshow(noisyImage);
title('带噪声的图像');subplot(1, 3, 3);
imshow(meanFilteredImage);
title('均值滤波后的图像');

在这里插入图片描述
  我们放大滤波后的图像来看。
在这里插入图片描述
  可以看到噪点其实都没有被消除,只是被平均了而已,这也是均值滤波的局限性。我们把窗口设成5*5,再放大看一下。
在这里插入图片描述
  可以看到窗口变大后,降噪效果也变好了,但是图像变得模糊了。

四、FPGA实现均值滤波

  实现均值滤波的关键就是开窗和扩展,关于生成3*3的矩阵,我们可以参考《FPGA图像处理之三行缓存》这里面,稍作修改一下。

4.1 生成 3*3 矩阵

  我们在三行缓存的基础上增加两行两列,使得原图像扩展一下,最后通过一个3*3的矩阵依次缓存下来:

always @(posedge sys_clk) beginif(sys_rst == 1'b1)begin{ro_matrix_11, ro_matrix_12, ro_matrix_13} <= 'd0;{ro_matrix_21, ro_matrix_22, ro_matrix_23} <= 'd0;{ro_matrix_31, ro_matrix_32, ro_matrix_33} <= 'd0;endelse if(w_img_data_valid == 1'b1)begin{ro_matrix_11, ro_matrix_12, ro_matrix_13} <= {ro_matrix_12, ro_matrix_13,w_img_data_1line};{ro_matrix_21, ro_matrix_22, ro_matrix_23} <= {ro_matrix_22, ro_matrix_23,w_img_data_2line};{ro_matrix_31, ro_matrix_32, ro_matrix_33} <= {ro_matrix_32, ro_matrix_33,w_img_data_3line};end
end

4.2 仿真3*3矩阵

  为了加快我们的仿真时间,我们在tb文件里先设置图像的长宽为50*50,然后输入的图像数据为0、1、2、3、…2499。仿真代码如下:

`timescale 1ns / 1psmodule tb_img_3line_buffer();reg                                                 sys_clk ;
reg                                                 sys_rst ;
reg                                                 i_img_data_valid    ;
reg             [23:0]                              i_img_data  ;
reg             [12:0]                              cnt ;
reg             [1:0]                               waite_cnt   ;initial beginsys_clk =0;sys_rst = 1;i_img_data_valid = 0;i_img_data = 'd0;#200;sys_rst = 0;
endalways #5 sys_clk = ~sys_clk;always @(posedge sys_clk) beginif(sys_rst == 1'b1)waite_cnt <= 'd0;else if(cnt == 49)waite_cnt <= 'd0;else if(i_img_data_valid == 1'b0)waite_cnt <= waite_cnt + 1'b1;elsewaite_cnt <= waite_cnt;
endalways @(posedge sys_clk) beginif(sys_rst == 1'b1)i_img_data_valid <= 1'b0;else if(cnt == 49)i_img_data_valid <= 1'b0;else if((waite_cnt == 3) && (i_img_data <= 2499))i_img_data_valid <= 1'b1;elsei_img_data_valid <= i_img_data_valid;
endalways @(posedge sys_clk) beginif(sys_rst == 1'b1)cnt <= 'd0;else if(cnt == 49)cnt <= 'd0;else if(i_img_data_valid == 1'b1)cnt <= cnt + 1'b1;elsecnt <= cnt;
endalways @(posedge sys_clk) beginif(sys_rst == 1'b1)i_img_data <= 'd0;//else if(i_img_data == 49)//    i_img_data <= 'd0;else if(i_img_data_valid == 1'b1)i_img_data <= i_img_data + 1'b1;elsei_img_data <= i_img_data;
endendmodule

  在代码里,我设置的扩展行列数据用十进制66填充,这样为了更好的观察,实际上可以根据需要任意填充数据。

在这里插入图片描述

  仿真输入的图像数据如上所示。
在这里插入图片描述
  读出的矩阵数据应该如上所示,第一个矩阵的数据从上到下,从左到右应该是:66、66、66、66、0、1、66、50、51;第二个矩阵数据应该是:66、66、66、0、1、2、50、51、52;其他的以此类推。我们打开仿真:

在这里插入图片描述  我们可以看到输入的图像数据就是从0-2499的累加数,每一行50个数,一共50列,我们来看输出的矩阵:

在这里插入图片描述
  第一个矩阵是66、66、66、66、0、1、66、50、51;第二个矩阵数据是:66、66、66、0、1、2、50、51、52;和我们设定的一致,其他的也是一样。

4.3 计算均值

  均值计算比较简单,就是九个数据相加起来除以9。我们知道FPGA不擅长做除法,因此我们可以先扩大再截位,可以先把数据扩大2^15 / 9 = 3640。然后取高8位即可,Verilog代码如下:

always @(posedge sys_clk) beginif(sys_rst == 1'b1)beginsum_1_line  <= 'd0;sum_2_line  <= 'd0;sum_3_line  <= 'd0;all_sum     <= 'd0;endelse beginsum_1_line  <= w_matrix_11[23:16] + w_matrix_12[23:16] + w_matrix_13[23:16];sum_2_line  <= w_matrix_21[23:16] + w_matrix_22[23:16] + w_matrix_23[23:16];sum_3_line  <= w_matrix_31[23:16] + w_matrix_32[23:16] + w_matrix_33[23:16];all_sum     <= sum_1_line + sum_2_line + sum_3_line;end
end//延迟了1拍,avg = all_sum / 9 = all_sum * 3641 >> 15
always @(posedge sys_clk) beginif(sys_rst)sum_mult <= 'd0;elsesum_mult <= all_sum * 12'd3641;
end//延迟了1拍
always @(posedge sys_clk) beginif(sys_rst)agv_data <= 'd0;elseagv_data <= sum_mult[22:15] + sum_mult[14];    //四舍五入
end

4.4 仿真均值滤波

  我们先用matlab给一张图片加上椒盐噪声然后生成灰度图片,matlab代码如下:

% 读取原始灰度图像
originalImage = imread('your_image.jpg'); % 替换为你的图像文件名% 检查图像是否为灰度图像
if size(originalImage, 3) == 1% 如果是灰度图像,直接使用grayImage = originalImage;
else% 如果是彩色图像,转换为灰度图像grayImage = rgb2gray(originalImage);
end% 将灰度图像转换为 24 位 RGB 图像
rgbImage = cat(3, grayImage, grayImage, grayImage);% 添加椒盐噪声(可以根据需要选择其他类型的噪声)
noisyImage = imnoise(rgbImage, 'salt & pepper', 0.02); % 2% 椒盐噪声% 保存带噪声的图像为 24 位 BMP 文件
imwrite(noisyImage, 'noisy_image.bmp'); % 保存为 noisy_image.bmp% 应用均值滤波
filteredImage = imfilter(noisyImage, fspecial('average', [3 3]), 'replicate');% 显示原始图像、带噪声的图像和均值滤波后的图像
figure;subplot(1, 3, 1);
imshow(rgbImage);
title('原始灰度图像(RGB)');subplot(1, 3, 2);
imshow(noisyImage);
title('带噪声的图像');subplot(1, 3, 3);
imshow(filteredImage);
title('均值滤波后的图像');

在这里插入图片描述
  生成图片后,我们输入到仿真里面,添加均值滤波模块然后启动仿真。
在这里插入图片描述

在这里插入图片描述
  我们可以看到噪点被滤波处理变得暗淡了,我们放大看一些细节。
在这里插入图片描述
  放大后的图像依然有噪点,和matlab仿真放大的几乎一样,这就说明均值滤波不适合滤掉椒盐噪声,后续还会讲到其它滤波算法。

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

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

相关文章

得物App3D创新应用引关注,世界设计之都大会启幕

近日&#xff0c;2024世界设计之都大会&#xff08;WDCC&#xff09;在上海盛大启幕。此次大会以“设计无界 新质生长”为主题&#xff0c;汇聚了全球设计领域的精英与前沿成果&#xff0c;展现了设计作为新质生产力的巨大潜力。主场展览占据了整整3个楼面&#xff0c;总面积达…

C#学习笔记(十)

C#学习笔记&#xff08;十&#xff09; 第七章 对象的构造方法与实例方法一、对象的构造方法1. 构造方法初识2. 构造方法的创建3. this关键字4. 构造方法的规范和重载4.1 构造方法的规范 5. 对象初始化器5.1 对象初始化器和构造方法的区别 二、对象的实例方法1. 简单应用2.实例…

代码随想录算法训练营第二天(补) | 滑动窗口、模拟、前缀和

目录 3.4 长度最小的子数组 3.5螺旋矩阵II 3.6 区间和 文章讲解&#xff1a;[58. 区间和 | 代码随想录 3.4 长度最小的子数组 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 文章讲解&#xff1a;代码随想录 视频讲解&#xff1a;拿下滑动窗口&#xff…

Linux历史

Linux 于 1991 年由芬兰学生 Linus Torvalds 作为个人项目开始&#xff0c;旨在创建一个新的免费操作系统内核。在其历史发展中&#xff0c;Linux 内核经历了持续的增长。自 1991 年首次发布源代码以来&#xff0c;Linux 内核从少量的 C 语言文件&#xff0c;且受限于禁止商业发…

机器视觉基础系列四—简单了解背景建模算法

机器视觉基础系列四—简单了解背景建模算法 首先我们应该了解的是背景建模的定义是什么&#xff1f;又有哪些应用场景呢&#xff1f; 背景建模是指通过分析视频序列中的像素值变化情况&#xff0c;从中提取出静态背景部分&#xff0c;并将其用于目标检测、运动跟踪等计算机视觉…

渗透测试导论

渗透测试的定义和目的 渗透测试&#xff08;Penetration Testing&#xff09;是一项安全演习&#xff0c;网络安全专家尝试查找和利用计算机系统中的漏洞。 模拟攻击的目的是识别攻击者可以利用的系统防御中的薄弱环节。 这就像银行雇用别人假装盗匪&#xff0c;让他们试图闯…

LeetCode1004.最大连续1的个数

题目链接&#xff1a;1004. 最大连续1的个数 III - 力扣&#xff08;LeetCode&#xff09; 1.常规解法&#xff08;会超时&#xff09; 遍历数组&#xff0c;当元素是1时个数加一&#xff0c;当元素是0时且已有的0的个数不超过题目限制时&#xff0c;个数加一&#xff0c;若上…

Lumerical学习——优化和参数扫描(Optimization and parameter sweeps)

一、概要介绍 这部分介绍优化和参数扫描项目设定的方法。在有大量数据模拟计算过程中这个特性允许用户使处理方法自动地查找期望的参数值。 ① 创建一个参数扫描任务 ② 创建一个优化任务 ③ 创建一个良率分析任务 ⑤ 打开所选择项目的编辑窗口&#xff0c;编辑其属性…

基于Java+SpringBoot+Uniapp的博客系统设计与实现

项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…

嵌入式C++中内存分配基本实现方法

大家好,今天主要给大家分享一下,如何使用计算机中的内存空间进行分配,观察具体现象。 第一:C语言动态空间分配方式 第二:C++中动态内存分配方法 new 可以自动计算数据类型的大小 与 类型的转换 malloc 只能手动进行。 2.new 可以在分配空间的时候初始化 malloc 不行。 第三…

【优选算法】——双指针(上篇)!

&#x1f308;个人主页&#xff1a;秋风起&#xff0c;再归来~&#x1f525;系列专栏&#xff1a;C刷题算法总结&#x1f516;克心守己&#xff0c;律己则安 目录 前言&#xff1a;双指针 1. 移动零&#xff08;easy&#xff09; 2. 复写零&#xff08;easy&#xff09; 3…

计数型信号量

一&#xff0c;什么是计数型信号量&#xff1f; 计数型信号量相当于队列长度大于1 的队列&#xff0c;因此计数型信号量能够容纳多个资源&#xff0c;这在计数型信号量被创建的时候确定的。 计数型信号量相关 API 函数 函数描述xSemaphoreCreateCounting()使用动态方法创建计数…

工业相机详解及选型

工业相机相对于传统的民用相机而言&#xff0c;具有搞图像稳定性,传输能力和高抗干扰能力等&#xff0c;目前市面上的工业相机大多数是基于CCD&#xff08;Charge Coupled Device)或CMOS(Complementary Metal Oxide Semiconductor)芯片的相机。 一&#xff0c;工业相机的分类 …

Java 虚拟机实战(基础篇 1万字)

此笔记来自于黑马程序员 基础篇 初识 JVM(Java Virtual Machine) 什么是 JVM JVM 本质上是一个运行在计算机上的程序&#xff0c;他的职责是运行 Java 字节码文件 JVM 的功能 翻译成字节码 即时编译 Java语言如果不做任何优化&#xff0c;性能不如C、C等语言。Java 支持跨…

嬴图 | 图数据库系列 之 图算法与可解释性

2024年诺贝尔物理学奖颁发给了机器学习与神经网络领域的研究者&#xff0c;这是历史上首次出现这样的情况。这项奖项原本只授予对自然现象和物质的物理学研究作出重大贡献的科学家&#xff0c;如今却将全球范围内对机器学习和神经网络的研究和开发作为了一种能够深刻影响我们生…

手机怎么玩GTA5?GameViewer远程助你手机畅玩GTA5侠盗飞车

原来手机也可以玩电脑游戏&#xff01;如果你想随时随地用手机玩GTA5&#xff0c;网易GameViewer远程能帮你实现&#xff0c;它的按键映射功能会让你在体验GTA5时非常好。你不仅可以享受4K蓝光144帧高画质的 驾驶、第三人称射击&#xff0c;还有开放世界探索&#xff0c;还可以…

服务器软件之Tomcat

服务器软件之Tomcat 服务器软件之Tomcat 服务器软件之Tomcat一、什么是Tomcat二、安装Tomcat1、前提&#xff1a;2、下载3、解压下载的tomcat4、tomcat启动常见错误4.1、tomcat8.0 startup报错java.util.logging.ErrorManager: 44.2、java.lang.UnsatisfiedLinkError 三、Tomca…

高级算法设计与分析 学习笔记13 线性规划

注意是线性规划不是动态规划哦 好家伙&#xff0c;这不是凸优化吗&#xff1f; 凸优化标准形式&#xff1a; 先改成统一最大化&#xff08;凸优化那边怎么是统一最小化&#xff1f;&#xff09; 原来的x2正负无所谓&#xff0c;但我希望每个x都是有限制的&#xff0c;所以把它改…

MySQL初识

在了解什么是MySQL前&#xff0c;我们先了解一下什么是数据库&#xff1f;&#xff1f; 1. 数据库简介 1.1 什么是数据库 数据库是20世纪60年代末发展起来的⼀项重要技术&#xff0c;已经成为计算机科学与技术的⼀个重要分⽀。数据库技术主要是⽤来解决数据处理的⾮数值计算问…

基于SpringBoot+Vue+uniapp的电影信息推荐APP的详细设计和实现

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不…