请选择 进入手机版 | 继续访问电脑版
[X]关闭

[米联客-XILINX-H3_CZ08_7100] FPGA_图像入门连载-3FPGA 实现色彩空间转换 RGB—YCbCr

文档创建者:FPGA课程
浏览次数:137
最后更新:2024-10-16
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-FPGA部分 » 2_FPGA实验篇(仅旗舰) » 8-FPGA图像入门
本帖最后由 FPGA课程 于 2024-10-16 18:55 编辑

​ 软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!




1 色彩空间转换原理简介
RGB 、YUV 和 YCbCr 都是人为规定的色彩空间。其用途是在某些标准下以通用化的方式对彩色进行描述。本质上,彩色模型是坐标系统和子空间的描述。
RGB 是依据人眼识别的颜色定义出的空间,可表示大部分颜色。但在科学研究一般不采用RGB 颜色空间,因 为它的细节难以进行数字化的调整。它将色调,亮度,饱和度三个量放在一起表示,很难分开。它是最通用的面向 硬件的彩色模型。该模型用于彩色监视器和一些彩色视频摄像。
在 YUV 色彩空间中,每一个颜色有一个亮度信号 Y,和两个色度信号 U 和 V。亮度信号是强度的感觉,它和 色度信号断开,这样的话强度就可以在不影响颜色的情况下改变。YUV,分为三个分量,“Y”表示明亮度(Luminance  或 Luma),也就是灰度值;而“U”和“V”  表示的则是色度(Chrominance 或 Chroma),作用是描述影像色彩及饱 和度,用于指定像素的颜色。如果没有 uv 信息就会显示黑白。人眼的视觉特点是对亮度更铭感,对位置、色彩相 对来说不铭感。在视频编码系统中为了降低带宽,可以保存更多的亮度信息(luma),保存较少的色差信息(chroma)。 通常对 yuv444 ,yuv422,yuv420  的解释是后面三个数字分别对应前面三个字母。拿 yuv422  来说,y  对应 4,表 示四个图形像素中,每个都有亮度值;u  对应 2 ,表示四个图形像素中,Cb  只占用两个像素;v  对应 2 , 表示四 个图形像素中, Cr  占用两个像素。对于 yuv422  模式,这样解释是没有问题。但是对于 yuv420  解释就不对了, 不能说四个图形像素中,Cr  占用 0  个像素吧?
表示,  是 J:a:b  模式,实心黑色圆圈表示包含色度像素(Cb+Cr),空心圆圈表示不包含色度像素。对于 J:a:b 模式,主要是围绕参考块的概念定义的,这个参考块是一个 J x 2  的矩形,J  通常是 4。这样,此参考块就是宽度 有 4  个像素、高度有 2  个像素的矩形。a  表示参考块的第一行包含的色度像素样本数,b  表示在参考块的第二行 包含的色度像素样本数。
YUV 使用 RGB 的信息,但它从全彩色图像中产生一个黑白图像(Y 信号),然后提取出三个主要的颜色变成 两个额外的信号来描述颜色。把这三个信号组合回来就可以产生一个全彩色图像。
Y  通道描述明亮度信号,值的范围介于亮和暗之间。明亮度是黑白电视可以看到的信号。U (Cb)  和 V (Cr)通 道从红 (U)  和蓝 (V)  中提取亮度值来减少颜色信息量。这些值可以从新组合来决定红,绿和蓝的混合信号。

1.1YUV 与 RGB 的转换
Y = 0.299 R + 0.587 G + 0.114 BU = -0.1687 R - 0.3313 G + 0.5 B + 128 V = 0.5 R - 0.4187 G - 0.0813 B + 128R = Y + 1.402 (V-128)G = Y - 0.34414 (U-128) - 0.71414 (V-128) B = Y + 1.772 (U-128)
1.2YCbCr 与 RGB 的转换
YCbCr  是在世界数字组织视频标准研制过程中作为 ITU - R BT1601  建议的一部分,是 YUV 经过缩放和偏移 的翻版。其中 Y 与 YUV  中的 Y 含义一致,  Cb  ,  Cr   同样都指色彩,  只是在表示方法上不同而已。在 YUV 家族中, YCbCr  是在计算机系统中应用最多的成员,其应用领域很广泛,JPEG、MPEG 均采用此格式。一般人们所讲的 YUV 大多是指 YCbCr。
YCbCr 与 RGB 的相互转换:
Y   = 0.2568*R + 0.5041*G + 0.0979*B + 16;  Cb = -0.1482*R - 0.2910*G + 0.4392*B + 128; Cr = 0.4392*R - 0.3678*G - 0.0714*B + 128;    R = 1.1644*(Y- 16) + 1.5960*(Cr - 128);G = 1.1644*(Y - 16) - 0.3918*(Cb- 128) -0.8130*(Cr- 128); B = 1.1644*(Y - 16) + 2.0172*(Cb- 128);

