昨天才更新了两篇博客,今天又要更新了,并不是我垃圾产,只不过这些在上个月就已经写好了,只是因为比赛忙,一直腾不出时间整理出来发表而已,但是做完一件事情总感觉不写一博文总结一下就少点什么,所以之后的一段时间里我会把我这学期学到的一些东西陆续整理出来发表,给自己一个总结交代。

  将彩色图像转化为灰度的方法有两种,一个是令RGB三个分量的数值相等,输出后便可以得到灰度图像,另一种是转化为YCbCr格式,将Y分量提取出来,YCbCr格式中的Y分量表示的是图像的亮度和浓度所以只输出Y分量,得到的图像就是灰度图像了。我在这里选择第二种方法实现。

  YCBCr是通过有序的三元组来表示的,三元由Y(Luminance)、Cb(Chrominance-Blue)和Cr(Chrominance-Red)组成,其中Y表示颜色的明亮度和浓度,而Cb和Cr则分别表示颜色的蓝色浓度偏移量和红色浓度偏移量。人的肉眼对由YCbCr色彩空间编码的视频中的Y分量更敏感,而Cb和Cr的微小变化不会引起视觉上的不同,根据该原理,通过对Cb和Cr进行子采样来减小图像的数据量,使得图像对存储需求和传输带宽的要求大大降低,从而达到在完成图像压缩的同时也保证了视觉上几乎没有损失的效果,进而使得图像的传输速度更快,存储更加方便。我们要的到灰度图像,首先要将采集到的彩色图像转化为YCbCr。

  我们配置摄像头采集到的数据是RGB565的格式,官方给出的转化公式是RGB888->YCbCr,所以先需要将RGB565转化为RGB888,转化方法如下:

  24bit RGB888 -> 16bit RGB565 的转换(只取高位)

  24ibt RGB888 {R7 R6 R5 R4 R3 R2 R1 R0} {G7 G6 G5 G4 G3 G2 G1 G0} {B7 B6 B5 B4 B3 B2 B1 B0}

  16bit RGB656 {R7 R6 R5 R4 R3} {G7 G6 G5 G4 G3 G2} {B7 B6 B5 B4 B3}

  同样也可以恢复回去。

  16bit RGB565 -> 24bit RGB888 的转换(高位补低位)

  16bit RGB656 {R4 R3 R2 R1 R0} {G5 G4 G3 G2 G1 G0} {B4 B3 B2 B1 B0}

  24ibt RGB888 {R4 R3 R2 R1 R0 R2 R1 R0} {G5 G4 G3 G2 G1 G0 G1 G0} {B4 B3 B2 B1 B0 B2 B1 B0}

 //--------------------------------------------
//RGB565 to RGB 888
wire [:] cmos_R0;
wire [:] cmos_G0;
wire [:] cmos_B0; assign cmos_R0 = {cmos_R, cmos_R[:]};
assign cmos_G0 = {cmos_G, cmos_G[:]};
assign cmos_B0 = {cmos_B, cmos_B[:]};

  采用高位补低位的方法直接转化即可。

  这是官方给的RGB888 to YCbCr的算法公式,我们可以直接把算法移植到FPGA上,但是我们都知道FPGA无法进行浮点运算,所以我们采取将整个式子右端先都扩大256倍,然后再右移8位,这样就得到了FPGA擅长的乘法运算和加法运算了。

  这个计算式子看起来是十分简单的,但是要是直接用Verilog直接写出来,那么只能说,这个人的代码写的一塌糊涂,所以这里就引出FPGA中流水线的设计思想。

在这里我们选择加3级流水线,就第一个Y分量而言,先计算括号中得乘法运算,消耗一个时钟,然后将括号中的数据求和,消耗一个时钟,这里为了计算方便,将128也扩大256倍,放到括号中,最终结果除以256就行了也就是右移8位,在FPGA中我们只需要舍弃低8位取高8位就行。具体代码如下

 //--------------------------------------------
