gaochy1126 发表于 2025-10-28 10:15

verilog HDL实现中值滤波

一、实现步骤:1、查看了中值滤波实现相关的网站和paper;2、按照某篇paper的设计思想进行编程实现;3、对各个模块进行语法检查、波形仿真、时序设计、调试验证;4、与matlab的中值滤波结果进行比较。二、实现过程:1、查看了中值滤波实现相关的网站和paper;在网上看了很多中值滤波的设计,也有一些代码可以下载,也有一片讲解的,只是感觉讲解的比较模糊而且不完整,最后看了几篇硕士论文,论文竟然主要做了中值滤波的工作,发现了一些设计思路,然后就按照自己的想法进行设计。2、按照某篇paper的设计思想进行编程实现;整个中值滤波模块分为几个小的模块:3*3窗口生成模块、计数器控制模块、3*3中值滤波模块、顶层模块以及最后的测试模块testbench的编写。整个框架的设计如下图所示(使用visio画的框架图):https://ask.qcloudimg.com/http-save/yehe-8131718/rit28hjs29.jpeg


各个模块的设计:1)ROM IP核的生成,用于存储原始灰度图像的数据。使用matlab生成.coe图像数据文件,然后使用Xilinx ISE工具将.coe文件添加到ROM核进行数据初始化,按步骤得到ROM模块,参考生成的.v文件在顶层模块直接调用即可。rom_512by512 rom_512by512_inst (   .clka(CLK),          //input clka;   .addra(rom_addr),   //input-from    .douta(rom_data)   //output-to);注意ROM的存储空间的大小;2)3*3窗口生成模块,用于生成滤波的滑动窗口,得到窗口内的所有元素数据。功能:(1)根据中心像素点得到所在其所在的行、列位置;(2)根据该模块的开始信号设计得到获取数据的有效时间序列;(3)在读取数据的有效时序内,得到窗口内的所有元素数据;(4)窗口数据的获取按照一定的时序顺序来获得,类似于黑金推荐的“仿顺序操作”,这个比较适合my style;不过后来发现调试的过程中被项目组的硬件人员改动了一些,甚至说不好,感觉可能是本人还没有理解掌握吃透“仿顺序操作”的精髓吧。(5)根据中心像素点的行、列位置信息得到每个窗口元素的ROM地址,根据某一时刻ROM地址,下一时刻调用ROM模块得到对应的元素数据,下一时刻将数据锁存,然后再读取该地址的数据;所以要注意地址和数据的获取不是在同一时刻,而是需要延迟两个时刻;(6)还需要注意的是图像的边界问题的特殊化处理;一般图像处理都会遇到边界问题,这个需要谨慎;(7)对matlab的中值滤波函数medfilt2原理的深入掌握对我们编写这一模块非常重要。matlab并没有主要过程的代码,看注释默认情况下边界元素设置为0,这也可以通过结果反推回去发现的。https://ask.qcloudimg.com/http-save/yehe-8131718/8ylyyw3wl6.png


https://ask.qcloudimg.com/http-save/yehe-8131718/1fosadhf3d.png


https://ask.qcloudimg.com/http-save/yehe-8131718/vt3xgxeygu.png


https://ask.qcloudimg.com/http-save/yehe-8131718/r8x21ug4sd.png


https://ask.qcloudimg.com/http-save/yehe-8131718/rfn2qr5qbf.png


https://ask.qcloudimg.com/http-save/yehe-8131718/kgt6f9yxc8.png


3)计数器控制模块,主要用于获得中心像素点的地址信息。(1)系统模块开始信号之后开始获取第一个中心像素点,注意初始化信号值和系统开始的信号值的区别;(2)该时刻得到的的数据将在下一个时刻产生结果,该时刻的数据并没有改变;(3)注意中心像素点的行、列位置信息的计算;https://ask.qcloudimg.com/http-save/yehe-8131718/rz5ey3q2wr.png


https://ask.qcloudimg.com/http-save/yehe-8131718/kwpwlu9syh.png


4) 3*3中值滤波模块功能:得到某一中心像素点的3*3滑窗区域的灰度值的中值,作为中心像素点的值;中值滤波原理,网上有很多,大家可以查看一下。本项目采用的是快速中值滤波的方法。(1)若是3*3窗口生成模块完成之后就计算下一个中心像素点,需要将该中心像素点的窗口元素锁存起来,以防计算过程中将这些元素掩盖,不能正确进行中值滤波的计算;https://ask.qcloudimg.com/http-save/yehe-8131718/2zilvohy42.png