2 框图原理图
23f919a188a54ec09920dc3ff390d999.jpg
上面框图内由摄像头采集图像送回 fpga 后经过存储发送给 HDMI。

3 代码分析
3.1matlab 代码分析
  1. clear;clear all;clc;

  2. image_in = imread('lena_ 1280x720.jpg');    %获取图像

  3. %图像三元分类
  4. image_in_r = image_in(:,:,1);  image_in_g = image_in(:,:,2); image_in_b = image_in(:,:,3);

  5. [row,col,n] = size(image_in);

  6. image1_in_y    = uint8(zeros(row,col));        %图像数据类型,即创建一个数组,数据类型为 uint8
  7. image1_in_cb = uint8(zeros(row,col)); image1_in_cr = uint8(zeros(row,col));

  8. image2_in_y    = uint8(zeros(row,col)); image2_in_cb = uint8(zeros(row,col));  image2_in_cr = uint8(zeros(row,col));


  9. image1_out_rgb_r = uint8(zeros(row,col));  image1_out_rgb_g = uint8(zeros(row,col)); image1_out_rgb_b = uint8(zeros(row,col));

  10. image2_out_rgb_r = uint8(zeros(row,col));  image2_out_rgb_g = uint8(zeros(row,col)); image2_out_rgb_b = uint8(zeros(row,col));

  11. %================================================================================= %rgb2ycbcr 0
  12. %================================================================================= % ycbcr0 = zeros(size(image_in), 'like', image_in);
  13. % ycbcr0(:,:,1)    =    0.2568*image_in_r + 0.5041*image_in_g + 0.0979*image_in_b + 16; % ycbcr0(:,:,2)    = -0.1482*image_in_r - 0.2910*image_in_g + 0.4392*image_in_b + 128;  % ycbcr0(:,:,3)    =    0.4392*image_in_r - 0.3678*image_in_g - 0.0714*image_in_b + 128; % image0_in_y        = ycbcr0(:,:,1);
  14. % image0_in_cb      = ycbcr0(:,:,2);
  15. % image0_in_cr      = ycbcr0(:,:,3);
  16. %=================================================================================


  17. %================================================================================= %rgb2ycbcr 1
  18. %=================================================================================
  19. T = [ ...
  20. 0.2568 0.5041    0.0979;... -0.1482 -0.2910 0.4392;...
  21. 0.4392 -0.3678 -0.0714];%系数数组 Offset = [16; 128; 128];%转换系数

  22. ycbcr1 = zeros(size(image_in), 'like', image_in);%把 ycbcr1 定义为 image 类型

  23. for p = 1:3
  24. ycbcr1(:,:,p) = imlincomb( T(p,1),image_in_r,...
  25. T(p,2),image_in_g,... T(p,3),image_in_b,...
  26. Offset(p));      %进行函数运算
  27. end
  28. image1_in_y    = ycbcr1(:,:,1); image1_in_cb = ycbcr1(:,:,2);  image1_in_cr = ycbcr1(:,:,3);
  29. %=================================================================================




  30. %================================================================================= %rgb2ycbcr 2
  31. %=================================================================================
  32. ycbcr2 = rgb2ycbcr(image_in);

  33. image2_in_y    = ycbcr2(:,:,1); image2_in_cb = ycbcr2(:,:,2);  image2_in_cr = ycbcr2(:,:,3);
  34. %=================================================================================

  35. %================================================================================= %ycbcr2rgb 0
  36. %================================================================================= % image0_out_rgb_r = 1.1644*(image0_in_y - 16) + 1.5960*(image0_in_cr - 128);
  37. % image0_out_rgb_g = 1.1644*(image0_in_y - 16) - 0.3918*(image0_in_cb - 128) -0.8130*(image0_in_cr - 128); % image0_out_rgb_b = 1.1644*(image0_in_y - 16) + 2.0172*(image0_in_cb - 128);

  38. %=================================================================================
  39. %================================================================================= %ycbcr2rgb 1
  40. %=================================================================================
  41. T = [65.481 128.553 24.966;... -37.797 -74.203 112; ...
  42. 112 -93.786 -18.214];
  43. %1.1644 0      1.5960
  44. %1.1644 -0.3918 -0.8130 %1.1644 2.0172    0
  45. % We can rewrite the equation in terms of ycbcr which is
  46. % T ^-1 * (ycbcr - offset) = rgb.    This is equation 9.7 in the book.

  47. Tinv = T^-1;%转置
  48. % Tinv = [0.00456621    0.                    0.00625893;...
  49. %                    0.00456621 -0.00153632 -0.00318811;...
  50. %                    0.00456621    0.00791071    0.]
  51. offset = [16;128;128];

  52. T = 255 * Tinv;
  53. offset = 255 * Tinv * offset;

  54. % Initialize the output
  55. rgb1 = zeros(size(ycbcr1), 'like', ycbcr1);

  56. for p = 1:3
  57. rgb1(:,:,p) = imlincomb(T(p,1),ycbcr1(:,:,1),...
  58. T(p,2),ycbcr1(:,:,2),... T(p,3),ycbcr1(:,:,3),... -offset(p));
  59. end

  60. image1_out_rgb_r = rgb1(:,:,1);  image1_out_rgb_g = rgb1(:,:,2); image1_out_rgb_b = rgb1(:,:,3);
  61. %=================================================================================




  62. %================================================================================= %ycbcr2rgb 2
  63. %=================================================================================
  64. rgb2 = zeros(size(ycbcr2), 'like', ycbcr2); rgb2 = ycbcr2rgb(ycbcr2);
  65. image2_out_rgb_r = rgb2(:,:,1);  image2_out_rgb_g = rgb2(:,:,2);
  66. image2_out_rgb_b = rgb2(:,:,3);
  67. %================================================================================= % image0_out_rgb = cat(3,image0_out_rgb_r,image0_out_rgb_g,image0_out_rgb_b);
  68. image1_out_rgb = cat(3,image1_out_rgb_r,image1_out_rgb_g,image1_out_rgb_b);
  69. image2_out_rgb = cat(3,image2_out_rgb_r,image2_out_rgb_g,image2_out_rgb_b);%构造三维矩阵




  70. %================================================================================= %display
  71. %=================================================================================
  72. subplot(251);
  73. imshow(image_in), title('The original rgb image'); subplot(252);
  74. imshow(image1_in_y),title('The grey y image'); subplot(253);
  75. imshow(image1_in_cb),title('The grey cb image'); subplot(254);
  76. imshow(image1_in_cr),title('The grey cr image'); subplot(255);
  77. imshow(image1_out_rgb);title('image1 out rgb');
  78. %
  79. subplot(256);
  80. imshow(image_in), title('The original rgb image'); subplot(257);
  81. imshow(image2_in_y),title('The grey y image'); subplot(258);
  82. imshow(image2_in_cb),title('The grey cb image'); subplot(259);
  83. imshow(image2_in_cr),title('The grey cr image'); subplot(2,5,10);
  84. imshow(image2_out_rgb);title('image2 out rgb');图像显示
  85. %
