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

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

3天内不再提示

基于FPGA的图像中值滤波算法实现方案

FPGA设计论坛 来源:FPGA设计论坛 2026-05-27 09:55 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

一、中值滤波算法原理

中值滤波算法简单来说就是:通过对3x3窗口中的数据进行排序,最终获得中值。

对于待处理的像素,我们选择一个3x3的窗口模板,该窗口内的像素为待处理像素的邻近像素,对窗口内的像素分别按行列排序,最终计算出中值,用该中值代替原像素值,实现中值滤波。

f927a3b4-57f5-11f1-90a1-92fbcf53809c.png

二、基于FPGA设计中值滤波

1.3x3图像窗口生成

卷积是图像处理 中很常见的一种操作,3x3是最常见的窗口大小。

f9824350-57f5-11f1-90a1-92fbcf53809c.jpg

如果像素是一个个来的,要想实现3x3卷积,就得同时获取一个像素和它周围的8个像素,将输入像素缓存2行,这样就能同时获取3行的像素输入,此时再将这3个并行输入的像素移位进3x3窗口,就获得了3x3卷积模板,如图:

f9d5f680-57f5-11f1-90a1-92fbcf53809c.jpg

这里要注意,输入像素此时作为第三行数据输入3x3窗口,最下面的行缓存输出的才是第一行像素,上图窗口的右下角是3x3卷积模板的左上角,窗口的左上角是3x3卷积模板的右下角。

实现两行缓存并获取3x3卷积窗口,用shift-ram是最简单的实现方法。

1.2 shift-ram

1.2.1shift_ram简介

shift-ram是一个ip核,quartus13.0中叫做Shift register(RAM based)

普通shift-ram如图:

fa29d02a-57f5-11f1-90a1-92fbcf53809c.png

带taps的shift-ram:

faa17c74-57f5-11f1-90a1-92fbcf53809c.png

其实带taps的shift-ram就是多个普通shift-ram组合,使用带taps的shift-ram可以轻松实现行缓存,设定taps数量为2,taps间隔为一行的像素数(此处为640),即可缓存两行。之后将这两个taps和输入像素移位进3x3窗口即可获得3x3卷积模板。

1.2.2 shift_ram配置方法

fafc6436-57f5-11f1-90a1-92fbcf53809c.png

三、程序设计

module median_filter (

input clk ,

input rst_n ,

input din_vld ,

input [7:0] din , //输入的图像数据

output [7:0] dout , //输出的图像数据

output dout_vld

);

//打拍

reg [3:0] din_vld_r;

wire [7:0] taps0 ;

wire [7:0] taps1 ;

wire [7:0] taps2 ;

//行同步

reg [7:0] row0_0;

reg [7:0] row0_1;

reg [7:0] row0_2;

reg [7:0] row1_0;

reg [7:0] row1_1;

reg [7:0] row1_2;

reg [7:0] row2_0;

reg [7:0] row2_1;

reg [7:0] row2_2;

//行排列

reg [7:0] row0_min;

reg [7:0] row0_med;

reg [7:0] row0_max;

reg [7:0] row1_min;

reg [7:0] row1_med;

reg [7:0] row1_max;

reg [7:0] row2_min;

reg [7:0] row2_med;

reg [7:0] row2_max;

//列排列

reg [7:0] col0_min;

reg [7:0] col0_med;

reg [7:0] col0_max;

reg [7:0] col1_min;

reg [7:0] col1_med;

reg [7:0] col1_max;

reg [7:0] col2_min;

reg [7:0] col2_med;

reg [7:0] col2_max;

//取出max列的min,med列的med,min列的max

reg [7:0] data_max;

reg [7:0] data_med;

reg [7:0] data_min;

/**************************************************************

四级流水(打四拍)

**************************************************************/

always@(posedge clk or negedge rst_n)

if(!rst_n)

din_vld_r <= 4'd0;

else

din_vld_r <= {din_vld_r[2:0],din_vld};

/**************************************************************

shift_ram(3x3)模块

**************************************************************/

shift_ramshift_ram_inst (

.aclr ( !rst_n ),

.clken ( din_vld ),

.clock ( clk ),

.shiftin ( din ),

.shiftout ( ),

.taps0x ( taps0 ),

.taps1x ( taps1 ),

.taps2x ( taps2 )

);

/**************************************************************

第一级流水

**************************************************************/

//缓存3行数据