/*Refer to <OV7725 Camera Module Software Applicaton Note> page 5
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*/
//--------------------------------------------
//RGB888 to YCrCb
//step1 conmuse 1clk
reg [:] cmos_R1, cmos_R2, cmos_R3;
reg [:] cmos_G1, cmos_G2, cmos_G3;
reg [:] cmos_B1, cmos_B2, cmos_B3;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)begin
cmos_R1 <= 'd0;
cmos_G1 <= 'd0;
cmos_B1 <= 'd0;
cmos_R2 <= 'd0;
cmos_G2 <= 'd0;
cmos_B2 <= 'd0;
cmos_R3 <= 'd0;
cmos_G3 <= 'd0;
cmos_B3 <= 'd0;
end
else begin
cmos_R1 <= cmos_R0 * 'd77;
cmos_G1 <= cmos_G0 * 'd150;
cmos_B1 <= cmos_B0 * 'd29;
cmos_R2 <= cmos_R0 * 'd43;
cmos_G2 <= cmos_G0 * 'd85;
cmos_B2 <= cmos_B0 * 'd128;
cmos_R3 <= cmos_R0 * 'd128;
cmos_G3 <= cmos_G0 * 'd107;
cmos_B3 <= cmos_B0 * 'd21;
end
end //-----------------------------------------------
//step2 consume 1clk
reg [:] img_Y0;
reg [:] img_Cb0;
reg [:] img_Cr0; always @(posedge clk or negedge rst_n)
begin
if(!rst_n)begin
img_Y0 <= 'd0;
img_Cb0 <= 'd0;
img_Cr0 <= 'd0;
end
else begin
img_Y0 <= cmos_R1 + cmos_G1 + cmos_B1;
img_Cb0 <= cmos_B2 - cmos_R2 - cmos_G2 + 'd32768;
img_Cr0 <= cmos_R3 - cmos_G3 - cmos_B3 + 'd32768;
end end
//-------------------------------------------
//step3 conmuse 1clk
reg [:] img_Y1;
reg [:] img_Cb1;
reg [:] img_Cr1; always @(posedge clk or negedge rst_n)
begin
if(!rst_n)begin
img_Y1 <= 'd0;
img_Cb1 <= 'd0;
img_Cr1 <= 'd0;
end
else begin
img_Y1 <= img_Y0 [:];
img_Cb1 <= img_Cb0 [:];
img_Cr1 <= img_Cr0 [:];
end end

流水线

  对于流水线的理论详细解释,请看我另一篇博文:http://www.cnblogs.com/ninghechuan/p/6970750.html

  将RGB565—>YCbCr成功后,提取出Y的值输出,就可以得到灰度色彩的图像了。

  将采集到的RGB565的像素数据,输入到算法处理模块进行操作,由RGB565——>YCbCr——Gray官方给出的公式来算,先将RGB565拆分开R G B三个分量,使用如上公式计算的到Y Cb Cr是三个分量。

  RGB转YCbCr算法的仿真过程,从图中可以看出,加了流水线后的运算过程,每一级运算相差一个时钟,然而每一级都在进行新的运算,我们加了3级流水线,这样运算速度可以提升3倍。

  将行信号、场信号和像素数据使能信号进行延时,消耗多少周期便延时几个周期,保持时钟的同步性。

  最后将Y分量的数据输出,进行位拼接,16位的RGB565像素R、G、B分量分别对应的取Y分量的高位,最后的输出显示出来就是灰度图像了。

 assign lcd_data = {per_img_Y1 [:],per_img_Y1 [:],per_img_Y1 [:]};//Gray

  这里还是采用高位补低位的方法。

  最终下载到FPGA开发板上,显示如下:

  图上为灰度显示,图下为转化前的原图,可以看出,灰度最终显示的是将彩色图像的颜色过滤掉,这样减小了图像的体积,滤掉多余的影响因素,为后面的滤波,边缘检测等图像处理做出关键性的基础。

转载请注明出处:NingHeChuan(宁河川)

个人微信订阅号:开源FPGANingHeChuan

如果你想及时收到个人撰写的博文推送,可以扫描左边二维码(或者长按识别二维码)关注个人微信订阅号

知乎ID:NingHeChuan

微博ID:NingHeChuan

原文地址:http://www.cnblogs.com/ninghechuan/p/6978104.html

