0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

灰度图像均值滤波算法的HDL实现介绍

FPGA之家 来源:FPGA之家 2023-10-16 09:23 次阅读

1.1均值滤波算法介绍

首先要做的是最简单的均值滤波算法。均值滤波是典型的线性滤波算法,它是指在图像上对目标像素给一个模板,该模板包括了其周围的临近像素(以目标象素为中心的周围8个像素,构成一个滤波模板,即去掉目标像素本身),再用模板中的全体像素的平均值来代替原来像素值。

P11 P12 P13
P21 P23
P31 P32 P33

中值滤波算法可以形象的用上述表格来描述,即对于每个3*3的阵列而言,中间像素的值,等于边缘8个像素的平均值。算法的理论很简单,对于C处理器而言,一幅640*480图像的均值滤波,可以很方便的通过数组获得3*3的阵列,但对于我们的Verilog HDL而言,着实不易。

1.23*3像素阵列的HDL实现

3*3阵列的获取,大概有以下三种方式:

(1)通过2个或3个RAM的存储,来实现3*3像素阵列;

(2)通过2个或3个FIFO的存储,来实现3*3像素阵列;

(3)通过2行或3行Shift_RAM的移位存储,来实现3*3像素阵列。

不过经验告诉大家,最方便的实现方式,非Shift_RAM莫属了,都感觉Shift_RAM甚至是为实现3*3阵列而生的!

Quartus II中,可以利用下图方式产生,很方便:

首先介绍一下Shift_RAM,宏定义模块如下图所示:

a2f3310c-6b30-11ee-939d-92fbcf53809c.png

图6‑1 QuartusII Shift_RAM IP使用界面

Shift_RAM可定义数据宽度、移位的行数、每行的深度。这里我们固然需要8Bit,640个数据每行,同时移位寄存2行即可(原因看后边)。同时选择时钟使能端口clken。详细的关于Shift_RAM的手册参数,可在宏定义窗口右上角Document中查看,如下:

a3083606-6b30-11ee-939d-92fbcf53809c.png

手册给出了一个非常形象的移位寄存示意图,如下所示:

a318ddc6-6b30-11ee-939d-92fbcf53809c.png

图6‑2移位寄存示意图

实现3*3像素阵列的大概的思路是这样子的,Shift_RAM中存2行数据,同时与当前输入行的数据,组成3行的阵列。

在Vivado中就没有类似的IP,但是难不倒我,可以利用成熟的IP核实现类似上诉的移位寄存器

在《Image�06_OV5640_DDR3_Gray_Mean_FilterOV5640_DEMOuserlinebuffer_Wapper》

中实现的就是移位寄存器功能的IP,使用方法类似上诉QuartusII中的使用。

例化方式如下:

代码6‑1

1.//---------------------------------------
2.//moduleofshiftramforrawdata
3.wireshift_clk_en=per_frame_clken;
4.
5.linebuffer_Wapper#
6.(
7..no_of_lines(2),
8..samples_per_line(640),
9..data_width(8)
10.)
11.linebuffer_Wapper_m0(
12..ce(1'b1),
13..wr_clk(clk),
14..wr_en(shift_clk_en),
15..wr_rst(rst_n),
16..data_in(row3_data),
17..rd_en(shift_clk_en),
18..rd_clk(clk),
19..rd_rst(rst_n),
20..data_out({row2_data,row1_data})
21.);

源码VIP_Matrix_Generate_3X3_8Bit文件中实现8Bit宽度的3*3像素阵列功能。具体的实现步骤如下:

(1)首先,将输入的信号用像素使能时钟同步一拍,以保证数据与Shift_RAM输出的数据保持同步,如下:

代码6‑2

1.//Generate3*3matrix
2.//--------------------------------------------------------------------------
3.//--------------------------------------------------------------------------
4.//--------------------------------------------------------------------------
5.//syncrow3_datawithper_frame_clken&row1_data&raw2_data
6.wire[7:0]row1_data;//framedataofthe1throw
7.wire[7:0]row2_data;//framedataofthe2throw
8.reg[7:0]row3_data;//framedataofthe3throw
9.always@(posedgeclkornegedgerst_n)
10.begin
11.if(!rst_n)
12.row3_data<= 0;  
13.else
14.begin
15.if(per_frame_clken)
16.row3_data<= per_img_Y;  
17.else
18.row3_data<= row3_data;  
19.end
20.end

(2)接着,例化并输入row3_data,此时可从Modelsim中观察到3行数据同时存在了,HDL如下:

代码6‑3 QuartusII例化移位寄存器代码

1.//---------------------------------------
2.//moduleofshiftramforrawdata
3.wireshift_clk_en=per_frame_clken;
4.Line_Shift_RAM_8Bit
5.#(
6..RAM_Length(IMG_HDISP)
7.)
8.u_Line_Shift_RAM_8Bit
9.(
10..clock(clk),
11..clken(shift_clk_en),//pixelenableclock
12.//.aclr(1'b0),
13..shiftin(row3_data),//Currentdatainput
14..taps0x(row2_data),//Lastrowdata
15..taps1x(row1_data),//Uparowdata
16..shiftout()
17.);