always@(posedge clk or negedge rst_n)

if(!rst_n) begin

row0_0 <= 'd0; row0_1 <= 'd0; row0_2 <= 'd0;

row1_0 <= 'd0; row1_1 <= 'd0; row1_2 <= 'd0;

row2_0 <= 'd0; row2_1 <= 'd0; row2_2 <= 'd0;

end

else if(din_vld_r[0]) begin

row0_0 <= taps0; row0_1 <= row0_0; row0_2 <= row0_1;

row1_0 <= taps1; row1_1 <= row1_0; row1_2 <= row1_1;

row2_0 <= taps2; row2_1 <= row2_0; row2_2 <= row2_1;

end

/**************************************************************

第二级流水

**************************************************************/

//三行分别排序

always@(posedge clk or negedge rst_n)

if(!rst_n) begin

row0_min <= 'd0;row0_med <= 'd0;row0_max <= 'd0;

row1_min <= 'd0;row1_med <= 'd0;row1_max <= 'd0;

row2_min <= 'd0;row2_med <= 'd0;row2_max <= 'd0;

end

else if(din_vld_r[1]) begin

COMPARE(row0_0,row0_1,row0_2,row0_max,row0_med,row0_min);

COMPARE(row1_0,row1_1,row1_2,row1_max,row1_med,row1_min);

COMPARE(row2_0,row2_1,row2_2,row2_max,row2_med,row2_min);

end

/**************************************************************

第三级流水

**************************************************************/

//每一行排完后,取出

//第一列的最小值

//第二列的中间值

//第三列的最大值

always@(posedge clk or negedge rst_n)

if(!rst_n) begin

col0_min <= 'd0;

col1_med <= 'd0;

col0_max <= 'd0;

end

else if(din_vld_r[2]) begin

COMPARE(row0_max,row1_max,row2_max,col0_max,col0_med,col0_min);

COMPARE(row0_med,row1_med,row2_med,col1_max,col1_med,col1_min);

COMPARE(row0_min,row1_min,row2_min,col2_max,col2_med,col2_min);

end

/**************************************************************

第四级流水

**************************************************************/

//得到最终的中值

always@(posedge clk or negedge rst_n)

if(!rst_n) begin

data_max <= 'd0;

data_med <= 'd0;

data_min <= 'd0;

end

else if(din_vld_r[3])begin

COMPARE(col0_min,col1_med,col2_max,data_max,data_med,data_min);

end

//输出端口

assign dout = data_med;

assign dout_vld = din_vld_r[3];

/**************************************************************

COMPARE任务

**************************************************************/

//用于比较三个数的大小并排列

task COMPARE;

input [7:0] data1 ;

input [7:0] data2 ;

input [7:0] data3 ;

output [7:0] max ;

output [7:0] mid ;

output [7:0] min ;

begin

//max

if(data1 >= data2 && data1 >= data3)

max = data1;

else if(data2 >= data1 && data2 >= data3)

max = data2;

else

max = data3;

//med

if((data1 >= data2 && data1 <= data3) || (data1 >= data3 && data1 <= data2))

mid = data1;

else if((data2 >= data1 && data2 <= data3) || (data2 >= data3 && data2 <= data1))

mid = data2;

else

mid = data3;

//min

if(data1 <= data2 && data1 <= data3)

min = data1;

else if(data2 <= data1 && data2 <= data3)

min = data2;

else

min = data3;

end

endtask

endmodule

四、仿真测试

fb510752-57f5-11f1-90a1-92fbcf53809c.png

fba65086-57f5-11f1-90a1-92fbcf53809c.png

4.1 代码逻辑功能仿真

首先对设计的代码单独进行仿真观察波形,看中值滤波功能是否正常执行

4.1.1 median_filter_tb

4.1.1.1 测试代码