基于FPGA的彩色图像转灰度算法实现的更多相关文章

  1. 基于FPGA的中值滤波算法实现

    在这一篇开篇之前,我需要解决一个问题,上一篇我们实现了基于FPGA的均值滤波算法的实现,最后的显示效果图上发现有一些黑白色的斑点,我以为是椒盐噪声,然后在做基于FPGA的中值滤波算法的实验时,我发现黑 ...

  2. 基于FPGA的均值滤波算法的实现

    前面实现了基于FPGA的彩色图像转灰度处理,减小了图像的体积,但是其中还是存在许多噪声,会影响图像的边缘检测,所以这一篇就要消除这些噪声,基于灰度图像进行图像的滤波处理,为图像的边缘检测做好夯实基础. ...

  3. 基于FPGA的腐蚀膨胀算法实现

    本篇文章我要写的是基于的腐蚀膨胀算法实现,腐蚀膨胀是形态学图像处理的基础,,腐蚀在二值图像的基础上做"收缩"或"细化"操作,膨胀在二值图像的基础上做" ...

  4. 基于FPGA的均值滤波算法实现

    我们为了实现动态图像的滤波算法,用串口发送图像数据到FPGA开发板,经FPGA进行图像处理算法后,动态显示到VGA显示屏上,前面我们把硬件平台已经搭建完成了,后面我们将利用这个硬件基础平台上来实现基于 ...

  5. 基于FPGA的Sobel边缘检测的实现

    前面我们实现了使用PC端上位机串口发送图像数据到VGA显示,通过MATLAB处理的图像数据直接是灰度图像,后面我们在此基础上修改,从而实现,基于FPGA的动态图片的Sobel边缘检测.中值滤波.Can ...

  6. 【转】基于FPGA的Sobel边缘检测的实现

    前面我们实现了使用PC端上位机串口发送图像数据到VGA显示,通过MATLAB处理的图像数据直接是灰度图像,后面我们在此基础上修改,从而实现,基于FPGA的动态图片的Sobel边缘检测.中值滤波.Can ...

  7. 基于FPGA的HDTV视频图像灰度直方图统计算法设计

    随着HDTV的普及,以LCD-TV为主的高清数字电视逐渐进入蓬勃发展时期.与传统CRT电视不同的是,这些高清数字电视需要较复杂的视频处理电路来驱动,比如:模数转换(A/D Converter).去隔行 ...

  8. 基于FPGA的RGB565_YCbCr_Gray算法实现

    前面我们讲了基于FPGA用VGA显示一副静态图片,那么接下来我们就接着前面的工程来实现我们图像处理的基础算法里最简单的一个那就是彩色图像转灰度的实现. 将彩色图像转化为灰度的方法有两种,一个是令RGB ...

  9. 基于FPGA的肤色识别算法实现

    大家好,给大家介绍一下,这是基于FPGA的肤色识别算法实现. 我们今天这篇文章有两个内容一是实现基于FPGA的彩色图片转灰度实现,然后在这个基础上实现基于FPGA的肤色检测算法实现. 将彩色图像转化为 ...

随机推荐

  1. STM32实战应用(一)——1602蓝牙时钟1液晶的显示测试

    前言 从51到STM32F4学习这么久了,总算找到点头绪了,目前学习了GPIO,中断,定时器,看门狗的基本使用,所以想试着看看能不能做个什么东西,就是想复习一下最近学习的知识.正好上学期单片机课程设计 ...

  2. [ext4]03 磁盘布局 – Flexible group分析

    Flexible Block Groups (flex_bg),我称之为"弹性块组",是EXT4文件系统引入的一个feature. 所谓Flexible Block Groups, ...

  3. ie8兼容background-size属性

    满心欢喜地写代码,最后测试兼容性的时候发现Logo图片在IE8下特别大.明显是background-size在ie8一下不兼容. 我懂得,IE8还是个孩子,我就加几句你独有的代码让你兼容吧,司空见惯了 ...

  4. SCP“免密” 远程COPY较多文件

    一.linux脚本实现自动输入密码 使用Linux的程序员对输入密码这个举动一定不陌生,在Linux下对用户有严格的权限限制,干很多事情越过了权限就得输入密码,比如使用超级用户执行命令,又比如ftp. ...

  5. Linux下安装Oracle的两种方式------有图形界面安装和静默安装

    本文参考文章 http://blog.csdn.net/zonej/article/details/50680857 http://blog.csdn.net/tongzidane/article/d ...

  6. Nginx 反向代理&负载均衡

    1.反向代理 当我们请求一个网站时,nginx会决定由哪台服务器提供服务,就是反向代理. nginx只做请求的转发,后台有多个tomcat服务器提供服务,nginx的功能就是把请求转发给后面的服务器, ...

  7. [大数据]-Elasticsearch5.3.1+Kibana5.3.1从单机到分布式的安装与使用<2>

    前言:上篇[大数据]-Elasticsearch5.3.1+Kibana5.3.1从单机到分布式的安装与使用<1>中介绍了ES ,Kibana的单机到分布式的安装,这里主要是介绍Elast ...

  8. 思考题:用Use Case获取需求的方法是否有什么缺陷,还有什么地方需要改进?(提示:是否对所有的应用领域都适用?使用的方便性?.......)

    思考题: 用Use Case获取需求的方法是否有什么缺陷,还有什么地方需要改进?(提示:是否对所有的应用领域都适用?使用的方便性?.......) 简答: 一.用例解释: 在软件工程中,用例是一种在开 ...

  9. redis多数据库操作

    redis下,数据库是由一个整数索引标识,而不是由一个数据库名称.默认情况下,一个客户端连接到数据库0. redis配置文件中下面的参数来控制数据库总数: databases 16   [root@M ...

  10. Python变量运算字符串等

    一,作用域 操作 name = 'liuyueming' if 1==1:... print name... liuyueming 两次回车执行 修改代码 >>> if 1==1:. ...