• 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开源工作室(公众号)

  • 相关阅读:
    Python与数据库
    初识matplotlib
    Jquery--实现轮播图
    Juery入门2
    CSS布局方式
    Jquery入门一
    html-DOM了解
    jquery --入门
    JS练习
    kettle 报错汇总
  • 原文地址:https://www.cnblogs.com/xianyufpga/p/12408988.html
Copyright © 2020-2023  润新知