`timescale 1ns/1ps

module median_filter_tb();

parameter CLK_CYCLE = 20;

regsys_clk,sys_rst_n;

reg din_vld;

reg [7:0] din;

always #(CLK_CYCLE/2) sys_clk = ~sys_clk;

initial begin

sys_clk = 1'b1;

sys_rst_n = 1'b0;

#(CLK_CYCLE*2);

sys_rst_n = 1'b1;

end

median_filter median_filter_tb(

/* input */ .clk (sys_clk),

/* input */ .rst_n (sys_rst_n),

/* input */ .din_vld (din_vld),

/* input [7:0] */ .din (din),

/* output [7:0] */ .dout (),

/* output */ .dout_vld()

);

integer i;

initial begin

din = 8'b0;

din_vld =1'b0;

#(CLK_CYCLE*20);

for(i=0;i<500;i=i+1)begin

din_vld = 1'b1;

din = {$random}%100;

@(posedge sys_clk);

end

din_vld = 1'b0;

#(CLK_CYCLE*200)

$stop(2);

end

endmodule

一键获取完整项目代码

4.1.1.1 仿真波形

观察每级流水波形,看每级流水功能是否正常。若哪级流水错误,则去修改该级流水代码逻辑,直到功能正常。

4.1.2 test_image

4.1.2.1 测试代码

仿真代码中涉及的系统函数可参考:Verilog 系统函数

`timescale 1ns/1ps

module test_image();

parameter CLK_CYCLE = 20;

regclk,rst_n;

always #(CLK_CYCLE/2) clk = ~clk;

initial begin

clk = 1'b1;

rst_n = 1'b0;

#(CLK_CYCLE*2);

rst_n = 1'b1;

end

reg [7:0] din;

reg din_vld;

wire [7:0] dout;

wire dout_vld;

median_filter med_filter_inst(

/* input */ .clk (clk),

/* input */ .rst_n (rst_n),

/* input */ .din_vld (din_vld),

/* input [7:0] */ .din (din ),

/* output [7:0] */ .dout (dout ),

/* output */ .dout_vld(dout_vld)

);

integer bmp_width;//图像宽度

integer bmp_high;//图像高度

integer bmp_size;//图像尺寸

integer start_index;//图像像素点起始位

//bmp file id

integer bmp_file_id;

integer bmp_dout_id;

integer dout_txt_id;

integer h;//文件句柄

reg [7:0] rd_data [0:921600];//bmp文件图片大小

reg [7:0] dout_data [0:921600];

//写操作

reg[23:0]wr_data;

integer i = 0;

integer index,index0;

initial begin

din_vld = 0;

#(CLK_CYCLE*10)

//打开原始图像$fopen("原始图像地址,文件夹间用\隔开","命令码")

bmp_file_id = $fopen("E:\Material\IntelFPGA\test\test6\median_filter\sim\in_bmp.bmp","rb");

//打开输出图像

bmp_dout_id = $fopen("E:\Material\IntelFPGA\test\test6\median_filter\sim\out_bmp.bmp","wb");

//打开输出数据

dout_txt_id = $fopen("E:\Material\IntelFPGA\test\test6\median_filter\sim\out.img.txt","w+");

//读取bmp文件

h = $fread(rd_data,bmp_file_id);

// 图像宽度

bmp_width = {rd_data[21], rd_data[20], rd_data[19], rd_data[18]};

// 图像高度

bmp_high = {rd_data[25], rd_data[24], rd_data[23], rd_data[22]};

// 像素起始位置

start_index = {rd_data[13], rd_data[12], rd_data[11], rd_data[10]};

// 图像尺寸

bmp_size = {rd_data[5], rd_data[4], rd_data[3], rd_data[2]};

// bmp_size = 921600;

$fclose(bmp_file_id);

index = start_index;

//重复1280次,1280个像素点

repeat(1280)begin

#(CLK_CYCLE*1);

din = rd_data[index];

din_vld = 1;

index = index + 1;

end

repeat(bmp_size-1280)begin

#(CLK_CYCLE*1);

dout_data[index-1280] = dout;

din = rd_data[index];

index = index + 1;

end

din_vld = 0;

// repeat(1280)begin

// #(CLK_CYCLE*1);

// dout_data[index-1280] = dout;

// din = rd_data[index];

// index = index + 1;

// end

//输出BMP

for(i = 0; i < bmp_size; i = i + 1)begin

if(i < start_index)

$fwrite(bmp_dout_id, "%c", rd_data[i]);//注意参数%c

else

$fwrite(bmp_dout_id, "%c", dout_data[i]);

end

$fclose(bmp_dout_id);

//输出txt,只存像素点

for(index0 = start_index; index0 < bmp_size-2; index0 = index0 + 3)begin

wr_data = {dout_data[index0 + 2], dout_data[index0 + 1], dout_data[index0]};

$fwrite(dout_txt_id, "%d,", wr_data[7:0]);

$fwrite(dout_txt_id, "%d,", wr_data[15:8]);

