当前位置: 首页 > news >正文

【盘古100Pro+开发板实验例程】FPGA学习 | 中值滤波 | 图像实验指导手册

 本原创文章由深圳市小眼睛科技有限公司创作,版权归本公司所有,如需转载,需授权并注明出处(www.meyesemi.com)

1. 实验简介

实验目的:

      生成 3x3 矩阵,并完成中值滤波。

实验环境:

      Window11

      PDS2022.SP6.4

      Modelsim10.6c

      MatlabR2023b

硬件环境:

      MES2L676-100HP

2. 实验原理

      在图像处理的入门算法中,中值滤波算法是一种经典的噪声平滑算法,它可以帮助我们过滤图片上的椒盐 噪声,非常适合孤立的噪声点处理。

      以目前主流的 rgb888 图像显示编码方案来说,图像的颜色深浅,是由 RGB 三色搭配后呈 24 位线性变化 显示颜色的差异的,如果一张图片中某一点的值异于周边的值太多,则我们判定其为噪声。下面我们用通俗举例 子的方法,一边讲解中值滤波的 FPGA 排序算法,一边分析滤波后算法的结果。

      举例来说,有 3x3 的图像数据矩阵如下:

      从上面 3x3 的数据矩阵中,不难发现,有数据 80 和周边的点有明显的颜色显示数值差异。反映到图像中, 应该是一个比周边值更亮的噪声孤点。

      如果采用中值滤波算法,对以上原始数据矩阵进行处理:

      第一步: 首先将 9 个图像数据按行分成 3 组, 分别对三组数据进行排序。

      (1)对 L11, L12, L13 进行排序得到:

       L1max(即 80), L1mid(即 4), L1min(即 2);

      (2)对 L21, L22, L23 进行排序得到 :

       L2max(即 5), L2mid(即 4), L2min(即 3);

      (3)对 L31, L32, L33 进行排序得到:

       L3max(即 6), L3mid(即 3), L3min(即 2)。

      处理后,得到一个临时过渡的矩阵,内容为:

      第二步:分别对三组像素数据中的 3 个最大, 3 个中间和 3 个最小分别进行排序。

      (1)对 L1max, L2max, L3max 进行排序得到 :

        Lmaxmax(即 80), Lmaxmid(即 6), Lmaxmin(即 5);

      (2)对 L1mid, L2mid, L3mid 进行排序得到:

       Lmidmax(即 4), Lmidmid(即 4), Lmidmin(即 3);

      (3)对 L1min, L2min, L3min 进行排序得到:

       Lminmax(即 3), Lminmid(即 2), Lminmin(即 2);

      处理后,得到这样第二个临时的过渡矩阵,内容为:

      第三步:对最大的最小(Lmaxmin),中间的中间(Lmidmid)以及最小的最大(Lminmax)进行排序,排序得到 的中间数据为最终的中值。

5(第一行末,最大的最小)4(第二行中,中间的中间)3(第三行首,最小的最大)

      最终,得到该图像矩阵中值为 4。

      这个中值,最终作为我们数据 9 宫格的第二行第二列的值。

      由于 FPGA 的图像显示数据采用的是逐个像素点的行场扫描输出方案,因此,当扫描到噪声信号点(如图中 数据 80)后,经过中值运算点阵的处理,该点是不会从矩阵输出的,即实现了图片噪声信号滤波。

      总结下,中值滤波方法是,对待处理的当前像素,选择一个模板,该模板为其邻近的若干个像素组成,对模 板的像素由小到大进行排序,再用模板的中值来替代原像素的值的方法。

      当我们使用 3x3 窗口后获取邻域中的 9 个像素,就需要对 9 个像素值进行排序,为了提高排序效率,排序 算法思想如下图所示:

(1) 对窗内的每行像素按降序排序,得到最大值、中间值和最小值;

(2) 把三行的最小值相比较,取其中的最大值;

(3) 把三行的最大值相比较,取其中的最小值;

(4) 把三行的中间值相比较,再取一次中间值;

(5) 把前面得到的三个值再做一次排序,获得的中值即该窗口的中值。

关于如何形成 3*3 的像素矩阵,请参考第十二章的内容,本章节重点讲解中值滤波的算法实现。

3. 接口列表

以下为 median_filter_3x3.v 模块的接口列表

4. 工程说明

      上图为本次工程架构,HDMI 输入后经过 MS7200 芯片解码出 RGB 数据,然后经过灰度化后进行中值滤波, 然后将数据存到 DDR3 之中,然后再从 DDR3 中读出到 HDMI 上显示。

4.1. 代码模块说明

本章节主要对中值滤波模块进行说明,以下是中值滤波 verilog 代码:

