verilog实现rgb2gray
前言
项目算法需求,需要将RGB彩色图像转换为灰度图像,算法原理是很简单的,但是对于刚接触FPGA的宝宝来说,进行时序的设计和调试还是不那么容易的,为了省事儿,就按照上一篇中值滤波(http://www.cnblogs.com/happyamyhope/p/5577898.html)的结构进行设计。开始的开始,只能根据已经做好的设计照葫芦画瓢,否则调试还是很繁琐的,主要是因为目前还是掌握不了时序设计的精髓和思路,慢慢来吧。
实验步骤:
1.实验原理介绍;
2.编写各模块的代码;
3.调试仿真,并与matlab中rgb2gray函数的结果进行比较;
实验过程:
1.实验原理介绍;
matlab中rgb2gray函数的原理还是比较简单的,最后输出的灰度图像是RGB三种颜色通道的加权和;
rgb2gray converts RGB values to grayscale values by forming a weighted sum of the R, G, and B components: 0.2989 * R + 0.5870 * G + 0.1140 * B
上面就是MATLAB中rgb2gray函数的算法原理;
本模块输入的是8bits的三通道彩色图像数据,输出的也是8bits的数据,至于整体算法模块的小数,有待到时候进行一下整合,改变数据的位数。
为了不涉及到小数,我们将数据整体左移16位即乘以65536,根据matlab中的算法原理进行设计:
gray <= 19589 * red + 38469 * green + 7471 * blue;
//gray <= 19595 * red + 38469 * green + 7472 * blue;
查看了一些资料,比如: http://www.cnblogs.com/diewcs/archive/2010/10/03/1841744.html
2.编写个模块的代码;
先将计数器控制模块和rgb2gray进行调试仿真,再将两个模块综合到一起进行调试仿真,得到最终的结果。
主要是计数器控制模块,如何正确得到正确时序的地址数据。
1)计数器控制模块:
module counter_ctrl( CLK,
RSTn,
iCall,
iNxt_pix,
oAddr,
oDone ); input CLK;
input RSTn;
input iCall;
input iNxt_pix;
output [:] oAddr;
output oDone; reg [:] imk;
reg isDone ; reg start_sig_d; wire start_sig_rising_vld; always @ (posedge CLK or negedge RSTn) //Asynchronous reset
if ( !RSTn )
start_sig_d <= ;
else
start_sig_d <= iCall; assign start_sig_rising_vld = iCall & (~start_sig_d); always @ ( posedge CLK or negedge RSTn )
if ( !RSTn ) begin
imk <= 'd0;
isDone <= 'b0;
end
else if ( start_sig_rising_vld )
begin
imk <= 'b1;
isDone <= 'b1;
end
else if ( iNxt_pix ) // & ( imk != 166222 )
begin
imk <= imk + 'b1;
isDone <= 'b1;
end
else isDone <= 'b0; assign oAddr = imk;
assign oDone = isDone; endmodule
模块通过计数控制得到将要读取图像数据的地址,需要注意的是何时开始获取数据初始地址,何时开始地址开始进行加一计数。
testbench模块:
module ctrl_tb;
// Inputs
reg CLK;
reg RSTn;
reg iCall;
// Outputs
wire [:] oAddr;
wire oDone;
// Instantiate the Unit Under Test (UUT)
counter_ctrl uut (
.CLK(CLK),
.RSTn(RSTn),
.iCall(iCall),
.oAddr(oAddr),
.oDone(oDone)
);
initial begin
// Initialize Inputs
CLK = ;
RSTn = ;
iCall = ;
// Wait 100 ns for global reset to finish
#;
RSTn = ;
iCall = ;
// Add stimulus here
end
always # CLK = ~CLK;
always @ ( posedge CLK or RSTn )
if ( oDone )
$display("%d\n", oAddr );
always @ ( posedge CLK or RSTn )
if ( oAddr == 'd200 )
begin
iCall <= ;
$stop;
end
endmodule
2)rgb2gray算法模块;
// matlab algorithm:gray = 0.2989 * R + 0.5870 * G + 0.1140 * B;
// move left by 16bits: gray = 19589 * R + 38469 * G + 7471 * B;
module rgb2gray( CLK,
RSTn,
iCall,
iRed,
iGreen,
iBlue,
oGray,
oDone ); input CLK;
input RSTn;
input iCall;
//input [23:0] iRGB;
input [:] iRed;
input [:] iGreen;
input [:] iBlue; output [:] oGray;
output oDone; reg [:] red;
reg [:] green;
reg [:] blue; reg [:] gray;
reg [:] i;
reg isDone; /********************************************************************************/ reg get_pix_vld; always @ ( posedge CLK or negedge RSTn )
if (!RSTn)
get_pix_vld <= 'b0;
else if ( iCall )
get_pix_vld <= 'b1;
else if ( i=='d2 )
get_pix_vld <= 'b0; always @ ( posedge CLK or negedge RSTn )
if ( !RSTn ) begin
red <= 'd0;
green <= 'd0;
blue <= 'd0;
end
else if ( iCall ) begin
red <= iRed ;
green <= iGreen;
blue <= iBlue ;
end always @ ( posedge CLK or negedge RSTn )
if ( !RSTn ) begin
i <= 'd0;
gray <= 'd0;
isDone <= 'b0;
end
else if ( get_pix_vld )
case ( i )
: begin
//gray <= 19595 * iRGB[23:16] + 38469 * iRGB[15:8] + 7472 * iRGB[7:0];
gray <= * red + * green + * blue;
//gray <= 19595 * red + 38469 * green + 7472 * blue;
i <= i + 'b1;
end
: begin isDone <= 'b1; i <= i + 1'b1; end
: begin isDone <= 'b0; i <= 3'd0; end
endcase assign oGray = ( gray >> ) ;
assign oDone = isDone ; endmodule
将输入的三色通道图像数据转换为灰度图像。
3)创建IP ROM核,将彩色图象数据分通道储存在ROM中,具体操作步骤请参考
http://www.cnblogs.com/happyamyhope/p/5498745.html
图像大小是383*434,共R、G、B三个通道。

