FPGA + 图像处理(三)生成3x3像素矩阵

news2025/1/25 9:15:25

前言

生成NxN的像素矩阵是对图像进行各类滤波操作的基本前提,本文介绍一种通过bram生成3x3矩阵的方法。

程序

生成bram核

因为本文介绍的是基于bram生成的3x3像素矩阵,所以要先生成两个bram核,用于缓存前两行图像数据

在 IP catalog中选择Block Memory Generator

配置如下

注意这里选择simple dual port RAM,即伪双端口,一个端口只能写,一个端口只能读

端口A用于写入数据,注意数据的位宽要与图像位深相同,彩色通常为24位,灰度图为8位,数据深度为一行像素的长度,operating选择写优先,enable port type选择始终使能

端口B用于读取数据,这里要注意下面的primitives output register要勾选上,勾选该选项后,数据的输出会延迟一个时钟周期,用于对齐数据。

HDMI时序生成模块

这里也用到了HDMI时序生成模块,具体作用和前面文章讲的一样,一是可以做到通过同步信号简化对图像数据的管理,二是可以让测试的数据处理模块更方便的适配用HDMI显示的图像处理工程。

具体代码如下

module hdmi_tim_gen(
    input           	clk			,
    input           	rst_n	    ,
	input   	[23:0]  data_in		,
		
    output          	hdmi_hs		,     //行同步信号
    output          	hdmi_vs		,     //场同步信号
    output          	hdmi_de		,     //数据使能
    output  	[23:0]  hdmi_data	,     //RGB888颜色数据
    output		reg		data_req 	

);

//1280*720 分辨率时序参数
parameter  H_SYNC   =  11'd40;   //行同步
parameter  H_BACK   =  11'd220;  //行显示后沿
parameter  H_DISP   =  11'd1280; //行有效数据
parameter  H_FRONT  =  11'd110;  //行显示前沿
parameter  H_TOTAL  =  11'd1650; //行扫描周期

parameter  V_SYNC   =  11'd5;    //场同步
parameter  V_BACK   =  11'd20;   //场显示后沿
parameter  V_DISP   =  11'd720;  //场有效数据
parameter  V_FRONT  =  11'd5;    //场显示前沿
parameter  V_TOTAL  =  11'd750;  //场扫描周期

//reg define
reg  [11:0] 	cnt_h;
reg  [11:0] 	cnt_v;

reg [10:0] pixel_xpos;
reg [10:0] pixel_ypos;

assign hdmi_de  = data_req;
assign hdmi_hs  = ( cnt_h < H_SYNC ) ? 1'b0 : 1'b1;  //行同步信号赋值
assign hdmi_vs  = ( cnt_v < V_SYNC ) ? 1'b0 : 1'b1;  //场同步信号赋值

//RGB888数据输出
assign hdmi_data = hdmi_de ? data_in : 24'd0;

//请求像素点颜色数据输入
always @(posedge clk or negedge rst_n) begin
	if(!rst_n)
		data_req <= 1'b0;
	else if(((cnt_h >= H_SYNC + H_BACK - 2'd2) && (cnt_h < H_SYNC + H_BACK + H_DISP - 2'd2))
                  && ((cnt_v >= V_SYNC + V_BACK) && (cnt_v < V_SYNC + V_BACK+V_DISP)))
		data_req <= 1'b1;
	else
		data_req <= 1'b0;
end

//像素点x坐标
always@ (posedge clk or negedge rst_n) begin
    if(!rst_n)
        pixel_xpos <= 11'd0;
    else if(data_req)
        pixel_xpos <= cnt_h + 2'd2 - H_SYNC - H_BACK ;
    else 
        pixel_xpos <= 11'd0;
end
    
//像素点y坐标	
always@ (posedge clk or negedge rst_n) begin
    if(!rst_n)
        pixel_ypos <= 11'd0;
    else if((cnt_v >= (V_SYNC + V_BACK)) && (cnt_v < (V_SYNC + V_BACK + V_DISP)))
        pixel_ypos <= cnt_v + 1'b1 - (V_SYNC + V_BACK) ;
    else 
        pixel_ypos <= 11'd0;