// 中值滤波 delay 3clk
module median_filter_3x3(input wire clk,input wire rst_n,input wire vsync_in,input wire hsync_in,input wire de_in,input wire [7:0] data11,input wire [7:0] data12,input wire [7:0] data13,input wire [7:0] data21,input wire [7:0] data22,input wire [7:0] data23,input wire [7:0] data31,input wire [7:0] data32,input wire [7:0] data33,output wire [7:0] target_data,output wire vsync_out,output wire hsync_out,output wire de_out
);//--------------------------------------------------------------------------------------
// FPGA Median Filter Sort order
// Pixel -- Sort1 -- Sort2 -- Sort3
// [ P1 P2 P3 ] [ Max1 Mid1 Min1 ]
// [ P4 P5 P6 ] [ Max2 Mid2 Min2 ] [Max_min, Mid_mid, Min_max] mid_valid
// [ P7 P8 P9 ] [ Max3 Mid3 Min3 ]// reg define
reg [2:0] vsync_in_r;
reg [2:0] hsync_in_r;
reg [2:0] de_in_r;// wire define
wire [7:0] max_data1;
wire [7:0] mid_data1;
wire [7:0] min_data1;
wire [7:0] max_data2;
wire [7:0] mid_data2;
wire [7:0] min_data2;
wire [7:0] max_data3;
wire [7:0] mid_data3;
wire [7:0] min_data3;
wire [7:0] max_min_data;
wire [7:0] mid_mid_data;
wire [7:0] min_max_data;//*****************************************************
//** main code
//*****************************************************
assign vsync_out = vsync_in_r[2];
assign hsync_out = hsync_in_r[2];
assign de_out = de_in_r[2];// Step1 对 stor3 进行三次例化操作
sort3 u_sort3_1( // 第一行数据排序.clk      (clk),.rst_n    (rst_n),.data1    (data11),.data2    (data12),.data3    (data13),.max_data (max_data1),.mid_data (mid_data1),.min_data (min_data1)
);sort3 u_sort3_2( // 第二行数据排序.clk      (clk),.rst_n    (rst_n),.data1    (data21),.data2    (data22),.data3    (data23),.max_data (max_data2),.mid_data (mid_data2),.min_data (min_data2)
);sort3 u_sort3_3( // 第三行数据排序.clk      (clk),.rst_n    (rst_n),.data1    (data31),.data2    (data32),.data3    (data33),.max_data (max_data3),.mid_data (mid_data3),.min_data (min_data3)
);// Step2 对三行像素取得的排序进行处理
sort3 u_sort3_4( // 取三行最大值的最小值.clk      (clk),.rst_n    (rst_n),.data1    (max_data1),.data2    (max_data2),.data3    (max_data3),.max_data (),.mid_data (),.min_data (max_min_data)
);sort3 u_sort3_5( // 取三行中值的最小值.clk      (clk),.rst_n    (rst_n),.data1    (mid_data1),.data2    (mid_data2),.data3    (mid_data3),.max_data (),.mid_data (mid_mid_data),.min_data ()
);sort3 u_sort3_6( // 取三行最小值的最大值.clk      (clk),.rst_n    (rst_n),.data1    (min_data1),.data2    (min_data2),.data3    (min_data3),.max_data (min_max_data),.mid_data (),.min_data ()
);// step3 将 step2 中得到的三个值,再次取中值
sort3 u_sort3_7(.clk      (clk),.rst_n    (rst_n),.data1    (max_min_data),.data2    (mid_mid_data),.data3    (min_max_data),.max_data (),.mid_data (target_data),.min_data ()
);// 延迟三个周期进行同步
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginvsync_in_r <= 0;hsync_in_r <= 0;de_in_r <= 0;endelse beginvsync_in_r <= {vsync_in_r[1:0], vsync_in};hsync_in_r <= {hsync_in_r[1:0], hsync_in};de_in_r <= {de_in_r[1:0], de_in};end
endendmodule

      这个模块实现了一个 3x3 的中值滤波器,用于图像处理。其主要功能是对输入的 3x3 图像矩阵进行中值计 算,并输出处理后的中心像素值。中值滤波是一种常用的去噪技术,它通过选择局部区域内的中间值来平滑图像, 同时保留图像的边缘细节。

      中值滤波器的核心在于排序 3x3 邻域的像素值,并选择其中的中间值作为输出。中值滤波可以有效去除椒 盐噪声,并且在保持边缘的情况下平滑图像。

      代码的第 54-56 行,延迟了输入同步信号三个时钟周期,使得这些信号与输出的滤波结果 target_data 对 齐。这个延迟通过移位寄存器(vsync_in_r, hsync_in_r, de_in_r)实现。

      代码的第 58-96 行,通过三个 sort3 模块,对 3x3 矩阵的每一行进行排序。每个 sort3 模块接收三个像素 值,输出它们的最大值、中间值和最小值。这样可以分别得到每行的最大、中间和最小值(max_data1, mid_data1, min_data1 等)。

      代码的第 98-136 行,使用额外的三个 sort3 模块来处理每一列的最大值、中值和最小值。

      第一个 sort3 模块 (u_sort3_4) 对三行的最大值(max_data1, max_data2, max_data3)进行排序,提 取出这三个最大值中的最小值(max_min_data)。

      第二个 sort3 模块 (u_sort3_5) 对三行的中值(mid_data1, mid_data2, mid_data3)进行排序,提取出 这三个中值中的最小值(mid_mid_data)。

      第三个 sort3 模块 (u_sort3_6) 对三行的最小值(min_data1, min_data2, min_data3)进行排序,提取 出这三个最小值中的最大值(min_max_data)。

      代码的第 138-150 行,进行最终的中值提取。在前两步中,我们得到的 max_min_data、mid_mid_data 和 min_max_data 分别是 3x3 矩阵中最大、最小和中间值的集合中的值。最后一步再使用一个 sort3 模块 (u_sort3_7) 来对这三个值进行排序,并提取中间值(mid_data)作为滤波后的输出 target_data。

      代码的第 152-164 行,通过一个 always 块,vsync_in、hsync_in 和 de_in 信号被延迟了三个时钟周期, 这样确保这些信号与处理后的数据 target_data 同步输出,避免了数据对齐问题。

