FPGA + 图像处理 (二) RGB转YUV色域、转灰度图及仿真

前言

具体关于色域的知识就不细说了,简单来讲YUV中Y通道可以理解为就是图像的灰度图,因此,将RGB转化为YUV是求彩色图的灰度直方图、进行二值化操作等的基础。

HDMI时序生成模块

这里先介绍一下仿真时用于生成HDMI时序,用这个时序来向数据处理模块输入数据,一是可以做到通过同步信号简化对图像数据的管理,二是可以让测试的数据处理模块更方便的适配用HDMI显示的图像处理工程。

 HDMI的单帧时序如图,具体时序知识不细说,下面代码实现的功能简单理解就是当data_req(数据请求)信号拉高时,开始向模块内输入图像数据,连续输入一行的数据,然后直接输出图像数据,当输出数据时拉高hdmi_de(数据有效)信号。因为本次是单帧的图像,所以hdmi_vs(场同步)信号以及hdmi_hs(行同步)信号是用不到的。

要注意不同尺寸的图像对应的参数不同,本模块适用于1280*720像素的图像

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	,     //图像数据
    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  [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; 

//图像数据输出
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

RGB转YUV模块

前面也说过了,YUV中的Y通道就是图像的灰度图,以此,单独将Y通道输出就可以得到彩色图像的灰度图

module rgb2yuv
(
    input               clk          	,  
    input               rst_n        	,  

    input               vs_i    		,  
    input               de_i    		,  
    input       [23:0]  data_i     		,  

    output              vs_o  			,  
    output              de_o  			,  
    output      [23:0]  data_yuv       	, 
    output      [7:0]   data_gray       	
	
  
);

//YUV中Y指明亮度,也就是灰度值,(U,V)指色度,即饱和度和色调

reg  [15:0]   rgb_r_m0, rgb_r_m1, rgb_r_m2;
reg  [15:0]   rgb_g_m0, rgb_g_m1, rgb_g_m2;
reg  [15:0]   rgb_b_m0, rgb_b_m1, rgb_b_m2;
reg  [15:0]   img_y0 ;
reg  [15:0]   img_cb0;
reg  [15:0]   img_cr0;
reg  [ 7:0]   img_y1 ;
reg  [ 7:0]   img_cb1;
reg  [ 7:0]   img_cr1;
reg  [ 2:0]   vs_i_d;
reg  [ 2:0]   de_i_d   ;

//wire define
wire [ 7:0]   rgb888_r;
wire [ 7:0]   rgb888_g;
wire [ 7:0]   rgb888_b;
wire [ 7:0]   img_y;
wire [ 7:0]   img_cb;
wire [ 7:0]   img_cr;

assign rgb888_r         = data_i[23:16];
assign rgb888_g         = data_i[15:8];
assign rgb888_b         = data_i[7:0];
//同步输出数据接口信号
assign vs_o   		= vs_i_d[2]      	;
assign de_o 		= de_i_d[2]         ;
assign img_y		= img_y1 			;
assign img_cb		= img_cb1			;
assign img_cr		= img_cr1			;
assign data_yuv		= {img_y,img_cb,img_cr};		
assign data_gray	= img_y;
/********************************************************
            RGB888 to YCbCr
 Y  = 0.299R +0.587G + 0.114B
 Cb = 0.568(B-Y) + 128 = -0.172R-0.339G + 0.511B + 128
 CR = 0.713(R-Y) + 128 = 0.511R-0.428G -0.083B + 128

 Y  = (77 *R    +    150*G    +    29 *B)>>8
 Cb = (-43*R    -    85 *G    +    128*B)>>8 + 128
 Cr = (128*R    -    107*G    -    21 *B)>>8 + 128

 Y  = (77 *R    +    150*G    +    29 *B        )>>8
 Cb = (-43*R    -    85 *G    +    128*B + 32768)>>8
 Cr = (128*R    -    107*G    -    21 *B + 32768)>>8
*********************************************************/

//step1 计算括号内的各乘法项
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        rgb_r_m0 <= 16'd0;
        rgb_r_m1 <= 16'd0;
        rgb_r_m2 <= 16'd0;
        rgb_g_m0 <= 16'd0;
        rgb_g_m1 <= 16'd0;
        rgb_g_m2 <= 16'd0;
        rgb_b_m0 <= 16'd0;
        rgb_b_m1 <= 16'd0;
        rgb_b_m2 <= 16'd0;
    end
    else begin
        rgb_r_m0 <= rgb888_r * 8'd77 ;
        rgb_r_m1 <= rgb888_r * 8'd43 ;
        rgb_r_m2 <= rgb888_r * 8'd128;
        rgb_g_m0 <= rgb888_g * 8'd150;
        rgb_g_m1 <= rgb888_g * 8'd85 ;
        rgb_g_m2 <= rgb888_g * 8'd107;
        rgb_b_m0 <= rgb888_b * 8'd29 ;
        rgb_b_m1 <= rgb888_b * 8'd128;
        rgb_b_m2 <= rgb888_b * 8'd21 ;
    end
end

//step2 括号内各项相加
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        img_y0  <= 16'd0;
        img_cb0 <= 16'd0;
        img_cr0 <= 16'd0;
    end
    else begin
        img_y0  <= rgb_r_m0 + rgb_g_m0 + rgb_b_m0;
        img_cb0 <= rgb_b_m1 - rgb_r_m1 - rgb_g_m1 + 16'd32768;
        img_cr0 <= rgb_r_m2 - rgb_g_m2 - rgb_b_m2 + 16'd32768;
    end

end

//step3 括号内计算的数据右移8位
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        img_y1  <= 8'd0;
        img_cb1 <= 8'd0;
        img_cr1 <= 8'd0;
    end
    else begin
        img_y1  <= img_y0 [15:8];
        img_cb1 <= img_cb0[15:8];
        img_cr1 <= img_cr0[15:8];
    end
end

//延时3拍以同步数据信号
always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        vs_i_d 		<= 3'd0;
        de_i_d    	<= 3'd0;
    end
    else begin
        vs_i_d 		<= {vs_i_d[1:0], vs_i};
        de_i_d    	<= {de_i_d[1:0], de_i};
    end
end

endmodule

仿真TB文件

注意文件读取和保存的路径

关于一些仿真中用的系统命令可以参考我的testbench中一些常用的系统命令-CSDN博客这篇

本次仿真读取的是txt文件,需要通过matlab或者python将图像转化为txt,具体实现程序可看本人主页文章

`timescale 1ns/1ns

module pic_tb();

//hdmi_tim_gen模块接口

reg             clk,rst_n				;
reg [23:0]      data_in					;

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


//rgb2yuv模块接口

reg  			vs_i,de_i	    ;
wire 			vs_o,de_o	    ;
wire [23:0] 	data_yuv		;
wire [7:0]        data_gray    ;
//延迟1clk,与data同步
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

integer file_out_yuv;
integer file_out_gray;
reg [31:0] out_addr;
initial begin
    file_out_yuv = $fopen("D:/pic/fileout_yuv.txt","w");
    file_out_gray = $fopen("D:/pic/fileout_gray.txt","w");
end

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        out_addr <= 0;
    end
    else if(out_addr == 1280*720)begin
        $display("task finish \n");
        $fclose(file_out_yuv);
        $fclose(file_out_gray);
        $finish;
    end
    else if(de_o)begin
		out_addr <= out_addr + 1;
		$fwrite(file_out_yuv,"%x\n",data_yuv);
		$fwrite(file_out_gray,"%x\n",data_gray);
    end
end




//例化hdmi_tim_gen模块

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)
);


//例化rgb2yuv模块

rgb2yuv u_rgb2yuv
(
    .clk         (clk),  	
    .rst_n       (rst_n),  		
					
    .vs_i    	(vs_i),  	
    .de_i    	(de_i),  	
    .data_i     (hdmi_data),
			
    .vs_o  		(vs_o),  	
    .de_o  		(de_o),  	
    .data_yuv     (data_yuv),
    .data_gray    (data_gray)	
);

endmodule

运行与结果

工程层级

直接在vivado内部仿真即可

 仿真结果

可以看到这部分符合HDMI时序波形

原图

YUV格式

灰度图

结语

本次实验比较简单,直接拷贝到工程,路径也没有问题应该可以直接运行,不过还是把工程附上,供大家免费下载,共同学习。 

【免费】RGB图像转YUV及灰度图FPGA实现工程资源-CSDN文库

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Flutter 开发学习笔记(4):widget布局容器学习

文章目录 前言相关链接Widget 有状态和无状态Flutter 代码风格去掉烦人的括号后缀提示代码缩进 Flutter 布局最简单的布局widgets和Material widgets Dark语法习惯Flutter 布局默认布局Center居中Padding 填充Align对齐默认居中顶部底部右上角 通用 WidgetContainer处于性能原因…

波奇学Linux:tcp滑动窗口

连接建立成功和上层有没有accept没有关系 listen的第一个参数为1&#xff0c;建立的连接数量为2 操作系统底层用队列来管理建立的连接&#xff0c;上层用accept来获取链接 blacklog1 表示底层已经建立好的连接队列的最大长度 超过最大长度的连接&#xff0c;服务端不会丢弃…

STM32CubeMX配置步骤详解零 —— 引言

引子 初识 笔者接触STM32系列MCU有些年头了。初次接触是2015年&#xff0c;那时是在第二空间&#xff08;北京&#xff09;科技有限公司上班&#xff0c;是以STM32F407&#xff08;后缀好像是RGT6或ZGT6&#xff0c;记得不是很清楚了&#xff09;为主芯片做VR头戴式设备&…

SpringBoot整合Activiti7——实战之出差流程(分支)

文章目录 代码实现部署流程启动流程查询任务填写出差审批单经理审批xml文件 出差流程&#xff1a;开始 - 填写出差表单 - 判断&#xff08;出差天数大于等于5&#xff09;- 副经理审批 - 否则总经理审批 - 完成 代码实现 部署流程 Testpublic void testDeployProcess() throws …

物联网实战--入门篇之(九)安卓QT--开发框架

目录 一、QT简介 二、开发环境 三、编码风格 四、设计框架 五、总结 一、QT简介 QT是一款以C为基础的开发工具&#xff0c;已经包含了很多常用的库&#xff0c;除了基本的GUI以外&#xff0c;还有网络、数据库、多媒体、进程通信、串口、蓝牙等常用库&#xff0c;开发起来…

mysql 正则表达式查询

学习了mysql 连接查询和子查询和myql join连接&#xff0c;接下来学习下正则表达式查询。正则表达式的规则都是相似的。 8&#xff0c;使用正则表达式查询 正则表达式通常被用来检索或替换那些符合某个模式的文本内容,根据指定的匹配模式匹配文本中符合要求的特殊字符串。例如从…

绿色wordpress外贸建站模板

绿色wordpress外贸建站模板 https://www.mymoban.com/wordpress/6.html

PAC下的ROP问题

Armv8.3-A引入了pointer authentication选项。 pointer authentication可以减轻ROP攻击。 为了防止ROP攻击&#xff0c;在函数开始时&#xff0c;LR寄存器中的返回地址被签名。这意味着在寄存器的高位添加了一个PAC。在返回之前&#xff0c;使用PAC对返回地址进行验证。如果检查…

Linux 环境下 Redis基础配置及开机自启

Linux 环境下 Redis基础配置及开机自启 linux环境安装redis<redis-6.0.5.tar.gz> 1-redis基本安装配置 解压 获取到tar包后&#xff0c;解压到相关目录&#xff0c;一般是将redis目录放在usr/local/redis目录下&#xff0c;可以使用-C指定到解压下目录 tar -zvxf re…

HCIA-RS基础-以太网设备工作原理

目录 以太网设备工作原理1. HUB 的工作原理2. L2 交换机的工作原理3. L3 交换机的工作原理 总结 以太网设备工作原理 以太网是一种常用的局域网技术&#xff0c;用于在计算机网络中传输数据。在以太网中&#xff0c;有几种常见的设备&#xff0c;包括 HUB、L2 交换机和 L3 交换…

PyQt qrc2py 使用PowerShell将qrc文件转为py文件并且将导入模块PyQt或PySide转换为qtpy模块开箱即用

前言 由于需要使用不同的qt环境&#xff08;PySide&#xff0c;PyQt&#xff09;所以写了这个脚本&#xff0c;使用找到的随便一个rcc命令去转换qrc文件&#xff0c;然后将导入模块换成qtpy这个通用库(支持pyside2-6&#xff0c;pyqt5-6)&#xff0c;老版本的是Qt.py(支持pysi…

BIM转Power BI数据集

在本博客中&#xff0c;我们将了解如何使用从 SSAS 表格、Power BI Desktop 或 Power BI 服务数据集中提取的 Model.bim 文件在本地或 PBI 服务上生成新数据集。 1、设置&#xff08;SSAS 表格和 PBI 服务通用&#xff09; 我建议你创建一个专门用于此任务的新 Python 环境&a…

hibernate session接口

hibernate session接口 Session接口是hibernate向应用程序提供的操纵数据库的最主要的接口&#xff0c;提供了保存、更新、删除和加载Java对象的方法。 session具有一个缓存&#xff0c;位于缓存中的对象成为持久化对象&#xff0c;和数据库中的相关记录对应。session能够在某些…

vue3中怎么点击按钮就上传文件

<el-button text type"primary" click"importBillExcel(row)">导入账单</el-button> // 导入客户账单Excel表 const importBillExcel (row) > {let input document.createElement(input)input.type fileinput.accept .pdf, .png, .zip…

摸鱼123

摸鱼https://toyaml.com/windowsupdate.html

3D模型格式转换工具HOOPS Exchange如何将3D文件加载到PRC数据结构中?

HOOPS Exchange是一款高效的数据访问工具&#xff0c;专为开发人员设计&#xff0c;用于在不同的CAD&#xff08;计算机辅助设计&#xff09;系统之间进行高保真的数据转换和交换。由Tech Soft 3D公司开发&#xff0c;它支持广泛的CAD文件格式&#xff0c;包括但不限于AutoCAD的…

js手持小风扇

文章目录 1. 演示效果2. 分析思路3. 代码实现 1. 演示效果 2. 分析思路 先编写动画&#xff0c;让风扇先转起来。使用 js 控制动画的持续时间。监听按钮的点击事件&#xff0c;在事件中修改元素的animation-duration属性。 3. 代码实现 <!DOCTYPE html> <html lang…

Spring IOC控制反转、DI注入以及配置

1.使用xml的方式进行配置IOC容器&#xff0c;首先引入依赖 在Resource资源下配置&#xff0c;applicationContext.xml ,刷新mevan后可以直接选择配置spring.xml文件 <!-- spring核心用来管理bean --><dependency><groupId>org.springframework</g…

代码随想录算法训练营Day42|LC416 分割等和子集

一句话总结&#xff1a;背包问题。 原题链接&#xff1a;416 分割等和子集 拿到题先明确这是动态规划的题&#xff0c;具体类型是01背包问题。到了题目解法这里&#xff0c;首先判断数组加和是否为偶数&#xff0c;否则return false。然后就是01背包问题的解题思路了。具体地&…

InterliJ IDEA基本设置

安装好idea后&#xff0c;将软件打开&#xff0c;可以进行基础设置 1.打开软件&#xff0c;先安装插件-汉化包&#xff08;不推荐&#xff0c;最好使用英文版&#xff09;&#xff0c;本次我们使用汉化版本完成基本设置&#xff0c;后期希望大家适应英文版的开发环境。&#x…