代码6‑4 Vivado例化移位寄存器代码

22.//---------------------------------------
23.//moduleofshiftramforrawdata
24.wireshift_clk_en=per_frame_clken;
25.
26.linebuffer_Wapper#
27.(
28..no_of_lines(2),
29..samples_per_line(640),
30..data_width(8)
31.)
32.linebuffer_Wapper_m0(
33..ce(1'b1),
34..wr_clk(clk),
35..wr_en(shift_clk_en),
36..wr_rst(rst_n),
37..data_in(row3_data),
38..rd_en(shift_clk_en),
39..rd_clk(clk),
40..rd_rst(rst_n),
41..data_out({row2_data,row1_data})
42.);

在经过Shift_RAMd移位存储后,我们得到的row0_data,row1_data,row2_data的仿真示意图如下所示:

a32b811a-6b30-11ee-939d-92fbcf53809c.png

图6‑3ModelSim仿真截图

数据从row3_data输入,满3行后刚好唯一3行阵列的第一。从图像第三行输入开始,到图像的最后一行,我们均可从row_data得到完整的3行数据,基为实现3*3阵列奠定了基础。不过这样做有2个不足之处,即第一行与第二行不能得到完整的3*3阵列。但从主到次,且不管算法的完美型,我们先验证3X3模板实现的正确性。因此直接在行有效期间读取3*3阵列,机器方便快捷的实现了我们的目的。

(3)Row_data读取信号的分析及生成

这里涉及到了一个问题,数据从Shift_RAM存储耗费了一个时钟,因此3*3阵列的读取使能与时钟,需要进行一个clock的偏移,如下所示:

代码6‑5

1.//------------------------------------------
2.//lag2clockssignalsync
3.reg[1:0]per_frame_vsync_r;
4.reg[1:0]per_frame_href_r;
5.reg[1:0]per_frame_clken_r;
6.always@(posedgeclkornegedgerst_n)
7.begin
8.if(!rst_n)
9.begin
10.per_frame_vsync_r<= 0;  
11.per_frame_href_r<= 0;  
12.per_frame_clken_r<= 0;  
13.end
14.else
15.begin
16.per_frame_vsync_r<=   {per_frame_vsync_r[0],  per_frame_vsync};  
17.per_frame_href_r<=   {per_frame_href_r[0],   per_frame_href};  
18.per_frame_clken_r<=   {per_frame_clken_r[0],  per_frame_clken};  
19.end
20.end
21.//Giveupthe1thand2throwedgedatacaculateforsimpleprocess
22.//Giveupthe1thand2thpointof1lineforsimpleprocess
23.wireread_frame_href=per_frame_href_r[0];//RAMreadhrefsyncsignal
24.wireread_frame_clken=per_frame_clken_r[0];//RAMreadenable
25.assignmatrix_frame_vsync=per_frame_vsync_r[1];
26.assignmatrix_frame_href=per_frame_href_r[1];
27.assignmatrix_frame_clken=per_frame_clken_r[1];

(4)Okay,此时根据read_frame_href与read_frame_clken信号,直接读取3*3像素阵列。读取的HDL实现如下:

代码6‑6

1. //----------------------------------------------------------------------------
2. //----------------------------------------------------------------------------
3. /******************************************************************************
4. ----------ConvertMatrix----------
5. [P31->P32->P33->]--->[P11P12P13]
6. [P21->P22->P23->]--->[P21P22P23]
7. [P11->P12->P11->]--->[P31P32P33]
8. ******************************************************************************/
9. //---------------------------------------------------------------------------
10. //---------------------------------------------------
11. /***********************************************
12. (1)ReaddatafromShift_RAM
13. (2)CaculatetheSobel
14. (3)SteadydataafterSobelgenerate
15. ************************************************/
16. //wire[23:0]matrix_row1={matrix_p11,matrix_p12,matrix_p13};//Justfortest
17. //wire[23:0]matrix_row2={matrix_p21,matrix_p22,matrix_p23};
18. //wire[23:0]matrix_row3={matrix_p31,matrix_p32,matrix_p33};
19. always@(posedgeclkornegedgerst_n)
20. begin
21. if(!rst_n)
22. begin
23. {matrix_p11,matrix_p12,matrix_p13}<= 24'h0;  
24. {matrix_p21,matrix_p22,matrix_p23}<= 24'h0;  
25. {matrix_p31,matrix_p32,matrix_p33}<= 24'h0;  
26. end
27. elseif(read_frame_href)
28. begin
29. if(read_frame_clken)//Shift_RAMdatareadclockenable
30. begin
31. {matrix_p11,matrix_p12,matrix_p13}<= {matrix_p12, matrix_p13, row1_data}; //1th shift input  
32. {matrix_p21,matrix_p22,matrix_p23}<= {matrix_p22, matrix_p23, row2_data}; //2th shift input  
33. {matrix_p31,matrix_p32,matrix_p33}<= {matrix_p32, matrix_p33, row3_data}; //3th shift input  
34. end
35. else
36. begin
37. {matrix_p11,matrix_p12,matrix_p13}<= {matrix_p11, matrix_p12, matrix_p13};  
38. {matrix_p21,matrix_p22,matrix_p23}<= {matrix_p21, matrix_p22, matrix_p23};  
39. {matrix_p31,matrix_p32,matrix_p33}<= {matrix_p31, matrix_p32, matrix_p33};  
40. end
41. end
42. else
43. begin
44. {matrix_p11,matrix_p12,matrix_p13}<= 24'h0;  
45. {matrix_p21,matrix_p22,matrix_p23}<= 24'h0;  
46. {matrix_p31,matrix_p32,matrix_p33}<= 24'h0;  
47. end
48. end

最后得到的matrix_p11、p12、p13、p21、p22、p23、p31、p32、p33即为得到的3*3像素阵列,仿真时序图如下所示:

a33c0c92-6b30-11ee-939d-92fbcf53809c.png

前面Shift_RAM存储耗费了一个时钟,同时3*3阵列的生成耗费了一个时钟,因此我们需要人为的将行场信号、像素使能读取信号移动2个时钟,如下所示:

assign matrix_frame_vsync =per_frame_vsync_r[1];

assign matrix_frame_href =per_frame_href_r[1];

assign matrix_frame_clken =per_frame_clken_r[1];

至此我们得到了完整的3*3像素阵列的模块,同时行场、使能时钟信号与时序保持一致,Modelsim仿真图如下所示:

a35689dc-6b30-11ee-939d-92fbcf53809c.png

1.3Mean_Filter均值滤波算法的实现

不过相对于3*3像素阵列的生成而言,均值滤波的算法实现反而难度小的多,只是技巧性的问题。

继续分析上面这个表格。其实HDL完全有这个能力直接计算8个值相加的均值,不过为了提升电路的速度,建议我们需要通过以面积换速度的方式来实现。So这里需要3个步骤:

(1)分别计算3行中相关像素的和;

(2)计算(1)中三个结果的和;

在(2)运算后,我们不能急着用除法去实现均值的运算。记住,能用移位替换的,绝对不用乘除法来实现。这里8个像素,即除以8,可以方便的用右移动3Bit来实现。不过这里更方便的办法是,直接提取mean_value4[10:3]。

这一步我们不单独作为一个Step,而是直接作为结果输出。分析前面的运算,总共耗费了2个时钟,因此需要将行场信号、像素读取信号偏移2个时钟,同时像素时钟,根据行信号使能,直接读取mean_value4[10:3],如下所示:

这样,我们便得到了运算后的时序,实现了均值滤波算法。

最后,在Video_Image_Processor顶层文件中例化Gray_Mean_Filter算法模块,完成算法的添加。

最后直接将生成的post_img_Y输入给24Bit的DDR控制器即可。









审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • RAM
    RAM
    +关注

    关注

    7

    文章

    1322

    浏览量

    113708
  • HDL
    HDL
    +关注

    关注

    8

    文章

    324

    浏览量

    47104
  • 移位寄存器
    +关注

    关注

    2

    文章

    182

    浏览量

    22021
  • 滤波算法
    +关注

    关注

    2

    文章

    82

    浏览量

    13661
  • FIFO存储
    +关注

    关注

    0

    文章

    102

    浏览量

    5895

原文标题:灰度图像的均值滤波算法的 HDL 实现

文章出处:【微信号:zhuyandz,微信公众号:FPGA之家】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    基于FPGA的均值滤波算法实现

      我们为了实现动态图像滤波算法,用串口发送图像数据到FPGA开发板,经FPGA进行图像处理
    发表于 01-02 16:26 4754次阅读

    数字图像空域滤波算法的FPGA设计

    空域滤波算法图像增强技术的一种,直接对图像的象素进行处理,不需要进行变换。常见的滤波算子如锐化算子、高通算子、平滑算子等,可以完成
    发表于 02-24 14:20

    基于FPGA的HDTV视频图像灰度直方图统计算法设计

    本文介绍了如何在FPGA 中利用Block RAM 的特殊结构实现HDTV 视频增强算法灰度直方图统计。灰度直方图统计
    发表于 05-14 12:37

    请教一种可识别未受污染点的中值/均值滤波matlab程序

    小弟最近需要学习一种关于灰度图像去噪的改进算法,它需要在原始的中值滤波或者均值滤波器上加以改进,
    发表于 03-30 17:06

    基于FPGA的均值滤波算法实现

    均值滤波如图所示,我们要进行均值滤波首先要生成一个3x3矩阵。算法运算窗口一般采用奇数点的邻域来计算中值,最常用的窗口有3X3和5X5模型
    发表于 08-28 11:34

    基于FPGA的中值滤波算法实现

    均值滤波算法实现第五篇:深刻认识Shift RAM学习笔记番外篇:数字图像处理界标准图像 Le
    发表于 09-01 07:04

    数字图像空域滤波算法的FPGA设计与实现

    本文采用的图像是256×256大小的灰度图像滤波模板3×3大小。如何设计硬件电路来完成上述空域滤波算法
    发表于 01-18 12:12 850次阅读
    数字<b class='flag-5'>图像</b>空域<b class='flag-5'>滤波</b><b class='flag-5'>算法</b>的FPGA设计与<b class='flag-5'>实现</b>

    灰度相关和区域特征的图像拼接算法

    本文提出一种结合灰度特点和区域特征的图像拼接算法。首先采用灰度直方图均衡化的方法降低光照条件不同造成的灰度差异;其次为减少匹配块的计算量,在
    发表于 03-07 15:34 60次下载
    <b class='flag-5'>灰度</b>相关和区域特征的<b class='flag-5'>图像</b>拼接<b class='flag-5'>算法</b>

    一种加权均值滤波的改进算法

    根据椒盐噪声污染图像灰度值取值范围的变化,提出了一种改进的加权均值滤波算法。实验结果表明,该方法能有效地去除椒盐噪声,同时保留了
    发表于 05-16 17:37 49次下载

    图像分割的非局部均值去噪算法

    针对传统非局部均值(NLM)算法滤波参数非自适应及去噪后边缘易模糊的缺点,提出一种基于图像分割的非局部均值去噪
    发表于 11-30 14:19 1次下载
    <b class='flag-5'>图像</b>分割的非局部<b class='flag-5'>均值</b>去噪<b class='flag-5'>算法</b>

    均值滤波均值滤波算法程序

    均值滤波是典型的线性滤波算法,它是指在图像上对目标像素给一个模板,该模板包括了其周围的临近像素(以目标像素为中心的周围个像素,构成一个
    发表于 12-19 15:35 6455次阅读

    基于FPGA灰度图像高斯滤波算法实现

    FPGA仿真篇-使用脚本命令来加速仿真二 基于FPGA的HDMI高清显示借口驱动 基于FPGA灰度图像高斯滤波算法实现 FPGA为什么比C
    发表于 02-20 20:49 7317次阅读
    基于FPGA<b class='flag-5'>灰度</b><b class='flag-5'>图像</b>高斯<b class='flag-5'>滤波</b><b class='flag-5'>算法</b>的<b class='flag-5'>实现</b>

    如何使用FPGA实现图像灰度级拉伸算法

    为了调整图像数据灰度介绍了一种图像灰度级拉伸算法的FPGA
    发表于 04-01 14:14 10次下载
    如何使用FPGA<b class='flag-5'>实现</b><b class='flag-5'>图像</b><b class='flag-5'>灰度</b>级拉伸<b class='flag-5'>算法</b>

    如何使用FPGA实现图像灰度级拉伸算法

    为了调整图像数据灰度介绍了一种图像灰度级拉伸算法的FPGA
    发表于 04-01 14:14 1次下载
    如何使用FPGA<b class='flag-5'>实现</b><b class='flag-5'>图像</b><b class='flag-5'>灰度</b>级拉伸<b class='flag-5'>算法</b>

    详解从均值滤波到非局部均值滤波算法的原理及实现方式

    将再啰嗦一次,详解从均值滤波到非局部均值滤波算法的原理及实现方式。 细数主要的2D降噪
    的头像 发表于 12-19 16:30 365次阅读