FPGA图像处理仿真实验——均值滤波(FIFO)

news2024/12/29 2:42:24

        之前的博客中用shift ram做的均值滤波,那篇文章里讲了原理,在这里不进行重复。考虑到shift ram的深度有限,在处理高分辨率图片时可能会收到限制,所以这次采用FIFO来进行均值滤波。FIFO可以看成是一个先进先出的堆栈,有两个独立的读使能信号和写使能信号,每写入一个数据,写地址加一,每读出一个数据,读地址加一。FIFO的难点在于空信号和满信号的判断,这个可以参考网上其他的讲解原理,在进行仿真实验时可以直接调用IP核,比较方便。在通过3*3的滑动窗口对图像进行处理时,需要进行图像边界补充操作。之前用shift ram做均值滤波的那篇文章是在图像的边界进行补0,而这篇文章选择复制的方法进行边界补充。中值滤波和均值滤波大致代码相同,可以参考之前的均值滤波和中值滤波,对本文代码进行修改,实现中值滤波的功能。

1、FIFO IP核设置

        FIFO IP核的设置比较简单,要搞清楚两种Read Mode用什么区别。Standard FIFO模式,读出的数据会滞后读使能信号一个时钟周期;First Word Fall Through模式,第一个写入的数据将被提前读出来放在数据线上(也可以理解成放在寄存器里)。这两个模式都可以完成功能,只是在最后信号对齐上延迟的时钟周期不同,本文选择First Word Fall Through模式。数据的宽度和深度根据处理图片的大小更改即可,IP核配置如下:

 

 2、边界复制

        边界复制需要对图像的第一行、最后一行、第一列、最后一列进行复制。加入一个行计数器,在行计数器为1时,将row2_data复制给row1_data,来完成第一行的复制(row3_data代表输入图像的数据,row2_data代表前一行数据,row1_data代表前两行数据)。在图像最后一行数据输入完成后,将row2_data数据复制给row3_data,完成最后一行的复制。对列边界的复制在计算3*3矩阵每一行数据和的时候完成。加入一个列计数器,当列计数器为1时,将3*3矩阵的第一列的值用第二列代替,完成第一列的复制。当列计数器为640(图像宽度)时,将3*3矩阵的第二列的值用第三列代替,完成最后一列的复制。

3、代码

 3*3矩阵生成模块

module generate_3_3(
    input				clk,  				//cmos video pixel clock
	input				rst_n,				//global reset

	//Image data prepred to be processd
	input				per_frame_vsync,	//Prepared Image data vsync valid signal
	input				per_frame_href,		//Prepared Image data href vaild  signal
	input				per_frame_clken,	//Prepared Image data output/capture enable clock
	input		[7:0]	per_img_Y,			//Prepared Image brightness input

	//Image data has been processd
	output				matrix_frame_vsync,	//Prepared Image data vsync valid signal
	output				matrix_frame_href,	//Prepared Image data href vaild  signal
	output				matrix_frame_clken,	//Prepared Image data output/capture enable clock	
	output	reg	[7:0]	matrix_p11, matrix_p12, matrix_p13,	
	output	reg	[7:0]	matrix_p21, matrix_p22, matrix_p23,
	output	reg	[7:0]	matrix_p31, matrix_p32, matrix_p33
    );
parameter [10:0] delay=11'd1310;     
wire [7:0] row1_data;
wire [7:0] row2_data;
wire [7:0] row3_data;
wire [7:0] row1_data1;
wire [7:0] row2_data1;
wire row2_rd_en;
wire row1_rd_en;
wire row2_wr_en;
wire row1_wr_en;
wire [9:0] data_count1,data_count2;
reg [8:0] row_cnt;
reg per_frame_href_delay;
wire [7:0] fifo_in;
reg [delay-1:0] per_frame_href_dl;
reg [delay-1:0] per_frame_clken_dl;
reg [delay-1:0] per_frame_vsync_dl;
wire per_frame_href_;
wire per_frame_clken_;
wire per_frame_vsync_;

