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

    文章

    1195

    浏览量

    113052
  • HDL
    HDL
    +关注

    关注

    8

    文章

    310

    浏览量

    46941
  • 移位寄存器
    +关注

    关注

    2

    文章

    145

    浏览量

    21838
  • 滤波算法
    +关注

    关注

    2

    文章

    76

    浏览量

    13588
  • FIFO存储
    +关注

    关注

    0

    文章

    94

    浏览量

    5869
收藏 人收藏

    评论

    相关推荐

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

    滤波算法图像增强威廉希尔官方网站 的一种,直接对图像的象素进行处理,不需要进行变换。常见的滤波算子如锐化算子、高通算子、平滑算子等,可以完成图像的边缘提取、噪声去除等处理。这些滤波算子尽管功能不同,
    发表于 02-24 14:20

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

    介绍了如何在FPGA 中利用Block RAM 的特殊结构实现HDTV 视频增强算法灰度直方图统计。灰度直方图统计灰度直方图统计是图像处理过程中很常用的一个步骤,简单来讲,就是对一幅图像各个
    发表于 05-14 12:37

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

    灰度图像去噪的改进算法,它需要在原始的中值滤波或者均值滤波器上加以改进,达到这样的要求:1.判断图像中哪些点是受污染的点2.若受污染,则用简单的中值/均值滤波算法处理3.若未受污染,则保持原样劳烦
    发表于 03-30 17:06

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

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

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

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

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

    灰度特点和区域特征的图像拼接算法。首先采用灰度直方图均衡化的方法降低光照条件不同造成的灰度差异;其次为减少匹配块的计算量,在选取的特征块上计算灰度均值和每个像素与平均值的绝对差值,然后通过控制阈值来减小搜索范围;最后引入
    发表于 03-07 15:34 60次下载
    <b>灰度</b>相关和区域特征的<b>图像</b>拼接<b>算法</b>

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

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

    MATLAB实现图像中值 均值 维纳滤波 源程序代码

    图像处理的算法,其中有关于中值、均值、维纳各种滤波代码的源程序;真的不错,可以下载。
    发表于 04-15 11:17 8次下载

    如何使用FPGA实现图像的中值滤波算法

    图像滤波图像预处理过程中苇要的组成部分,而基于FPGA的滤波算法相对软件算法而言具有高度的并行性。能满足实时图像处理的要求.同时也具有灵活的硬件可编程性;简要说明了中值滤波的原理.介绍并比较了标准
    发表于 04-01 11:21 41次下载
    如何使用FPGA<b>实现</b><b>图像</b>的中值<b>滤波</b><b>算法</b>

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

    图像数据灰度介绍了一种图像灰度级拉伸算法的FPGA实现方法,并针对FPGA的特点对算法实现方法进行了研究,从而解决了其在导引系统应用中的实时性问题。仿真验证结果表明:基于FPGA的图像拉伸算法
    发表于 04-01 14:14 1次下载
    如何使用FPGA<b>实现</b><b>图像</b><b>灰度</b>级拉伸<b>算法</b>

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

    图像是256×256大小的灰度图像滤波模板3×3大小。如何设计硬件电路来完成上述空域滤波算法,分析上述算法实现过程,可以得出结论,实现空域滤波算法可采用3个三阶的FIR滤波器+延时
    发表于 01-18 12:12 793次阅读
    数字<b>图像</b>空域<b>滤波</b><b>算法</b>的FPGA设计与<b>实现</b>

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

    均值滤波是典型的线性滤波算法,它是指在图像上对目标像素给一个模板,该模板包括了其周围的临近像素(以目标像素为中心的周围个像素,构成一个滤波模板,即去掉目标像素本身),再用模板中的全体像素的平均值来代替原来像素值。
    发表于 12-19 15:35 6143次阅读

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

    灰度图像高斯滤波算法实现 FPGA为什么比CPU和GPU快 基于Xilinx FPGA的视频图像采集
    发表于 02-20 20:49 7078次阅读
    基于FPGA<b>灰度</b><b>图像</b>高斯<b>滤波</b><b>算法</b>的<b>实现</b>

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

    实现动态图像滤波算法,用串口发送图像数据到FPGA开发板,经FPGA进行图像处理算法后,动态显示到VGA显示屏上,前面我们把硬件平台已经搭建完成了,后面我们将利用这个硬件基础平台
    发表于 01-02 16:26 4538次阅读