4.2. 代码仿真
4.2.1. Matlab 仿真介绍
%% 读取图像
originalImage = imread('noise.png');
figure;%% 显示原图
subplot(1, 3, 1);
imshow(originalImage);
title('原图像');%% 灰度化
grayImage = rgb2gray(originalImage);%% 图像尺寸
[img_height, img_width] = size(grayImage);
medianImage = zeros(img_height, img_width);%% 定义参数
windowSize = 3; % 窗口大小,奇数%% 遍历像素 计算窗口均值
halfWindowSize = floor(windowSize / 2);for i = 1:img_heightfor j = 1:img_width% 窗口边界r1 = max(i - halfWindowSize, 1);    % 窗口上边界r2 = min(i + halfWindowSize, img_height); % 窗口下边界c1 = max(j - halfWindowSize, 1);    % 窗口左边界c2 = min(j + halfWindowSize, img_width);  % 窗口右边界% 提取窗口window = grayImage(r1:r2, c1:c2);% 计算窗口内的中值localmedian = median(window(:));medianImage(i,j) = localmedian;end
end%% 无符号 8bit
medianImage = uint8(medianImage);%% 将原图像转换为二值图像
binarizedImage = imbinarize(grayImage);% 显示原图和处理后的图像
subplot(1, 3, 2);
imshow(grayImage);
title('灰度化图像');subplot(1, 3, 3);
imshow(medianImage);
imwrite(medianImage, 'matlab_median.png');
title('中值滤波图像');

      代码首先读取要处理的图像并将其转换为灰度图像。

      然后初始化一个空的矩阵 filtered_img 来存储滤波后的图像。获取图像的尺寸,用于设置循环的边界。

      代码的 15-30 行是核心部分,使用双重循环遍历每个像素并应用中值滤波。

      双重循环 (for i = 2:rows-1, for j = 2:cols-1):循环从 2 到 rows-1,从 2 到 cols-1,以确保在提取 3x3 邻域时不会超出图像边界。使用这种方式遍历图像的每一个像素。

      提取 3x3 邻域 (window = gray_img(i-1:i+1, j-1:j+1)):window 变量获取以当前像素为中心的 3x3 邻域。MATLAB 中的矩阵切片(gray_img(i-1:i+1, j-1:j+1))用于提取图像矩阵中的子矩阵。

      计算中值 (filtered_img(i, j) = median(window(:))):将 window 转换为一个列向量 (window(:))。使 用 median 函数计算列向量的中值。将中值赋给 filtered_img 的相应位置,实现了对图像的中值滤波。

      最后显示滤波前后的图像,并将结果保存到文件中。

4.2.2. Modelsim 仿真介绍

      Tb 文件其实整体框架基本一致,只需要修改中间的例化模块和最后的有效信号和场信号以及数据即可,仅 给出修改后的部分,具体波形可以看视频或者读者自行仿真,只放置最后的 matlab 复原结果。