assign row2_rd_en=(per_frame_clken||per_frame_clken_)&&(data_count2==10'd640);
assign row1_rd_en=(per_frame_clken||per_frame_clken_)&&(data_count1==10'd640);
assign row2_wr_en=(per_frame_clken||per_frame_clken_);
assign row1_wr_en=(per_frame_clken||per_frame_clken_)&&(data_count2==10'd640);
assign row3_data=(per_frame_href_==1&&per_frame_href==0)?row2_data:per_img_Y;  //在图像后面延时了一行行有效信号,在这一行把row2_data复制,实现在图像下方通过复制补边界的操作
assign row1_data=(row_cnt==1||row_cnt==0)?row2_data1:row1_data1;    //在行计数等于1之前,将row2_data1的值给row1_data,实现在图像上方通过复制补一行边界
assign row2_data=row2_data1;
assign fifo_in=(row_cnt==480)?0:per_img_Y;  //在图像最后一行的后面再向fifo中送入一行0,使fifo多工作一行,以便在图像的下方补一行边界

fifo_generator_0 u2 (
  .clk(clk),                // input wire clk
  .srst(!rst_n),              // input wire srst
  .din(fifo_in),                // input wire [7 : 0] din
  .wr_en(row2_wr_en),            // input wire wr_en
  .rd_en(row2_rd_en),            // input wire rd_en
  .dout(row2_data1),              // output wire [7 : 0] dout
  .full(),              // output wire full
  .empty(),            // output wire empty
  .data_count(data_count2)  // output wire [9 : 0] data_count
);

fifo_generator_0 u1 (
  .clk(clk),                // input wire clk
  .srst(!rst_n),              // input wire srst
  .din(row2_data1),                // input wire [7 : 0] din
  .wr_en(row1_wr_en),            // input wire wr_en
  .rd_en(row1_rd_en),            // input wire rd_en
  .dout(row1_data1),              // output wire [7 : 0] dout
  .full(),              // output wire full
  .empty(),            // output wire empty
  .data_count(data_count1)  // output wire [9 : 0] data_count
);


wire	     read_frame_href ;
wire	     read_frame_clken;
reg  [1:0]  per_frame_vsync_r;
reg  [1:0]  per_frame_href_r;
reg  [1:0]  per_frame_clken_r;
assign	read_frame_href    = per_frame_href_r[0] ;
assign	read_frame_clken   = per_frame_clken_r[0];
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];

//delay 2 clk
always@(posedge clk or negedge rst_n) begin
	if(!rst_n) begin		
		per_frame_vsync_r <= 0;
		per_frame_href_r  <= 0;
		per_frame_clken_r <= 0;
	end
	else begin		
		per_frame_vsync_r <= { per_frame_vsync_r[0], per_frame_vsync_ };
		per_frame_href_r  <= { per_frame_href_r[0],  per_frame_href_  };
		per_frame_clken_r <= { per_frame_clken_r[0], per_frame_clken_ };
	end
end


always @(posedge clk or negedge rst_n) begin
    if(~rst_n)begin
        per_frame_href_dl<=0;
        per_frame_clken_dl<=0;
        per_frame_vsync_dl<=0;
    end
    else begin
        per_frame_href_dl<={per_frame_href_dl[delay-2:0],per_frame_href};
        per_frame_clken_dl<={per_frame_clken_dl[delay-2:0],per_frame_clken};
        per_frame_vsync_dl<={per_frame_vsync_dl[delay-2:0],per_frame_vsync};
    end
end
assign per_frame_href_=per_frame_href_dl[delay-1];
assign per_frame_clken_=per_frame_clken_dl[delay-1];
assign per_frame_vsync_=per_frame_vsync_dl[delay-1];

always @(posedge clk) begin
    per_frame_href_delay<=per_frame_href_;
end
//行计数
always @(posedge clk or negedge rst_n) begin
    if(!rst_n||~per_frame_vsync_)
        row_cnt<=9'd0;
    else if(~per_frame_href_delay&per_frame_href_) begin
        if(row_cnt==9'd480)
            row_cnt<=9'd1;
        else
            row_cnt<=row_cnt+1;
    end
    else
        row_cnt<=row_cnt;
end

//generate the 3X3 matrix 
always@(posedge clk or negedge rst_n) begin
	if(!rst_n) begin		
		{matrix_p11, matrix_p12, matrix_p13} <= 24'h0;
		{matrix_p21, matrix_p22, matrix_p23} <= 24'h0;
		{matrix_p31, matrix_p32, matrix_p33} <= 24'h0;
	end
	else if(per_frame_href_||read_frame_href) begin
	    
		if(per_frame_clken_) begin			
			{matrix_p11, matrix_p12, matrix_p13} <= {matrix_p12, matrix_p13, row1_data};
            {matrix_p21, matrix_p22, matrix_p23} <= {matrix_p22, matrix_p23, row2_data};
            {matrix_p31, matrix_p32, matrix_p33} <= {matrix_p32, matrix_p33, row3_data};
		end
		
		else begin			
			{matrix_p11, matrix_p12, matrix_p13} <= {matrix_p11, matrix_p12, matrix_p13};
			{matrix_p21, matrix_p22, matrix_p23} <= {matrix_p21, matrix_p22, matrix_p23};
			{matrix_p31, matrix_p32, matrix_p33} <= {matrix_p31, matrix_p32, matrix_p33};
		end	
	end
	else begin		
		{matrix_p11, matrix_p12, matrix_p13} <= {matrix_p11, matrix_p12, matrix_p13};
        {matrix_p21, matrix_p22, matrix_p23} <= {matrix_p21, matrix_p22, matrix_p23};
        {matrix_p31, matrix_p32, matrix_p33} <= {matrix_p31, matrix_p32, matrix_p33};
	end
	

end


endmodule

均值滤波模块

module mean_filter(
    input clk,
    input rst_n,
    
    input per_frame_vsync,
    input per_frame_href,
    input per_frame_clken,
    input [7:0] per_img_Y,
    
    output post_frame_vsync,
    output post_frame_href,
    output post_frame_clken,
    output [7:0] post_img_data
    );
    
parameter [10:0] delay=11'd1310;    
wire matrix_frame_clken;
wire matrix_frame_href;
wire matrix_frame_vsync;
wire [7:0] matrix_p11;
wire [7:0] matrix_p12;
wire [7:0] matrix_p13;
wire [7:0] matrix_p21;
wire [7:0] matrix_p22;
wire [7:0] matrix_p23;
wire [7:0] matrix_p31;
wire [7:0] matrix_p32;
wire [7:0] matrix_p33;
wire [7:0] img_data;
reg [11:0] add_p1;
reg [11:0] add_p2;
reg [11:0] add_p3;
reg [11:0] add_all;
reg [9:0] col_cnt;  
 
generate_3_3 #(delay) u(
    .clk(clk),
    .rst_n(rst_n),
    
    .per_frame_vsync(per_frame_vsync),
    .per_frame_href(per_frame_href),
    .per_frame_clken(per_frame_clken),
    .per_img_Y(per_img_Y),
    .matrix_frame_vsync ( matrix_frame_vsync ),
    .matrix_frame_href  ( matrix_frame_href  ),
    .matrix_frame_clken ( matrix_frame_clken ),
    .matrix_p11         ( matrix_p11         ),
    .matrix_p12         ( matrix_p12         ),
    .matrix_p13         ( matrix_p13         ),
    .matrix_p21         ( matrix_p21         ),
    .matrix_p22         ( matrix_p22         ),
    .matrix_p23         ( matrix_p23         ),
    .matrix_p31         ( matrix_p31         ),
    .matrix_p32         ( matrix_p32         ),
    .matrix_p33         ( matrix_p33         )
);

//列计数
always @(negedge matrix_frame_clken or negedge rst_n) begin
    if(!rst_n)
        col_cnt<=10'd0;
    else begin
        if(col_cnt==640)
            col_cnt<=10'd1;
        else
            col_cnt<=col_cnt+1;
    end
end
//step1:add every href
always @(posedge clk or negedge rst_n) begin
    if(~rst_n)begin
        add_p1<=12'd0;
        add_p2<=12'd0;
        add_p3<=12'd0;
    end
    else if(col_cnt==10'd1) begin
        add_p1<=matrix_p12+matrix_p12+matrix_p13;
        add_p2<=matrix_p22+matrix_p22+matrix_p23;
        add_p3<=matrix_p32+matrix_p32+matrix_p33;
    end
    else if(col_cnt==10'd640) begin
        add_p1<=matrix_p12+matrix_p13+matrix_p13;
        add_p2<=matrix_p22+matrix_p23+matrix_p23;
        add_p3<=matrix_p32+matrix_p33+matrix_p33;
    end
    else begin
        add_p1<=matrix_p11+matrix_p12+matrix_p13;
        add_p2<=matrix_p21+matrix_p22+matrix_p23;
        add_p3<=matrix_p31+matrix_p32+matrix_p33;
    end
end
always @(posedge clk or negedge rst_n) begin
    if(~rst_n)begin
        add_all<=12'd0;
    end
    else begin
        add_all<=add_p1+add_p2+add_p3;
    end
end
assign img_data=add_all/9;
//延时2个像素时钟周期(4个系统时钟周期),因为对3*3矩阵内的数进行计算时,当每一行第二个像素送入时,我们计算的结果替代的是第一个像素的值
//所以输出的像素时钟比3*3矩阵输入的像素时钟延迟一个像素时钟周期,计算add_p1、add_p2、add_p3时延迟了一个系统时钟周期,计算add_all又延时了一个系统时钟周期
//计算出add_all总共延时了两个系统时钟周期即一个像素时钟周期,最后总共延时2个像素时钟周期,完成数据对齐
reg [3:0] post_frame_clken_dy;
reg [3:0] post_frame_href_dy;
reg [3:0] post_frame_vsync_dy;
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        post_frame_clken_dy<=4'd0;
        post_frame_href_dy<=4'd0;
        post_frame_vsync_dy<=4'd0;
    end
    else begin
        post_frame_clken_dy<={post_frame_clken_dy[2:0],matrix_frame_clken};
        post_frame_href_dy<={post_frame_href_dy[2:0],matrix_frame_href};
        post_frame_vsync_dy<={post_frame_vsync_dy[2:0],matrix_frame_vsync};
    end
end
assign post_frame_clken=post_frame_clken_dy[3];
assign post_frame_href=post_frame_href_dy[3];
assign post_frame_vsync=post_frame_vsync_dy[3];
assign post_img_data=post_frame_href?img_data:0;
endmodule

4、结果图

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/786537.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TSINGSEE视频监控汇聚平台EasyCVR视频监控录像的3种方式

视频监控综合管理平台EasyCVR可以实现海量资源的接入、汇聚、计算、存储、处理等&#xff0c;平台具备轻量化接入能力&#xff0c;可支持多协议方式接入&#xff0c;包括主流标准协议GB28181、RTSP/Onvif、RTMP等&#xff0c;以及厂家私有协议与SDK接入&#xff0c;包括海康Eho…

UE5 关于MRQ渲染器参数

最佳参数&#xff1a; Spatial Sample Count&#xff1a;使用奇数样本时临时抗锯齿会收敛 Temporal Sample Count&#xff1a;超过2之后&#xff0c;采样过大会造成TAA效果不佳 TSR&#xff1a;UE5最好的抗锯齿方案

【C#】并行编程实战:使用 Visual Studio 调试任务

并行编程可以提高应用程序的性能&#xff0c;但是调试起来会更困难&#xff0c;这一点在之前的章节中我们已经有了很直观的感受。对于程序而言&#xff0c;保证程序的正确性和保证性能同样重要。 本章将介绍可以在 Visual Studio 中的调试工具&#xff08;包括 Thread 窗口、Ta…

C#winform中Icon图标获取方式

文章目录 图标来源格式转换 图标来源 阿里巴巴矢量图库 以“文件夹”图标为例&#xff1a; 格式转换 想要给winform的窗口添加一个图标&#xff0c;可以看到&#xff0c;需要添加.ico的格式。 将上面下载的图标通过wps的图片查看器打开&#xff1a; 点击左上角的属性&…

Docker 的数据管理和镜像的创建(Dockerfile)

目录 一&#xff1a;Docker 的数据管理 1&#xff0e;数据卷 2&#xff0e;数据卷容器 3.容器互联&#xff08;使用centos镜像&#xff09; 二&#xff1a;Docker 镜像的创建 1&#xff0e;基于现有镜像创建 &#xff08;1&#xff09;首先启动一个镜像&#xff0c;在容器里…

什么是AI和BI?

近日在冲浪时看到一个问题&#xff0c;说“AI和BI都有I&#xff0c;那这两个是一个东西吗&#xff1f;”&#xff0c;想要解答一下发现无从下口&#xff0c;这一下激起了我的“求知欲”&#xff0c;于是我找了一些资料后决定写下这篇文章&#xff0c;打算从几个方面为大家解答一…

生物信息学_玉泉路_课堂笔记_07 第七章 转录组学:基因芯片及RNA_sep数据分析

第七章 转录组学&#xff1a;基因芯片及RNA_sep数据分析 大部分是可以转录的 大概70-80%可Rna 从此区域出来的rna 来看 编码基因 只占据很小的一部分 2%左右 更多的区域转录出来的是非编码rna 转录组学的测序方法 基因芯片 RNA-sep 基因芯片只是了解思想 重点是RNA-sep…

Docker的数据卷、数据卷容器,容器互联

一、数据卷&#xff08;容器与宿主机之间数据共享&#xff09; 数据卷是一个供容器使用的特殊目录&#xff0c;位于容器中。可将宿主机的目录挂载到数据卷上&#xff0c;对数据卷的修改操作立刻可见&#xff0c;并且更新数据不会影响镜像&#xff0c;从而实现数据在宿主机与容…

Kubernetes 的核心概念:Pod、Service 和 Namespace 解析

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

【更新公告】Airtest更新至1.3.0.1版本

1. 前言 本次更新为Airtest库更新&#xff0c;版本提升至1.3.0.1版本&#xff0c;主要新增了一些iOS设备相关的装包等接口&#xff0c;以及封装了一些tidevice常用接口。更多更新详情&#xff0c;详见我们下文的描述。 2. 新增iOS设备接口 1&#xff09;iOS安装接口&#xf…

idea springBoot 部署多个项目打开Run Dashboard 窗口

在部署springcloud 项目的时候 本地调试&#xff0c;有可能需要全部启动所有服务&#xff0c;单个部署比较麻烦&#xff0c;通过Run DashBoard 窗口可以完美实现 1.先打开项目的文件地址找到workspace.xml文件&#xff0c;在项目下的.idea\workspace.xml 2. ctrlf 找到RunDash…

tortoiseSVN提交报错记录

tortoiseSVN提交文件时报错&#xff1a;你的主机中的软件中止了一个已建立的连接。 本来是好几个文件和文件夹一起提交的。提交直接报错&#xff0c;网上说的更换网络、退安全软件、关闭防火墙都试过了&#xff0c;没有效果。 偶然看到一个回答说是可能是文件内容的问题&…

基于Hilt的依赖注入跨模块导航框架的Kotlin实现

前提&#xff1a; GitHub链接&#xff1a;GitHub - savelove123/AwesomeNavigation: 基于Hilt的Android页面导航框架 在使用清洁架构MVVM组件化重构现有的项目的时候&#xff0c;为了实现跨模块页面导航&#xff0c;需要使用一个支持跨模块的页面导航组件。原本使用的是阿里巴巴…

图说 SQL 的 JOIN

JOIN 用于多表联查&#xff0c;分为&#xff1a; OUTER JOIN FULL OUTER JOIN LEFT OUTER JOIN RIGHT OUTER JOIN INNER JOIN OUTER 通常省略&#xff0c;所以我们在查询语句中看到的大都是 FULL JOIN、LEFT JOIN、RIGHT JOIN。 为了便于验证说明&#xff0c;下面我在 tem…

每日一题——判断链表中是否有环

题目 判断给定的链表中是否有环。如果有环则返回true&#xff0c;否则返回false。 数据范围&#xff1a;链表长度 0≤n≤10000&#xff0c;链表中任意节点的值满足 ∣val∣<100000 要求&#xff1a;空间复杂度 O(1)&#xff0c;时间复杂度 O(n) 输入分为两部分&#xff0c…

关于tensorflow和pytroch安装的一些坑坑

主要是自己总结记录一下 首先tensorflow的安装 主要先参照的官网 https://docs.anaconda.com/free/anaconda/applications/tensorflow/之后我的项目是需要用到keras的&#xff0c;然后我又去安装keras&#xff0c;出现了Cannot import name ‘dtensor’ from ‘tensorflow.co…

物联网阀控水表计量准确度如何?

物联网阀控水表是一种新型的智能水表&#xff0c;它采用了先进的物联网技术&#xff0c;可以通过远程控制和监测水表的运行情况&#xff0c;实现更加精准的水量计量和费用结算。那么&#xff0c;物联网阀控水表的计量准确度如何呢&#xff1f;下面我们将从以下几个方面进行详细…

树状数组笔记

数组、前缀和、树状数组的区别&#xff1a; 数组&#xff1a;修改某点O&#xff08;1&#xff09;&#xff0c;求区间O&#xff08;n&#xff09; 前缀和&#xff1a;修改某点O&#xff08;n&#xff09;&#xff0c;求区间O&#xff08;1&#xff09; 树状数组&#xff1a;修改…

机器学习实战:Python基于GBM梯度提升机进行预测(十四)

这篇干货很硬&#xff0c;喜欢的小伙伴点个赞/收藏&#xff0c;持续更新&#xff01; 文章目录 1.前言1.1 GBM的介绍1.2 GBM的应用 2. scikit-learn实战演示2.1 分类问题2.2 回归问题 3. GBM超参数3.1 决策树数量&#xff08;n_estimators&#xff09;3.2 样本数量&#xff08…

网络设备中的配置文件管理

建立强大网络的第一步是为灾难和网络中断做好准备&#xff0c;许多企业在中断期间遭受损失&#xff0c;因为他们缺乏备份计划并且配置管理不达标&#xff0c;使用配置文件管理工具进行适当的配置文件管理不仅有助于处理网络中断&#xff0c;还有助于优化网络性能。 使用配置文…