复制代码

3.2Verilog 代码分析
3.2.1RGB 转 YCbCr
  1. //按照 1.2 小节中的公式中进行公式变换:
  2. // ycbcr0(:,:,1)    =    0.2568*image_in_r + 0.5041*image_in_g + 0.0979*image_in_b + 16; // ycbcr0(:,:,2)    = -0.1482*image_in_r - 0.2910*image_in_g + 0.4392*image_in_b + 128;  // ycbcr0(:,:,3)    =    0.4392*image_in_r - 0.3678*image_in_g - 0.0714*image_in_b + 128; //先乘以256 然后右移 8 位。
  3. // ycbcr0(:,:,1)    = 256*( 0.2568*image_in_r + 0.5041*image_in_g + 0.0979*image_in_b + 16 )>>8;// ycbcr0(:,:,2)    = 256*(-0.1482*image_in_r - 0.2910*image_in_g + 0.4392*image_in_b + 128)>>8; // ycbcr0(:,:,3)    = 256*( 0.4392*image_in_r - 0.3678*image_in_g - 0.0714*image_in_b + 128)>>8;  //最终结果如下:
  4. // ycbcr0(:,:,1)    = (66*image_in_r + 129*image_in_g + 25*image_in_b + 4096    )>>8; // ycbcr0(:,:,2)    = (-38*image_in_r - 74*image_in_g + 112*image_in_b + 32768)>>8;   // ycbcr0(:,:,3)    = (112*image_in_r - 94*image_in_g - 18*image_in_b + 32768 )>>8;    //我们将乘法运算单独在一个时钟周期中完成,代码如下:
  5. always@(posedge i_clk ornegedge i_rst_n) begin
  6. if(!i_rst_n) begin
  7. r_d0 <= 16'd0;  g_d0 <= 16'd0; b_d0 <= 16'd0; r_d1 <= 16'd0;  g_d1 <= 16'd0; b_d1 <= 16'd0; r_d2 <= 16'd0;  g_d2 <= 16'd0; b_d2 <= 16'd0;
  8. end    else    begin
  9. r_d0 <= 66    * i_r;
  10. g_d0 <= 129 * i_g;  b_d0 <= 25    * i_b; r_d1 <= 38    * i_r;  g_d1 <= 74    * i_g; b_d1 <= 112 * i_b;  r_d2 <= 112 * i_r;   g_d2 <= 94    * i_g; b_d2 <= 18    * i_b;
  11. end end
  12. //完成乘法后进行加减法运算:
  13. always@(posedge i_clk ornegedge i_rst_n) begin
  14. if(!i_rst_n) begin
  15. y_d0    <= 16'd0; cb_d0 <= 16'd0;  cr_d0 <= 16'd0;
  16. end    else    begin
  17. y_d0    <= r_d0 + g_d0 + b_d0 + 4096 ;cb_d0 <= b_d1 - r_d1 - g_d1 + 32768; cr_d0 <= r_d2 - g_d2 - b_d2 + 32768;
  18. end end
  19. //最后进行信号的同步: always@(posedge i_clk )  begin
  20. hsyn <= {hsyn[0],i_hsyn}; vsyn <= {vsyn[0],i_vsyn}; de            <= {de[0],i_de};
  21. end

  22. assign      o_hsyn    = hsyn[1];
  23. assign      o_vsyn    = vsyn[1];
  24. assign      o_y          = y_d0 [15:8];
  25. assign      o_cb= cb_d0[15:8];
  26. assign      o_cr = cr_d0[15:8];
  27. assign      o_de= de[1];