(2)需要在时序的有效区域内进行计算,怎么设计信号的有效性;https://ask.qcloudimg.com/http-save/yehe-8131718/spus5y18r3.png


(3)仿顺序操作可以分开进行;每一个时刻只进行一个操作,这样可能更明了(代码中没有这样做);https://ask.qcloudimg.com/http-save/yehe-8131718/s4y9aadhng.png


(4)verilog编程调用函数的方法,指出输入信号,函数内可以使用其他定义声明的信号,最后的输出信号作为调用函数的结果(突然想起来,如果输出信号有多个元素呢,又该怎么办呢?大家可以想想);https://ask.qcloudimg.com/http-save/yehe-8131718/kvmwhuwhkr.png


该模块的代码:https://ask.qcloudimg.com/http-save/yehe-8131718/75ind9fi34.png


https://ask.qcloudimg.com/http-save/yehe-8131718/87fsiafbh4.png


https://ask.qcloudimg.com/http-save/yehe-8131718/gsuuayhzve.png


https://ask.qcloudimg.com/http-save/yehe-8131718/6o4aqilzhr.png


https://ask.qcloudimg.com/http-save/yehe-8131718/l60tnhwciw.png


https://ask.qcloudimg.com/http-save/yehe-8131718/5pb8ofzkmf.png


https://ask.qcloudimg.com/http-save/yehe-8131718/43zyih7u3a.png


5)顶层模块用于将低层的各个功能/控制模块衔接起来,得到结果;注意输入输出信号,以及不同模块之间是如何进行连线的。信号的名称尽量有其特别的意义,不要重复使用同一个信号名称,容易造成混乱;区别wire和reg类型数据的使用情况;https://ask.qcloudimg.com/http-save/yehe-8131718/n58dm098c3.png


https://ask.qcloudimg.com/http-save/yehe-8131718/zmij9nullq.png


https://ask.qcloudimg.com/http-save/yehe-8131718/otff6zu36y.png


6)测试模块如何将数据写入文件,需要定义文件的名称和类型;integer fouti;需要在初始化部分打开文件:fouti = $fopen("medfilter2_re.txt");代码如下:https://ask.qcloudimg.com/http-save/yehe-8131718/xg5xffzns5.png


https://ask.qcloudimg.com/http-save/yehe-8131718/jj3croqufu.png


https://ask.qcloudimg.com/http-save/yehe-8131718/ys1ucea6wl.png