4)顶层模块:
将低层各个模块联系起来,得到rgb2gray的整体模块。
module rgb_gray(
CLK,
RSTn,
Start,
Gray,
Done
); input CLK;
input RSTn;
input Start; output [:] Gray;
output Done; /*****************************************************************************/ wire [:] addra ;
wire [: ] red ;
wire [: ] green ;
wire [: ] blue ; imLr imLr_inst(
.clka ( CLK ),
.addra ( addra ),
.douta ( red )
); imLg imLg_inst(
.clka ( CLK ),
.addra ( addra ),
.douta ( green )
); imLb imLb_inst(
.clka ( CLK ),
.addra ( addra ),
.douta ( blue )
); /*****************************************************************************/ wire done_ctrl;
wire done_gray; counter_ctrl counter_ctrl_inst( .CLK ( CLK ),
.RSTn ( RSTn ),
.iCall ( Start ),
.iNxt_pix( done_gray ),
.oAddr ( addra ),
.oDone ( done_ctrl )
); wire [:] gray; rgb2gray rgb2gray_inst( .CLK ( CLK ) ,
.RSTn ( RSTn ) ,
.iCall ( done_ctrl ) ,
.iRed ( red ) ,
.iGreen ( green ) ,
.iBlue ( blue ) ,
.oGray ( gray ) ,
.oDone ( done_gray )
); /*****************************************************************************/ assign Gray = gray;
assign Done = done_gray; endmodule
顶层模块需要注意不同模块之间数据的连接,以数据线的形式相连,故要使用wire类型。
5)testbench模块:
module rgb_gray_tb;
// Inputs
reg CLK;
reg RSTn;
reg Start;
reg [:] pix_cnt;
// Outputs
wire [:] Gray;
wire Done ;
integer fout ;
// Instantiate the Unit Under Test (UUT)
rgb_gray rgb_gray_inst (
.CLK(CLK),
.RSTn(RSTn),
.Start(Start),
.Gray(Gray),
.Done(Done)
);
initial begin
// Initialize Inputs
CLK = ;
RSTn = ;
Start = ;
pix_cnt = ;
fout = $fopen( "rgb2gray_re.txt" );
// Wait 100 ns for global reset to finish
#;
RSTn = ;
Start = ;
pix_cnt = ;
// Add stimulus here
#; // To start the system
// Add stimulus here
RSTn = ;
pix_cnt = ;
end
always # CLK = ~CLK;
always @ ( posedge CLK )
if ( Done )
pix_cnt <= pix_cnt + 'b1;
always @ ( posedge CLK )
if ( pix_cnt == 'd166223 ) begin
Start <= ;
$display("Image rgb2gray Completed!\n");
$display("The all time is %d \n",$time);
$stop;
end
always @ ( posedge CLK )
if ( Done ) begin
$fwrite(fout, "%d", Gray, "\n");
$display("%d, %d ",pix_cnt, Gray);
end
endmodule
结果图片:

前一张图片,在最后两个像素的时候代码出现了警告,不知道是什么原因,不过最后的结果没有错误。
后一张图片可以看出前几个像素点得到的算法结果。
3.调试仿真,并与matlab中rgb2gray函数的结果进行比较:
matlab的比较代码:
% code to create image data from rgb2gray txt file
clc;
clear all;
close all; I_rgb = imread('imL.png');
subplot(2, 2, 1), imshow(I_rgb), title('imL-rgb') I_gray = rgb2gray(I_rgb);
[m, n] = size(I_gray);
subplot(2, 2, 3), imshow(I_gray), title('imL-rgb2gray-mfunc') rgb2gray_v_load = load('.\rgb2gray_re.txt'); % verilog 产生的rgb2gray数据
rgb2gray_v = reshape(rgb2gray_v_load, n, m);
rgb2gray_v = uint8(rgb2gray_v'); diff = I_gray - rgb2gray_v;
subplot(2, 2, 4), imshow(rgb2gray_v), title('rgb2gray-verilog');
最后的数据结果显示,verilog的算法结果与matlab函数的处理结果相比较,差值在1个像素之内。
显示结果:

可以看出,最后的结果相差无几,Good!
实验结论:
因为有中值滤波的基础,基于此,实现rgb2gray的算法设计还是比较简单的,不过也还是弄得有点久,最重要的是时序的设计,在调试仿真的过程中让宝宝比较烦恼的就是时序问题,是在是搞不懂FPGA的时序到底是怎么回事儿,就算明白了时序的问题还会有一些该有的延时或者该考虑的时序没有考虑到,还有,就算考虑到了,可是编写代码还是硬伤。
加油吧,少年!
完
verilog实现rgb2gray的更多相关文章
- verilog实现中值滤波
前言 项目需要,想要实现算法中的其中一步即中值滤波,同时,因为图像处理部分中值滤波相对来说还是比较简单的,将中值滤波的硬件实现作为进入FPGA领域的第一次尝试.虽然说网上有较多关于中值滤波的文档,可是 ...
- Verilog学习笔记简单功能实现(二)...............全加器
先以一位全加器为例:Xi.Yi代表两个加数,Cin是地位进位信号,Cout是向高位的进位信号.列表有: Xi Yi Cin Sum Cout 0 0 0 0 0 0 0 1 1 0 ...
- Verilog HDL模型的不同抽象级别
所谓不同的抽象类别,实际上是指同一个物理电路,可以在不同层次上用Verilog语言来描述.如果只从行为功能的角度来描述某一电路模块,就称作行为模块.如果从电路结构的角度来描述该电路模块,就称作结构模块 ...
- Verilog学习笔记基本语法篇(十二)········ 编译预处理
h Verilog HDL语言和C语言一样也提供编译预处理的功能.在Verilog中为了和一般的语句相区别,这些预处理语句以符号"`"开头,注意,这个字符位于主键盘的左上角,其对应 ...
- Verilog学习笔记基本语法篇(十一)········ 常用系统函数
1)系统任务:$monitor 格式: $monitor(p1,p2,p3...pn); $monitor; $monitoron; $monitoroff; 任务$monitor提供了监控输出列 ...
- FPGA作为从机与STM32进行SPI协议通信---Verilog实现 [转]
一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用 ...
- 基于Verilog HDL整数乘法器设计与仿真验证
基于Verilog HDL整数乘法器设计与仿真验证 1.预备知识 整数分为短整数,中整数,长整数,本文只涉及到短整数.短整数:占用一个字节空间,8位,其中最高位为符号位(最高位为1表示为负数,最高位为 ...
- system verilog中的跳转操作
在verilog中,使用disable声明来从执行流程中的某一点跳转到另一点.特别地,disable声明使执行流程跳转到标注名字的声明组末尾,或者一个任务的末尾. verilog中的disable命令 ...
- system verilog中的类型转换(type casting)、位宽转换(size casting)和符号转换(sign casting)
类型转换 verilog中,任何类型的任何数值都用来给任何类型赋值.verilog使用赋值语句自动将一种类型的数值转换为另一种类型. 例如,当一个wire类型赋值给一个reg类型的变量时,wire类型 ...
随机推荐
- 基本数据类型int,bool,str
.基本数据类型(int,bool,str) 基本数据数据类型: int 整数 str 字符串. 一般不存放大量的数据 bool 布尔值. 用来判断. True, False list 列表.用来存放大 ...
- 关于TCP长连接和发送心跳的一些理解
原因 TCP是一种有连接的协议,但是这个连接并不是指有一条实际的电路,而是一种虚拟的电路.TCP的建立连接和断开连接都是通过发送数据实现的,也就是我们常说的三次握手.四次挥手.TCP两端保存了一种数据 ...
- 巧用call,appl有 根据对象某一属性求最大值
查找对象数组中某属性的最大最小值的快捷方法 例如要查找array数组中对象的value属性的最大值 var array=[ { "index_id": 119, "are ...
- python xlrd使用
python xlrd使用 1● xlrd安装 管理员模式 success 2● 引用 import xlrd
- 由@Convert注解引出的jackson对枚举的反序列化规则
对于一些状态字段以前时兴用常量,现在时兴用枚举,虽然阅读体验极佳,但是传值的时候还是会有些麻烦,需要设置一下转换器.比如: class A{ @Convert(converter=TestTypeCo ...
- Win10系列:JavaScript综合实例2
在项目中添加一个名为pages的文件夹,并在pages文件夹里面再添加一个名为mainPage的文件夹,接着在mainPage文件夹里添加一个"页面控制"项,命名为mainPage ...
- 首席科学家马丁•福勒(Martin Fowler)
现任思特沃克公司首席科学家的马丁·福勒先生是当今世界软件开发领域最具影响力的五位大师之一.作为一位敏捷软件开发方法的早期开拓者,福勒先生对IT 业的影响是不可估量的. 思特沃克公司是一家跨国专业IT ...
- sqlalchemy动态组合查询语句。
if filter_type == 1: search = and_(GameRoom.status ==1,or_( and_(GameRoom.white_user_id == user_id, ...
- MATLAB 图像归一化
matlab图像处理为什么要归一化和如何归一化一.为什么归一化1. 基本上归一化思想是利用图像的不变矩寻找一组参数使其能够消除其他变换函数对图像变换的影响.也就是转换成唯一的标准形式以抵抗仿射变换 ...
- 4.6 C++抽象基类和纯虚成员函数
参考:http://www.weixueyuan.net/view/6376.html 总结: 在C++中,可以通过抽象基类来实现公共接口 纯虚成员函数没有函数体,只有函数声明,在纯虚函数声明结尾加上 ...