复制代码

3.2.2YCbCr 转 RGB
  1. //按照 1.2 小节中的公式中进行公式变换:
  2. // image0_out_rgb_r = 1.1644*(ycbcr0(:,:,1) - 16) + 1.5960*(ycbcr0(:,:,3) - 128);
  3. // image0_out_rgb_g = 1.1644*(ycbcr0(:,:,1) - 16) - 0.3918*(ycbcr0(:,:,2) - 128) -0.8130*(ycbcr0(:,:,3) - 128); // image0_out_rgb_b = 1.1644*(ycbcr0(:,:,1) - 16) + 2.0172*(ycbcr0(:,:,2) - 128);
  4. //展开系数部分:
  5. // image0_out_rgb_r = 1.1644*ycbcr0(:,:,1) - 18.6304 + 1.5960*ycbcr0(:,:,3) - 204.288;
  6. // image0_out_rgb_g =  1.1644*ycbcr0(:,:,1)  -  18.6304  -  0.3918*ycbcr0(:,:,2)  +  50.1504  +  -0.8130*ycbcr0(:,:,3)  + 104.063;
  7. // image0_out_rgb_b = 1.1644*ycbcr0(:,:,1) - 18.6304 + 2.0172*ycbcr0(:,:,2) - 258.2016; //进行系数合并:
  8. // image0_out_rgb_r = 1.1644*ycbcr0(:,:,1) + 1.5960*ycbcr0(:,:,3) - 223;
  9. // image0_out_rgb_g = 1.1644*ycbcr0(:,:,1) - 0.3918*ycbcr0(:,:,2) - 0.8130*ycbcr0(:,:,3) + 136; // image0_out_rgb_b = 1.1644*ycbcr0(:,:,1) + 2.0172*ycbcr0(:,:,2) - 277;
  10. //先乘以256 然后右移 8 位。
  11. // image0_out_rgb_r = 256*(1.1644*ycbcr0(:,:,1) + 1.5960*ycbcr0(:,:,3) - 223)>>8;
  12. // image0_out_rgb_g = 256*(1.1644*ycbcr0(:,:,1) - 0.3918*ycbcr0(:,:,2) - 0.8130*ycbcr0(:,:,3) + 136)>>8;
  13. // image0_out_rgb_b = 256*(1.1644*ycbcr0(:,:,1) + 2.0172*ycbcr0(:,:,2) - 277)>>8; //最终结果如下:
  14. // image0_out_rgb_r = (298*ycbcr0(:,:,1) + 408*ycbcr0(:,:,3) - 57088)>>8;
  15. // image0_out_rgb_g = (298*ycbcr0(:,:,1) - 100*ycbcr0(:,:,2) - 208*ycbcr0(:,:,3) + 34816)>>8; // image0_out_rgb_b = (298*ycbcr0(:,:,1) + 516*ycbcr0(:,:,2) - 70912)>>8;
  16. //我们将乘法运算单独在一个时钟周期中完成,代码如下: always@(posedge i_clk ornegedge i_rst_n)
  17. begin
  18. if(!i_rst_n) begin
  19. y_d0    <= 16'd0;   // cb_d0 <= 16'd0; cr_d0 <= 16'd0;
  20. y_d1    <= 16'd0;  cb_d1 <= 16'd0;   cr_d1 <= 16'd0;    y_d2    <= 16'd0;  cb_d2 <= 16'd0;   // cr_d2 <= 16'd0;
  21. end    else    begin
  22. y_d0      <= 298 * i_y;
  23. // cb_d0    <= 0      * i_cb; cr_d0    <= 408 * i_cr;
  24. y_d1      <= 298 * i_y;
  25. cb_d1    <= 100 * i_cb; cr_d1    <= 208 * i_cr;
  26. y_d2      <= 298 * i_y;
  27. cb_d2    <= 516 * i_cb;    // cr_d2    <= 0      * i_cr;
  28. end end
  29. //完成乘法后进行加减法运算:
  30. always@(posedge i_clk ornegedge i_rst_n) begin
  31. if(!i_rst_n) begin
  32. r_d0    <= 16'd0;  g_d0    <= 16'd0; b_d0    <= 16'd0;
  33. end    else    begin
  34. r_d0    <= y_d0 + cr_d0 - 57088;
  35. g_d0    <= y_d1 - cb_d1 - cr_d1 + 34816;
  36. b_d0    <= y_d2 + cb_d2 - 70912;
  37. end end
  38. //最后进行信号的同步: always@(posedge i_clk )  begin
  39. hsyn <= {hsyn[0],i_hsyn}; vsyn <= {vsyn[0],i_vsyn};
  40. de            <= {de[0],i_de};
  41. end

  42. assign      o_hsyn    = hsyn[1];
  43. assign      o_vsyn    = vsyn[1];
  44. assign      o_r          = r_d0[15:8];
  45. assign      o_g          = g_d0[15:8];
  46. assign      o_b          = b_d0[15:8];
  47. assign      o_de= de[1];