整体的代码就是这样的。3、对各个模块进行语法检查、波形仿真、时序设计、调试验证;本人觉得原理清楚之后按部就班的编写代码还好,只是刚接触波形仿真和调试的时候是真心不顺心,还好有其他人帮忙调试;在调试的过程中其实会学习到很多东西,很多经验,以及很简单的但你之前就是不知道的知识,这就是一个实践的过程,有时候你根本不知道错误在哪里,这怎么会是错误的呢,为什么不可以这样写,我觉得这样写才是正确的,这些就是在调试过程中本人的真实心情写照呀。可是,没有那么多为什么,verilog就是这样编程的,只是你不知道而已!这才是最伤人的,因为你不知道!仿真调试的过程中遇到的问题以及解决方法有空专门写一篇,调试的过程中最好是一个一个模块的测试,特别是关键信号的数值,最好搞懂整体模块和各个模块的时序设计过程,推荐使用TimeDesigner进行波形的设计;另外还需要有关联的两个甚至多个不同模块信号的交叉仿真验证。4、与matlab的中值滤波结果进行比较使用matlab编程基于自带的中值滤波函数得到处理之后的图像与数据,并将verilog得到的滤波数据转换为图像,将二者进行比较使用matlab自带的中值滤波函数medfilt2生成原图像的灰度图像的滤波数据;% mcode to median filter for one jpg image, and create a image data filesrc = imread('lena.jpg');gray = rgb2gray(src);medfilt2im = medfilt2( gray ); = size( medfilt2im );                  % m行 n列N = m*n;                               %%数据的长度,即存储器深度。word_len = 8;                        %%每个单元的占据的位数,需自己设定lena_gray = reshape(gray', 1, N);% 1行N列lena_medfilt = reshape(medfilt2im', 1, N);% 1行N列fid_gray=fopen('lena_gray.txt', 'wt');       %打开文件fid_medfilt=fopen('lena_medfilt.txt', 'wt');       %打开文件% fprintf(fid, 'MEMORY_INITIALIZATION_RADIX=16;\n');% fprintf(fid, 'MEMORY_INITIALIZATION_VECTOR=\n');for i = 1 : N-1fprintf(fid_gray, '%d,\n', lena_gray(i));%使用%x表示十六进制数endfprintf(fid_gray, '%d;\n', data(N));               %%输出结尾,每个数据后面用逗号或者空格或者换行符隔开,最后一个数据后面加分号fclose(fid_gray);                            %%关闭文件for i = 1 : N-1fprintf(fid_medfilt, '%d,\n', lena_medfilt(i));%使用%x表示十六进制数endfprintf(fid_medfilt, '%d;\n', lena_medfilt(N));               %%输出结尾,每个数据后面用逗号或者空格或者换行符隔开,最后一个数据后面加分号fclose(fid_medfilt);                            %%关闭文件将medfilt2函数和verilog产生的滤波数据转换为图像,并与matlab直接产生的滤波图像进行对比,代码如下:% code to create image data from txt fileclc;clear all;close all;I_rgb = imread('lena.jpg');subplot(2, 3, 1), imshow(I_rgb), title('lena-rgb')I_gray = rgb2gray(I_rgb);subplot(2, 3, 2), imshow(I_gray), title('lena-gray')medfilt_m_load = load('.\lena_medfilt.txt');%medfilt_m_load = load('.\lena.coe');medfilt_v_load = load('.\medfilter2_reV1.txt'); % verilog 产生的中值滤波之后数据medfilt2im = medfilt2( I_gray );subplot(2, 3, 3), imshow(medfilt2im), title('lena-medfilt2')m = 512;n = 512;medfilt_m = reshape(medfilt_m_load, m, n);medfilt_v = reshape(medfilt_v_load, m, n);medfilt_m = uint8(medfilt_m');medfilt_v = uint8(medfilt_v');aa = medfilt2im - medfilt_m;bb = medfilt2im - medfilt_v;cc = medfilt_m - medfilt_v;subplot(2, 3, 5), imshow(medfilt_m), title('medfilt-matlab');subplot(2, 3, 6), imshow(medfilt_v), title('medfilt-verilog');显示的结果如下图所示:https://ask.qcloudimg.com/http-save/yehe-8131718/hl0w2qhb16.jpeg


结果:两种滤波产生的图像数据完全一致,不过感觉函数直接产生的图像颜色更深一些,不知道为什么。这里需要了解一下medfilt2这个函数的原理。结果数据表明,默认情况下该函数对图像边界采用的是补0的方法进行处理的。

sdlls 发表于 2025-10-29 19:55

这些资料太全了!!!               

updownq 发表于 2025-10-29 19:56

以后学习就方便了                                 

macpherson 发表于 2025-10-29 19:56

资料还是相当全面的                                 

gaochy1126 发表于 2025-10-29 19:56

避免全排序算法,可采用分阶段比较的快速中值提取方法

gaochy1126 发表于 2025-10-29 19:57

中间运算过程需预留足够位宽,例如CIC滤波器的中间字长需根据输入位宽、阶数等通过公式计算

gaochy1126 发表于 2025-10-29 19:57

采用并行处理结构(如多级流水线)提升吞吐量,例如积分器模块每级仅需1个寄存器和1个加法器。

gaochy1126 发表于 2025-10-29 19:57

避免不必要的逻辑冗余,例如抽取模块仅需计数器控制输出周期。

gaochy1126 发表于 2025-10-29 19:57

位宽计算与模块化设计方法见[数字滤波器的MATLAB与FPGA实现]。

jackcat 发表于 2025-10-29 19:57

楼主太好了,非常感谢            

jtracy3 发表于 2025-10-29 19:57

共享的资料比较详细谢谢                                 

sesefadou 发表于 2025-10-29 19:58

共享的资料比较详细谢谢                                 

kkzz 发表于 2025-10-29 19:58

楼主太好了,非常感谢            

uytyu 发表于 2025-10-29 19:59

正准备学习的朋友推荐下载。                                 

lzmm 发表于 2025-10-29 19:59

这些资料太全了!!!               

uiint 发表于 2025-10-29 20:00

共享的资料比较详细谢谢                                 

10299823 发表于 2025-10-29 20:00

正准备学习的朋友推荐下载。                                 

alvpeg 发表于 2025-10-29 20:01

资料很好。谢谢楼主!                                 
页: [1]
查看完整版本: verilog HDL实现中值滤波