// 读取图片数据
video_data_gen #(.TOTAL_WIDTH (12'd1650),.IMG_WIDTH  (12'd1280),.H_SYNC     (12'd40),.H_BP       (12'd220),.H_FP       (12'd110),.TOTAL_HEIGHT (12'd750),.IMG_HEIGHT (12'd720),.V_SYNC     (12'd5),.V_BP       (12'd20),.V_FP       (12'd5)
) u_video_data_gen (.video_clk  (video_clk),.rst_n      (rst_n),.video_vs   (video_vs),.video_de   (video_de),.video_data (video_data)
);// 灰度化
RGB2YCbCr u_RGB2YCbCr (.clk        (video_clk),.rst_n      (rst_n),.vsync_in   (video_vs),.hsync_in   (video_de),.de_in      (video_de),.red        (video_data[23:19]),.green      (video_data[15:10]),.blue       (video_data[7:3]),.vsync_out  (y_vs),.hsync_out  (y_hs),.de_out     (y_de),.y          (y_data),.cb         (),.cr         ()
);// 矩阵生成
matrix_3x3 #(.IMG_WIDTH  (IMG_WIDTH),.IMG_HEIGHT (IMG_HEIGHT)
) u_matrix_3x3 (.video_clk  (video_clk),.rst_n      (rst_n),.video_vs   (y_vs),.video_de   (y_de),.video_data (y_data),.matrix_de  (matrix_de),.matrix11   (matrix11),.matrix12   (matrix12),.matrix13   (matrix13),.matrix21   (matrix21),.matrix22   (matrix22),.matrix23   (matrix23),.matrix31   (matrix31),.matrix32   (matrix32),.matrix33   (matrix33)
);// 中值滤波
median_filter_3x3 u_median_filter_3x3 (.clk        (video_clk),.rst_n      (rst_n),.vsync_in   (y_vs),.hsync_in   (matrix_de),.de_in      (matrix_de),.data11     (matrix11),.data12     (matrix12),.data13     (matrix13),.data21     (matrix21),.data22     (matrix22),.data23     (matrix23),.data31     (matrix31),.data32     (matrix32),.data33     (matrix33),.target_data(median_data),.vsync_out  (median_vs),.hsync_out  (median_hs),.de_out     (median_de)
);// 读取图片数据后经过灰度化模块,然后通过3x3矩阵后再通过中值滤波模块
always @(posedge video_clk or negedge rst_n) beginif (!rst_n)video_vs_d <= 1'd0;elsevideo_vs_d <= median_vs;
endassign frame_flag = ~median_vs & video_vs_d; // 下降沿always @(posedge video_clk or negedge rst_n) beginif (!rst_n)img_done <= 1'b0;else if (frame_flag) // 下降沿判断一帧结束img_done <= 1'b1;elseimg_done <= img_done;
endalways @(posedge video_clk or negedge rst_n) beginif (img_done) begin$stop; // 停止仿真endelse if (median_de) begin // 写入数据$fdisplay(output_file, "%h\t%h\t%h", median_data, median_data, median_data); // 16进制写入end
end

    最后的信号改成中值滤波后的信号即可,然后开启联合仿真。  

4.3. 实验现象

连接好下载器,电源、HDMI_IN 口连接电脑、HDMD_OUT 口连接显示器,然后下载程序。

上图为测试原图像,可以看到添加了很多椒盐噪声。

上图为中值滤波的处理结构,对比原图像,椒盐噪声基本滤除。

http://www.lryc.cn/news/618960.html

相关文章:

  • Redis知识点+项目+面试八股
  • redis认识缓存击穿
  • Flutter UI Kits by Olayemi Garuba:免费开源的高质量UI组件库
  • Element用法---Loading 加载
  • React 腾讯面试手写题
  • Photoshop软件打开WebP文件格的操作教程
  • 第六十四章:AI的“觅食”之路:数据采集器设计与多源数据获取
  • Android性能优化:架构层面的性能考量
  • Android 引导式访问(屏幕固定 Screen Pinning)完整指南
  • CPPIO流
  • 北京JAVA基础面试30天打卡08
  • 信号反射规律
  • [激光原理与应用-254]:理论 - 几何光学 - 自动对焦的原理
  • W5500之“socket.c”中的相关函数
  • Vue接口平台小功能——发送报告到飞书
  • AWT与Swing深度对比:架构差异、迁移实战与性能优化
  • Unity数据可视化图表插件XCharts
  • Elasticsearch JS 自定义 ConnectionPool / Connection / Serializer、敏感信息脱敏与 v8 平滑迁移
  • python调研本地 DeepSeek API的例子
  • NLP—词向量转换评论学习项目分析真实案例
  • 【Vue 3 响应式系统深度解析:reactive vs ref 全面对比】
  • 【实时Linux实战系列】基于RFID的实时资产追踪系统
  • 当赞美来敲门:优雅接纳的艺术
  • 21.Linux HTTPS服务
  • GitHub的简单使用方法----(5)
  • 文件IO的学习
  • 论文Review 激光动态物体剔除 Dynablox | RAL2023 ETH MIT出品!
  • web前端第二次作业
  • 5G专网项目外场常见业务测试指南(六)-PingInfoView
  • 衡石HENGSHI SENSE6.0亮点功能-应用创作