zoukankan      html  css  js  c++  java
  • FPGA实现图像灰度转换(2):RGB转YCbCr转Gray

      本篇博客整理一下 RGB565 转 RGB888,再转YCbCr444的算法,最后取 YCbCr 的 Y 分量即可实现 Gray 灰度效果。

    一、YCbCr介绍

      “YCbCr或Y'CbCr有的时候会被写作:YCBCR或是Y'CBCR,是色彩空间的一种,通常会用于影片中的影像连续处理,或是数字摄影系统中。Y'为颜色的亮度(luma)成分、而CB和CR则为蓝色和红色的浓度偏移量成份。Y'和Y是不同的,而Y就是所谓的亮度(luminance),表示光的浓度且为非线性,使用伽马修正(gamma correction)编码处理。

      正如几何上用坐标空间来描述坐标集合,色彩空间用数学方式来描述颜色集合。常见的3 个基本色彩模型是RGB,CMYKYUV。YCbCr 则是在世界数字组织视频标准研制过程中作为ITU - R BT.601 建议的一部分,其实是YUV经过缩放和偏移的翻版。其中Y与YUV 中的Y含义一致,Cb,Cr 同样都指色彩,只是在表示方法上不同而已。在YUV 家族中,YCbCr 是在计算机系统中应用最多的成员,其应用领域很广泛,JPEGMPEG均采用此格式。一般人们所讲的YUV大多是指YCbCr。YCbCr 有许多取样格式,如4∶4∶4,4∶2∶2,4∶1∶1 和4∶2∶0。
      YCbCr其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。人的肉眼对视频的Y分量更敏感,因此在通过对色度分量进行子采样来减少色度分量后,肉眼将察觉不到的图像质量的变化。主要的子采样格式有 YCbCr 4:2:0、YCbCr 4:2:2 和 YCbCr 4:4:4。
      YCbCr 4:4:4 即 YUV三个信道的抽样率相同,因此在生成的图像里,每个象素的三个分量信息完整(每个分量通常8比特),经过8比特量化之后,未经压缩的每个像素占用3个字节。“

    ——百度百科《YCbCr》

      RGB888 转 YCbCr 的公式如下所示:

     

     

    二、MATLAB实现

      首先还是在 MATLAB 中实现,由于 MATLAB 中本来就是 RGB888 的格式,因此不需要 RGB565 转 RGB888 的操作。MATLAB代码如下所示:

     1 %--------------------------------------------------------------------------
     2 %                       RGB转YCbCr取Y值转灰度图
     3 %--------------------------------------------------------------------------
     4 clc;
     5 clear all;
     6 RGB = imread('flower.bmp'); %读取图像
     7 
     8 R = RGB(:,:,1);             %R分量
     9 G = RGB(:,:,2);             %G分量
    10 B = RGB(:,:,3);             %B分量
    11 
    12 [ROW,COL,N] = size(RGB);    %获得图像尺寸[高度,长度,维度]
    13 for r = 1:ROW 
    14     for c = 1:COL
    15         Y(r,c)  =  0.299*R(r,c) + 0.587*G(r,c) + 0.114*B(r,c);
    16         Cb(r,c) = -0.172*R(r,c) - 0.339*G(r,c) + 0.511*B(r,c) + 128;
    17         Cr(r,c) =  0.511*R(r,c) - 0.428*G(r,c) - 0.083*B(r,c) + 128;
    18     end
    19 end 
    20 
    21 subplot(2,2,1);imshow(R);title('R分量灰度图');
    22 subplot(2,2,2);imshow(G);title('G分量灰度图');
    23 subplot(2,2,3);imshow(B);title('B分量灰度图');
    24 subplot(2,2,4);imshow(Y);title('Y分量灰度图');

      点击运行,得到如下效果:

      由结果可以看到,相比 RGB 分量转灰度图来说,YCbCr 取 Y 分量的灰度图更具有层次感,和原图片更为接近。

    三、FPGA实现

    1、RGB565 转 RGB888

      本次实验的输入像素是 RGB565 的,因此需要先转换为 RGB888。前面的博客介绍过 RGB332 转 RGB565,原理是一样的,即低位补 0 或继续补充原通道的低位。代码如下所示:

    //RGB565 转 RGB888
    assign R0 = {RGB_data[15:11],RGB_data[13:11]}; //R8
    assign G0 = {RGB_data[10: 5],RGB_data[ 6: 5]}; //G8
    assign B0 = {RGB_data[ 4: 0],RGB_data[ 2: 0]}; //B8

    2、公式变形

      RGB888 转 YCbCr 的原公式如下所示:

      如果直接对着这个公式进行 Verilog 代码编写是不行的,因为 FPGA 无法进行浮点数的运算,先将公式变一下形,变形过程如下所示:

      第一次变形:由于 FPGA 无法进行浮点运算,因此将包含乘法的部分扩大256倍,然后再右移 8 位,右移8位即在二进制中即除以256的意思。

      第二次变形:将 128 也扩大 256 倍后移到括号里,最后一起右移 8 位。

    3、流水线设计

      所谓流水线设计,即数据流由原先的一条线运算转变为多条线同时运算,最终再汇合在一起。这样能充分利用 FPGA 并行的特点,扩大了面积但是提高了速度。

      (1)计算乘法,第一个时钟先将所有的乘法运算集中到一个 always 块中计算。

    //clk 1
    //---------------------------------------------------
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            {R1,G1,B1} <= {16'd0, 16'd0, 16'd0};
            {R2,G2,B2} <= {16'd0, 16'd0, 16'd0};
            {R3,G3,B3} <= {16'd0, 16'd0, 16'd0};
        end
        else begin
            {R1,G1,B1} <= { {R0 * 16'd77},  {G0 * 16'd150}, {B0 * 16'd29 } };
            {R2,G2,B2} <= { {R0 * 16'd43},  {G0 * 16'd85},  {B0 * 16'd128} };
            {R3,G3,B3} <= { {R0 * 16'd128}, {G0 * 16'd107}, {B0 * 16'd21 } };
        end
    end

      (2)计算加减法,第二个时钟将所有的加减法运算集中到一个 always 块中计算。

    //clk 2
    //---------------------------------------------------
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            Y1  <= 16'd0;
            Cb1 <= 16'd0;
            Cr1 <= 16'd0;
        end
        else begin
            Y1  <= R1 + G1 + B1;
            Cb1 <= B2 - R2 - G2 + 16'd32768; //128扩大256倍
            Cr1 <= R3 - G3 - B3 + 16'd32768; //128扩大256倍
        end
    end

      (3)右移8位,第三个时钟将所有的移位运行集中到一个 always 块中计算,这样便得到了 YCbCr 的不同分量值。

    //clk 3,除以256即右移8位,即取高8位
    //---------------------------------------------------
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            Y2  <= 8'd0;
            Cb2 <= 8'd0;
            Cr2 <= 8'd0;
        end
        else begin
            Y2  <= Y1[15:8];  
            Cb2 <= Cb1[15:8];
            Cr2 <= Cr1[15:8];
        end
    end

    4、Y分量赋值

      得到 YCbCr 的三个分量后,取 Y 分量赋值给我们的 RGB565 通道即可。

    assign gray_data = {Y2[7:3],Y2[7:2],Y2[7:3]}; //只取Y分量给RGB565格式

    5、打拍计算

      在图像处理时,我们是有数据的同步信号的,有的是数据使能信号,有的还有行同步信号和帧同步信号。经过图像处理后的数据延迟了拍数,这些同步信号也要相应的打拍,否则最终的图像显示会出问题。

      本次设计我们共耗费了 3 拍,因此同步信号也要相应的延迟 3 拍。

    //==========================================================================
    //==    信号同步
    //==========================================================================
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            RGB_de_r    <= 3'b0;
            RGB_hsync_r <= 3'b0;
            RGB_vsync_r <= 3'b0;
        end
        else begin  
            RGB_de_r    <= {RGB_de_r[1:0],    RGB_de};
            RGB_hsync_r <= {RGB_hsync_r[1:0], RGB_hsync};
            RGB_vsync_r <= {RGB_vsync_r[1:0], RGB_vsync};
        end
    end
    
    assign gray_de    = RGB_de_r[2];
    assign gray_hsync = RGB_hsync_r[2];
    assign gray_vsync = RGB_vsync_r[2];

    四、上板验证

      最终效果如下所示:

      和上面 MATLAB 的情况一样,YCbCr取Y分量的灰度图更有层次感。

      实验视频如下所示,本次设计和上一篇博客一样,利用了 key_select 按键选择模块,使用按键对图像进行效果切换。共5种显示效果,分别为原图、R分量灰度图、G分量灰度图、B分量灰度图、YCbCr的Y分量灰度图。

    五、后记

      很多图像算法都是基于 YCbCr 的 Y 分量来进行的,因此后面就用这个版本的工程做蓝本了。

    参考资料:

        [1]CrazyBingo 图像处理教程

        [2]NingHechuan 图像处理教程

        [3]小梅哥FPGA教程

        [4]OpenS Lee:FPGA开源工作室(公众号)

  • 相关阅读:
    scala之伴生对象的继承
    scala之伴生对象说明
    “Failed to install the following Android SDK packages as some licences have not been accepted” 错误
    PATH 环境变量重复问题解决
    Ubuntu 18.04 配置java环境
    JDBC的基本使用2
    DCL的基本语法(授权)
    ZJNU 1374
    ZJNU 2184
    ZJNU 1334
  • 原文地址:https://www.cnblogs.com/xianyufpga/p/12408988.html
Copyright © 2011-2022 走看看