复制代码

4 工程结构分析
ov5640 摄像头采集过来是数据经 DDR3 缓存后,通过 FDMA 读出后送入了rgb2ycbcr 模块,rgb2ycbcr 输出的 数据直接送到 HDMI 模块进行驱动显示。
cf3904d4805147a1996cf824850554e6.jpg
ov5640 摄像头采集过来是数据经 DDR3 缓存后,通过 FDMA 读出后送入了rgb2ycbcr 模块,rgb2ycbcr 输出的 数据直接送到 ycbcr2rgb 模块,最后数据送进 HDMI 模块进行驱动显示。
2c52c5bfbcb6477ea938660b74241466.jpg
5 仿真及结果
5.1Matlab 实验结果
第一行为 RGB 转 YCbCr ,从左至右分别是原图、Y 图、Cb 图、Cr 图、YCbCr 转 RGB 图。

387dfce719304fb6bd43c2ca1365351c.jpg
5.2Modelsim 实验结果
b597f94e55b14f5b95c0fc81962ba7a2.jpg
由波形分析可得,o_y,o_cb,o_cr 有输出时,data 有数据输出。
6 搭建 Vitis-sdk 工程
创建 soc_base  sdk  platform  和 APP  工程的过程不再重复,可以阅读 3-3-01_sdk_base_app。以下给出创建好 soc_base sdk platform 的截图和对应工程 APP 的截图。
6.1 创建 SDK Platform 工程
2f86a31a16a046bfad9e61f1cbe42b08.jpg
6.2SDK APP 工程
ffa671d8793c4511892b38353a146666.jpg
7 硬件连接
硬件连接如图所示:
1538f8b6be0b4636a760d434dad3d199.jpg
8 上板实验结果
RGB 转 YCbCr:
a14418d3be394672b89ad890b5cf9857.jpg

RGB 转 YCbCr 后转 RGB:
81a7d5d5ec0a4b138aebf3ecbf3b5844.jpg








您需要登录后才可以回帖 登录 | 立即注册

本版积分规则