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类型 ...
随机推荐
- IO多路复用和协程
1.IO多路复用 作用:检测多个socket是否已经发生变化(是否连接成功/是否已经获取数据) 什么是进程.线程.协程以及它们的区别? 进程是资源分配的最小单元,其作用是进行数据隔离, 线程是cpu调 ...
- android project
- Dagger2不自动生成daggerXXXcomponent
在Fragment里面初始化dagger2创建对象时,不自动生成daggerXXXcomponent. 百思不得其解,后来发现是import android.app.Fragment;所以不自动生成. ...
- sql server中截取字符串的常用函数
我们如果要在sql server中,使用截取字符串的方法要怎样使用呢? sql server提供了3个常用截取字符串方法,LEFT().RIGHT().SUBSTRING() /****** Sql ...
- JQuery操作input
// 不可编辑 $("#id").attr("disabled","disabled"); $("#id").remov ...
- NLTK 3.2.2 安装经验
NLTK 3.2.2 安装经验 Nltk 3.2.2要求Python版本是Python2.7 或者Python3.4+. Nltk 3.2.3 如果是从网站上直接下载程序进行安装可能会报错:Pytho ...
- .NET读取视频信息、视频截图
在.NET中处理视频是一件痛苦的事情,.NET并没有提供视频处理的类.于是咱们只能找一些第三方的类库或者自己实现,在项目时间比较赶的情况下,自己实现是不可能的了,而且说不定会留下很多坑.所以一般情况下 ...
- bzoj2301
题解: 莫比乌斯反演 再加上一个分块 然后和上一题差不多了 代码: #include<cstdio> #include<cmath> #include<algorithm ...
- 第二篇 界面开发 (Android学习笔记)
第二篇 界面开发 第5章 探索界面UI元素 ●The Android View Class ●△Widget设计步骤 需要修改三个XML,以及一个class: 1)第一个xml是布局XML文件 ...
- Asp.Net WebApi核心对象解析(一)
生活需要自己慢慢去体验和思考,对于知识也是如此.匆匆忙忙的生活,让人不知道自己一天到晚都在干些什么,似乎每天都在忙,但又好似不知道自己到底在忙些什么.不过也无所谓,只要我们知道最后想要什么就行.不管怎 ...