$fwrite(dout_txt_id, "%d ", wr_data[23:16]);

end

$fclose(dout_txt_id);

$stop;

end

endmodule

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

    关注

    1665

    文章

    22577

    浏览量

    640950
  • 滤波算法
    +关注

    关注

    2

    文章

    98

    浏览量

    14503

原文标题:基于FPGA的图像中值滤波

文章出处:【微信号:gh_9d70b445f494,微信公众号:FPGA设计论坛】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    FPGA verilog HDL实现中值滤波

    今天给大侠简单带来FPGA verilog HDL实现中值滤波,话不多说,上货。一、实现步骤: 1、查看了
    发表于 06-18 18:50

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

    ` 本帖最后由 ninghechuan 于 2017-8-30 08:20 编辑 我们为了实现动态图像滤波算法,用串口发送图像数据到
    发表于 08-28 11:34

    基于FPGA中值滤波算法实现

    ` 本帖最后由 ninghechuan 于 2017-9-1 07:04 编辑 在这一篇开篇之前,我需要解决一个问题,上一篇我们实现了基于FPGA的均值滤波算法
    发表于 09-01 07:04

    基于FPGA的腐蚀膨胀算法实现

    :基于FPGA的均值滤波算法实现第五篇:深刻认识ShiftRAM学习笔记番外篇:数字图像处理界标准图像
    发表于 09-22 13:20

    请问如何实现改进的中值滤波器的设计?

    如何实现改进的中值滤波器的设计?中值滤波的基本原理是什么?中值
    发表于 04-14 06:54

    基于医学图像的有效中值滤波算法研究

    本文对于由Visible Human 所提供的人体CT 图像序列所形成的体数据场,提出了一种有效的快速中值滤波方法。中值滤波是一种非常有用的
    发表于 08-13 14:39 10次下载

    一种基于FPGA图像中值滤波器的硬件实现

    一种基于FPGA图像中值滤波器的硬件实现:随着超大规模集成电路(VLSI) 技术的不断发展,图像
    发表于 11-01 15:18 31次下载

    快速中值滤波FPGA实现

    中值滤波算法说明: 系统获取的图像在形成、传输、接收和处理的过程中,不可避免地存在着外部干扰和内部干扰。各种噪声随之而来,如图像传感器、
    发表于 03-25 15:10 234次下载

    测井图像的多级中值滤波算法及其FPGA实现

    微电阻率成像测井仪传输上来的地层信息数据需要滤波处理后才能真实地反映出地层中油层的信息,而中值滤波图像预处理中常用的技术。本文介绍了标准中值
    发表于 12-31 09:20 8次下载

    基于FPGA的实时图像中值滤波算法实现_蒋涛

    基于FPGA的实时图像中值滤波算法实现_蒋涛
    发表于 03-19 11:38 15次下载

    图像加窗中值滤波算法的研究分析

    提出了一种实用的图像滤波算法,即图像加窗中值滤波算法
    发表于 11-30 11:11 4次下载
    <b class='flag-5'>图像</b>加窗<b class='flag-5'>中值</b><b class='flag-5'>滤波</b><b class='flag-5'>算法</b>的研究分析

    基于FPGA图像调焦算法实现方案

    利用图像处理方法进行自动调焦的关键是提取图像清晰度特征,并建立其评价算法。本文研究了灰度值线性变换、灰度直方图均衡、中值滤波及同态
    发表于 03-19 16:45 16次下载
    基于<b class='flag-5'>FPGA</b>的<b class='flag-5'>图像</b>调焦<b class='flag-5'>算法</b>的<b class='flag-5'>实现</b><b class='flag-5'>方案</b>

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

    中值滤波和多级中值滤波的特点和适用范围,针对滤波算法的邻域性特点,设计了基于
    发表于 04-01 11:21 42次下载
    如何使用<b class='flag-5'>FPGA</b><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>

    labview图像中值滤波实例分享

    labview图像中值滤波实例分享
    发表于 12-15 14:55 38次下载

    2D中值滤波算法的设计实现

    该项目包含使用高级综合 (HLS) 的 2D 中值滤波算法实现。该项目的目标是在不到 3 ms的时间内对测试图像进行去噪,同时消耗不到
    的头像 发表于 07-12 15:19 1816次阅读
    2D<b class='flag-5'>中值</b><b class='flag-5'>滤波</b><b class='flag-5'>算法</b>的设计<b class='flag-5'>实现</b>