end

//行计数器对像素时钟计数
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        cnt_h <= 11'd0;
    else begin
        if(cnt_h < H_TOTAL - 1'b1)
            cnt_h <= cnt_h + 1'b1;
        else 
            cnt_h <= 11'd0;
    end
end

//场计数器对行计数
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        cnt_v <= 11'd0;
    else if(cnt_h == H_TOTAL - 1'b1) begin
        if(cnt_v < V_TOTAL - 1'b1)
            cnt_v <= cnt_v + 1'b1;
        else 
            cnt_v <= 11'd0;
    end
end

endmodule

生成3x3像素矩阵的顶层模块

module kernel_3x3_gen
(
	input					clk,  		
	input					rst_n,				

	//准备要进行处理的图像数据
	input					vs_i,
	input					de_i,
	input        [23:0]  	data_i,

	//矩阵化后的图像数据和控制信号
	output				vs_o,
	output				de_o,
	output	reg  [23:0]	mat11, 
	output	reg  [23:0]	mat12,
	output	reg  [23:0]	mat13,
	output	reg	 [23:0]	mat21, 
	output	reg  [23:0]	mat22, 
	output	reg  [23:0]	mat23,
	output	reg	 [23:0]	mat31, 
	output	reg  [23:0]	mat32, 
	output	reg  [23:0]	mat33
);

//wire define
wire  [23:0]  	row1_data;        //第一行数据
wire  [23:0]  	row2_data;        //第二行数据
wire	     	de_i_en ;

//reg define
reg  [23:0]  row3_data;         //第三行数据,即当前正在接受的数据
reg  [23:0]  row3_data_d0;
reg  [23:0]  row3_data_d1;
reg  [23:0]  row2_data_d0;
reg  [1:0]   vs_i_d;
reg  [1:0]   de_i_d;

assign	de_i_en = de_i_d[0] ;
assign	vs_o 	= vs_i_d[1];
assign	de_o  	= de_i_d[1] ;

//当前数据放在第3行
always@(posedge clk or negedge rst_n) begin
	if(!rst_n)
		row3_data <= 0;
	else begin		
		if(de_i)
			row3_data <= data_i ;
		else
			row3_data <= row3_data ;
	end
end

//用于存储列数据的RAM
line_shift  u_line_shift
(
	.clk		    (clk),
	.de_i 			(de_i),

	.data_i	    	(data_i),   //当前行的数据
	.data1_o		(row2_data),   //前一行的数据
	.data2_o		(row1_data)    //前前一行的数据
);

//将同步信号延迟两拍,用于同步化处理
always@(posedge clk or negedge rst_n) begin
	if(!rst_n) begin		
		vs_i_d <= 0;
		de_i_d <= 0;
	end
	else begin		
		vs_i_d  <= { vs_i_d[0], vs_i };
		de_i_d  <= { de_i_d[0], de_i };
	end
end

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        row3_data_d1 <= 0;
        row3_data_d0 <= 0;
        row2_data_d0 <= 0;
    end
    else begin
        row3_data_d0 <= row3_data;
        row3_data_d1 <= row3_data_d0;
        row2_data_d0 <= row2_data;
    end
end

//在同步处理后的控制信号下,输出图像矩阵
always@(posedge clk or negedge rst_n) begin
	if(!rst_n) begin		
		{mat11, mat12, mat13} <= 0;
		{mat21, mat22, mat23} <= 0;
		{mat31, mat32, mat33} <= 0;
	end
	else if(de_i_en) begin				
		{mat11, mat12, mat13} <= {mat12, mat13, row1_data};
		{mat21, mat22, mat23} <= {mat22, mat23, row2_data_d0};
		{mat31, mat32, mat33} <= {mat32, mat33, row3_data_d1};
	end
	else begin		
		{mat11, mat12, mat13} <= 0;
		{mat21, mat22, mat23} <= 0;
		{mat31, mat32, mat33} <= 0;
	end
end

endmodule

行移位模块

module line_shift(
	input 			clk,
	input           de_i,

	input   [23:0]  data_i,    //当前行的数据
	output  [23:0]  data1_o,   //前一行的数据
	output  [23:0]  data2_o    //前前一行的数据
);

//reg define
reg  de_i_d0;
reg  de_i_d1;
reg  de_i_d2;
reg  [10:0]  ram_rd_addr;
reg  [10:0]  ram_rd_addr_d0;
reg  [10:0]  ram_rd_addr_d1;
reg  [23:0]  data_i_d0;
reg  [23:0]  data_i_d1;
reg  [23:0]  data_i_d2;
reg  [23:0]  data1_o_d0;

//在数据到来时,RAM的读地址累加
always@(posedge clk)begin
	if(de_i)
		ram_rd_addr <= ram_rd_addr + 1 ;	
	else
		ram_rd_addr <= 0 ;
end

//将数据使能延迟两拍
always@(posedge clk) begin
	de_i_d0 <= de_i;
	de_i_d1 <= de_i_d0;
	de_i_d2 <= de_i_d1;
end

//将RAM地址延迟2拍
always@(posedge clk ) begin
	ram_rd_addr_d0 <= ram_rd_addr;
	ram_rd_addr_d1 <= ram_rd_addr_d0;
end

//输入数据延迟3拍送入RAM
always@(posedge clk)begin
	data_i_d0 <= data_i;
	data_i_d1 <= data_i_d0;
	data_i_d2 <= data_i_d1;
end

//用于存储前一行图像的RAM
blk_mem_gen_0  u_ram_1024x8_0(
  .clka   (clk),
  .wea    (de_i_d2),
  .addra  (ram_rd_addr_d1),     //在延迟的第三个时钟周期,当前行的数据写入RAM0
  .dina   (data_i_d2),
  
  .clkb   (clk),
  .addrb  (ram_rd_addr),    
  .doutb  (data1_o)              //延迟一个时钟周期,输出RAM0中前一行图像的数据
);

//寄存前一行图像的数据
always@(posedge clk)begin
	data1_o_d0  <= data1_o;
end

//用于存储前前一行图像的RAM
blk_mem_gen_0  u_ram_1024x8_1(
	.clka   (clk),
	.wea    (de_i_d1),
	.addra  (ram_rd_addr_d0),
	.dina   (data1_o_d0),       //在延迟的第二个时钟周期,将前一行图像的数据写入RAM1

	.clkb   (clk),
	.addrb  (ram_rd_addr),
	.doutb  (data2_o)           //延迟一个时钟周期,输出RAM1中前前一行图像的数据
);

endmodule

仿真模块

`timescale 1ns/1ns

module pic_tb();

reg             clk,rst_n				;

reg [23:0]      data_in					;
wire      		hdmi_hs,hdmi_vs,hdmi_de ;
wire [23:0]  	hdmi_data  				;
wire 			data_req   				;

reg  			vs_i,de_i	;
wire 			vs_o,de_o		;
wire [23:0]		mat11, mat12, mat13 ;
wire [23:0]		mat21, mat22, mat23 ;
wire [23:0]		mat31, mat32, mat33 ;
//延迟1clk,与data同步,hdmi时序中,data比de延迟了一个时钟周期
always @(posedge clk)begin
    vs_i <= hdmi_vs;
    de_i <= hdmi_de;
end

initial begin
	clk = 1;
	rst_n = 0;
	#20 rst_n = 1;
end
always #10 clk = ~clk;

reg [23:0] img[0:1280*720-1];
reg [31:0] addr;
initial begin
    $readmemh("D:/pic/img2txt.txt",img);
end

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        addr <= 0		;
        data_in <= 0	;
    end
    else if(data_req) begin
        data_in	 <= img[addr];
        addr	 <= addr + 1;
        if(addr == (1280*720-1))
			addr <= 0;
    end
end

hdmi_tim_gen u_hdmi_tim_gen(
	.clk		 	(clk),	
    .rst_n	  		(rst_n),
	//input
    .data_in	 	(data_in),
    //output
    .hdmi_hs	 	(hdmi_hs),
    .hdmi_vs	 	(hdmi_vs),
    .hdmi_de	 	(hdmi_de),
    .hdmi_data 		(hdmi_data),
    .data_req  		(data_req)
);

 kernel_3x3_gen u_kernel_3x3_gen(
    .clk        (clk), 
    .rst_n      (rst_n),
    
    //预处理灰度数据
    .vs_i    		 (vs_i),
    .de_i     		 (de_i), 
    .data_i          (hdmi_data),
    
    //输出3x3矩阵
    .vs_o   		(vs_o),
    .de_o    		(de_o),
    .mat11         (mat11),    
    .mat12         (mat12),    
    .mat13         (mat13),
    .mat21         (mat21),    
    .mat22         (mat22),    
    .mat23         (mat23),
    .mat31         (mat31),    
    .mat32         (mat32),    
    .mat33         (mat33)
);

endmodule

整体架构

仿真结果

截取部分数据结果

mat31、mat32、mat33是第一行数据(最先输入的那一行),mat11、mat12、mat13是第三行数据(最后输入的那一行),可以看见数据的移位满足像素矩阵的要求。

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

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

相关文章

IDEA连接SqlServer数据库详细讲解

####一、前期准备 确保已经安装了SqlServer数据库&#xff0c;并记住服务器名称、登录名和密码等信息。在IDEA中安装适当的JDBC&#xff08;Java Database Connectivity&#xff09;驱动程序。你可以从Microsoft官方网站上下载最新版本。 二、连接步骤 打开IDEA&#xff0c;…

Unity类银河恶魔城学习记录12-7-1 p129 Craft UI - part 1源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili UI_CraftList.cs using System.Collections; using System.Collections.Gen…

【小白学机器学习10】假设检验之1:F检验,F检验量的构造,F分布,F分布查表求P值等

目录 1 什么是F检验 F-test 1.1 F-test的定义 1.1.1 维基百科对F检验的定义 1.1.2 百度百科的定义 1.2 F检验的别名 1.3 F检验的判断手段 / 要达成的目标 / 适用范围 1.3.1 判断手段 1.3.2 对H0原假设的理解 1.3.3 判断目标/目的 1.3.4 适用的范围&#xff0c;场合 …

HTML5+CSS3+JS小实例:圣诞按钮

实例:圣诞按钮 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0&…

甘特图/横道图制作技巧 - 任务组

在甘特图中通过合理的任务分组可以让项目更加清晰&#xff0c;修改也更方便。 列如下面的甘特图一眼不太容易看清楚整体的进度。或者需要把所有的任务整体的延迟或者提前只能这样一个一个的任务调整&#xff0c;就比较麻烦。 通过给任务分组&#xff0c;看这上面整体的进度就…

TiDB MVCC 版本堆积相关原理及排查手段

导读 本文介绍了 TiDB 中 MVCC&#xff08;多版本并发控制&#xff09;机制的原理和相关排查手段。 TiDB 使用 MVCC 机制实现事务&#xff0c;在写入新数据时不会直接替换旧数据&#xff0c;而是保留旧数据的同时以时间戳区分版本。 当历史版本堆积过多时&#xff0c;会导致读…

【c语言】strncat函数模拟实现

strncat函数模拟实现 strncat函数在cplusplus网站中的定义 模拟实现源码 //strncat函数模拟实现 #include <stdio.h> #include <string.h> #include <assert.h>char* my_strncat(char* destination, const char* source, size_t num) {assert(destination &a…

第十三届蓝桥杯真题解析

本专栏内容为&#xff1a;算法学习专栏&#xff0c;分为优选算法专栏&#xff0c;贪心算法专栏&#xff0c;动态规划专栏以及递归&#xff0c;搜索与回溯算法专栏四部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握算法。 &#x1f493;博主csdn个人主页&#xff1a;小…

抖音-引流私域转化模式1.0现场视频,从抖音源源不断把人加到私域,

抖音-引流私域转化模式1.0现场视频&#xff0c;从抖音源源不断把人加到私域&#xff0c;让加到私域的粉丝买单 抖音-引流私域转化模式1.0现场视频&#xff0c;从抖音源源不断把人加到私域 - 百创网-源码交易平台_网站源码_商城源码_小程序源码 课程内容&#xff1a; 01.第一…

JetBrains IDE 2024.1 发布 - 开发者工具

JetBrains IDE 2024.1 (macOS, Linux, Windows) - 开发者工具 CLion, DataGrip, DataSpell, Fleet, GoLand, IntelliJ IDEA, PhpStorm, PyCharm, Rider, RubyMine, WebStorm 请访问原文链接&#xff1a;JetBrains IDE 2024.1 (macOS, Linux, Windows) - 开发者工具&#xff0…

代码随想录阅读笔记-二叉树【合并二叉树】

题目 给定两个二叉树&#xff0c;想象当你将它们中的一个覆盖到另一个上时&#xff0c;两个二叉树的一些节点便会重叠。 你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠&#xff0c;那么将他们的值相加作为节点合并后的新值&#xff0c;否则不为 NULL 的节…

uniapp 密码框的眼睛

效果展示&#xff1a; uniapp input 官网链接&#xff1a;链接 按照官方文档&#xff0c;uni-icon出不来。 通过自己的方法解决了&#xff0c;解决方案如下&#xff1a; 代码&#xff1a; <uni-forms-item name"password"><inputclass"uni-input&quo…

批发批量订购下单商城公众号 小程序_博纳软云

批发批量订购下单商城——满足您的批量采购需求 在如今快节奏的商业环境中&#xff0c;批发批量订购已成为众多企业和个人创业者的首选采购方式。为了满足广大用户的批量采购需求&#xff0c;我们特别推出了批发批量订购下单商城&#xff0c;为您提供一站式的采购解决方案。 …

牛客论坛项目中使用到Redis的地方总结

实体分为很多类&#xff0c;实体的确定要通过实体类型和实体id两个属性同时确定。牛客论坛中使用到了3类实体&#xff1a; 1 登录 使用到的Redis命令&#xff1a; set key value // 设置指定key的值为value get key // 获取指定key的值1.1 存储/获取验证码 验证码文本&…

【iOS】UITableView性能优化

文章目录 前言一、优化的本质二、卡顿产生原因三、CPU层面优化1.使用轻量级对象2.cellForRowAtIndexPath方法中不要做耗时操作3.UITableView的复用机制4.提前计算好布局了解tableView代理方法执行顺序cell高度计算rowHeightestimatedRowHeight 高度计算进行时机rowHeight计算时…

无参数绕过RCE

一.什么是无参数 顾名思义&#xff0c;就是只使用函数&#xff0c;且函数不能带有参数&#xff0c;这里有种种限制&#xff1a;比如我们选择的函数必须能接受其括号内函数的返回值&#xff1b;使用的函数规定必须参数为空或者为一个参数等 无参数题目特征 if(; preg_replace…

这就是AI眼中的物理世界:OpenAI Sora音乐短片《Worldweight》和超现实影片《气球人》

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

Java8关于Function接口

Java学习-Function接口 1 函数式接口简介和学习地址2 两种常见的函数式接口2.1 Runnable&#xff1a;执行接口&#xff0c;不接收参数&#xff0c;也无返回结果。2.2 Consumer&#xff1a;作为消费接口&#xff0c;接收一个参数&#xff0c;无返回结果。 3 初识3.1 定义Functio…

JVM从1%到99%【精选】-初步认识

目录 &#x1f95e;1.什么是JVM &#x1f37f;2.JVM的功能 &#x1f953;3.常见的JVM &#x1f32d;4.JVM的位置 &#x1f9c2;5.JVM的整体结构 &#x1f383;6.JVM的生命周期 &#x1f388;7.JVM的架构模型 1.什么是JVM JVM本质上是一个运行在计算机上的程序,他的职责…

WPS快速将插入Excle数据插入Word

前置条件&#xff1a; 一张有标题、数据的excle表格word中的表格与excle表格标题对应或包含电脑已经安装WPS软件 第一步、根据word模板设计excle模板&#xff0c;标头对应 第二步、word上面选【引用】--【邮件】&#xff0c;选打开数据源&#xff0c;找到excle文件&#xff0c;…