搜索
bottom↓
回复: 1

【正点原子FPGA连载】第二十五章OV5640摄像头灰度图显示实验--摘自【正点原子】领航者 ZYNQ 之嵌入式开发指南

[复制链接]

出0入234汤圆

发表于 2020-8-13 10:58:53 | 显示全部楼层 |阅读模式
本帖最后由 正点原子 于 2020-10-24 10:48 编辑

1)实验平台:正点原子领航者ZYNQ开发板
2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz_linhanz.html
4)对正点原子FPGA感兴趣的同学可以加群讨论:876744900
QQ群头像.png
5)关注正点原子公众号,获取最新资料


100846rel79a9p4uelap24.jpg

100846f1ce1fg14zbg0va4.png

第二十五章OV5640摄像头灰度图显示实验





前面的实验我们介绍了OV5640摄像头LCD显示实验,在该实验中摄像头输出的是RGB格式的图像数据。而在数字图像处理领域中YUV是一种更常用的图像格式,其特点是将亮度和色度进行分离,更适合运用于图像处理领域。在本章实验中,我们将进行RGB到YUV的颜色空间转换,并通过LCD显示灰度图的实验。
本章包括以下几个部分:
12525.1OV5640简介
25.2实验任务
25.3软件设计
25.4程序设计
25.5下载验证



25.1简介
人眼中的锥状细胞是负责彩色视觉的传感器,可分为三个主要的感知类别,分别对应红色、绿色、蓝色,我们人眼看到的彩色实际上是红、绿、蓝三原色的各种组合。前面我们用到的RGB就是以红、绿、蓝为三原色的颜色空间模型,通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。
YUV(YCbCr)是欧洲电视系统所采用的一种颜色编码方法。“Y”表示明亮度(Luminance或Luma),也就是灰阶值,“U”和“V”表示色度,用于描述影像的饱和度和色调。RGB与YUV的转换实际上是色彩空间的转换,即将RGB的三原色色彩空间转换为YUV所表示的亮度与色度的色彩空间模型。YUV 主要应用在模拟系统中,而 YCbCr 是通过 YUV 信号的发展,并通过校正的主要应用在数字视频中的一种编码方法。YUV适用于PAL和SECAM彩色电视制式,而YCrCb适用于计算机用的显示器。
RGB着重于人眼对色彩的感应,YUV则着重于视觉对于亮度的敏感程度。使用YUV描述图像的好处在于,(1)亮度(Y)与色度(U、V)是独立的;(2)人眼能够识别数千种不同的色彩,但只能识别20多种灰阶值,采用YUV标准可以降低数字彩色图像所需的储存容量。因而YUV在数字图像处理中是一种很常用的颜色标准。
YUV 信号的提出,是因为国际上出现彩色电视,为了兼容黑白电视的信号而设计的,在视频码率,压缩,兼容性等方面有很大优势,我们最常用的主要是YUV4:4:4和V4:2:2两中采样格式的YUV信号。下面我们将介绍这两种格式的信号。
(1)YUV4:4:4
在YUV4:4:4格式中,YUV三个信道的采样率相同。因此在生成的图像里,每个像素都有各自独立的三个分量,每个分量通常为8bit,故每个像素占用3个字节。下图为YUV444单个像素的模型图,可以看出,每个Y都对应一组U、V数据,共同组成一个像素。
阿莫论坛发帖领航者专用11066.png

图 25.1.1 单个V444的素

(2)YUV4:2:2
在YUV4:2:2格式中,U和V的采样率是Y的一半(两个相邻的像素共用一对U、V数据)。如下图所示,图中包含两个相邻的像素。第一个像素的三个YUV分量分别是Y1、U1、V1,第二个像素的三个YUV分量分别是Y2、U1、V1,两个像素共用一组U1、V1。
阿莫论坛发帖领航者专用11268.png

图 25.1.2 两个相邻的YUV422像素

YUV4:4:4格式和YUV4:2:2格式的数据流也是不同的。如一组连续的四个像素P1、P2、P3、P4,采用YUV444的采样格式时,数据流为Y0 U0 V0、Y1 U1 V1、Y2 U2 V2、Y3 U3 V3,每组数据代表一个像素点。而用YUV422的采样格式时,数据流为Y0 U0 Y1 V1、Y2 U2 Y3 V3。其中,Y0 U0 Y1 V1表示P1、P2两个像素,Y2 U2 Y3 V3表示P3、P4两个像素。
一般意义上 YCbCr 即为 YUV 信号,没有严格的划分。我们通常说的YUV就是指YCbCr。 CbCr 分别为蓝色色度分量、红色色度分量。下面为 RGB 与 YCbCr 色彩空间转换的算法公式, RGB 转 YCbCr 的公式如下所示:
阿莫论坛发帖领航者专用11670.png

图 25.1.3 RGB 转 YcbCr算法

由于 Verilog HDL 无法进行浮点运算,因此使用扩大 256 倍,再向右移 8Bit的方式,来转换公式,(0.083=00010101) 如下所示:
阿莫论坛发帖领航者专用11817.png

图 25.1.4 RGB 转 YcbCr算法


为了防止运算过程中出现负数,我们对上述公式进行进一步变换,得到如下公式:
阿莫论坛发帖领航者专用11923.png

图 25.1.5 RGB 转 YcbCr算法

实际上OV5640本身支持输出RGB、YUV格式的数据,本章节实验是着重于实RGB转YUV的HDL算法实现,因此我们把摄像头设置为RGB565格式。当我们需要显示器显示灰度图时,我们只需要将转换后的Y值作为R、G、B三原色通道的输入就可以实现了。
25.2实验任务
本节实验任务是使用启明星开发板及OV5640摄像头采集RGB565格式的数据,并通过算法转换,将RGB格式的图像数据转换为YCbCr格式,然后通过LCD实时显示灰度图。
25.3硬件设计
图 25.3.1是根据本章实验任务画出的系统框图。对比OV5640摄像头LCD显示实验,本实验中仅添加了RGB转Ycbcr模块,该模块用于将摄像头采集到的RGB数据转换成YCbCr格式数。
OV5640摄像头LCD显示灰度图系统框图如下图所示:
阿莫论坛发帖领航者专用12374.png

图 25.3.1 OV5640摄像头LCD显示灰度图系统框图

如下图 25.3.2我们给出了rgb2ycbcr的ip核以及其接口的连线图:
阿莫论坛发帖领航者专用12513.png

图 25.3.2 rgb2ycbcr模块连接图

有关其他各个模块的功能可以参考“OV5640摄像头LCD显示实验”的相关描述,在本实验中我们将对rgb2ycbcr模块的功能进行描述。摄像头采集模块输出24为RGB数据经“rgb2ycbcr”模块转换,输出24位的Ycbcr数据。
RGB转Ycbcr模块的代码如下:
  1. 1   module rgb2ycbcr
  2. 2   (
  3. 3       //module clock
  4. 4       input               clk          ,  // 模块驱动时钟
  5. 5       input               rst_n        ,  // 复位信号
  6. 6   
  7. 7       //图像处理前的数据接口
  8. 8       input               rgb_vsync    ,  // vsync信号
  9. 9       input               rgb_clken    ,  // 时钟使能信号
  10. 10      input               rgb_valid    ,  // 数据有效信号
  11. 11      input       [23:0]  rgb_data     ,  // 输入图像数据RGB
  12. 12     
  13. 13  
  14. 14      //图像处理后的数据接口
  15. 15      output              ycbcb_vsync  ,  // vsync信号
  16. 16      output              ycbcbr_clken ,  // 时钟使能信号
  17. 17      output              ycbcr_valid  ,  // 数据有效信号
  18. 18      output      [23:0]  gray_data       // 输出图像Y数据
  19. 19   
  20. 20  );
  21. 21  
  22. 22  //reg define
  23. 23  reg  [15:0]   rgb_r_m0, rgb_r_m1, rgb_r_m2;
  24. 24  reg  [15:0]   rgb_g_m0, rgb_g_m1, rgb_g_m2;
  25. 25  reg  [15:0]   rgb_b_m0, rgb_b_m1, rgb_b_m2;
  26. 26  reg  [15:0]   img_y0 ;
  27. 27  reg  [15:0]   img_cb0;
  28. 28  reg  [15:0]   img_cr0;
  29. 29  reg  [ 7:0]   img_y1 ;
  30. 30  reg  [ 7:0]   img_cb1;
  31. 31  reg  [ 7:0]   img_cr1;
  32. 32  reg  [ 2:0]   rgb_vsync_d;
  33. 33  reg  [ 2:0]   rgb_clken_d;
  34. 34  reg  [ 2:0]   rgb_valid_d   ;
  35. 35  
  36. 36  //wire define
  37. 37  wire [ 7:0]   rgb888_r;
  38. 38  wire [ 7:0]   rgb888_g;
  39. 39  wire [ 7:0]   rgb888_b;
  40. 40  wire [ 7:0]   img_y;
  41. 41  wire [ 7:0]   img_cb;
  42. 42  wire [ 7:0]   img_cr;
  43. 43  
  44. 44  //*****************************************************
  45. 45  //**                    main code
  46. 46  //*****************************************************
  47. 47  
  48. 48  //RGB565 to RGB 888
  49. 49  assign rgb888_r         = rgb_data[23:16];
  50. 50  assign rgb888_g     = rgb_data[15:8];
  51. 51  assign rgb888_b     = rgb_data[7:0] ;
  52. 52  //同步输出数据接口信号
  53. 53  assign ycbcb_vsync  = rgb_vsync_d[2] ;
  54. 54  assign ycbcbr_clken = rgb_clken_d[2] ;
  55. 55  assign ycbcr_valid  = rgb_valid_d[2] ;
  56. 56  assign img_y        = ycbcbr_clken ? img_y1 : 8'd0;
  57. 57  assign img_cb       = ycbcbr_clken ? img_cb1: 8'd0;
  58. 58  assign img_cr       = ycbcbr_clken ? img_cr1: 8'd0;
  59. 59  assign gray_data    = {img_y,img_y,img_y};
  60. 60  //--------------------------------------------
  61. 61  //RGB 888 to YCbCr
  62. 62  
  63. 63  /********************************************************
  64. 64              RGB888 to YCbCr
  65. 65   Y  = 0.299R +0.587G + 0.114B
  66. 66   Cb = 0.568(B-Y) + 128 = -0.172R-0.339G + 0.511B + 128
  67. 67   CR = 0.713(R-Y) + 128 = 0.511R-0.428G -0.083B + 128
  68. 68  
  69. 69   Y  = (77 *R    +    150*G    +    29 *B)>>8
  70. 70   Cb = (-43*R    -    85 *G    +    128*B)>>8 + 128
  71. 71   Cr = (128*R    -    107*G    -    21 *B)>>8 + 128
  72. 72  
  73. 73   Y  = (77 *R    +    150*G    +    29 *B        )>>8
  74. 74   Cb = (-43*R    -    85 *G    +    128*B + 32768)>>8
  75. 75   Cr = (128*R    -    107*G    -    21 *B + 32768)>>8
  76. 76  *********************************************************/
  77. 77  
  78. 78  //step1 计算括号内的各乘法项
  79. 79  always @(posedge clk or negedge rst_n) begin
  80. 80      if(!rst_n) begin
  81. 81          rgb_r_m0 <= 16'd0;
  82. 82          rgb_r_m1 <= 16'd0;
  83. 83          rgb_r_m2 <= 16'd0;
  84. 84          rgb_g_m0 <= 16'd0;
  85. 85          rgb_g_m1 <= 16'd0;
  86. 86          rgb_g_m2 <= 16'd0;
  87. 87          rgb_b_m0 <= 16'd0;
  88. 88          rgb_b_m1 <= 16'd0;
  89. 89          rgb_b_m2 <= 16'd0;
  90. 90      end
  91. 91      else begin
  92. 92          rgb_r_m0 <= rgb888_r * 8'd77 ;
  93. 93          rgb_r_m1 <= rgb888_r * 8'd43 ;
  94. 94          rgb_r_m2 <= rgb888_r * 8'd128;
  95. 95          rgb_g_m0 <= rgb888_g * 8'd150;
  96. 96          rgb_g_m1 <= rgb888_g * 8'd85 ;
  97. 97          rgb_g_m2 <= rgb888_g * 8'd107;
  98. 98          rgb_b_m0 <= rgb888_b * 8'd29 ;
  99. 99          rgb_b_m1 <= rgb888_b * 8'd128;
  100. 100         rgb_b_m2 <= rgb888_b * 8'd21 ;
  101. 101     end
  102. 102 end
  103. 103
  104. 104 //step2 括号内各项相加
  105. 105 always @(posedge clk or negedge rst_n) begin
  106. 106     if(!rst_n) begin
  107. 107         img_y0  <= 16'd0;
  108. 108         img_cb0 <= 16'd0;
  109. 109         img_cr0 <= 16'd0;
  110. 110     end
  111. 111     else begin
  112. 112         img_y0  <= rgb_r_m0 + rgb_g_m0 + rgb_b_m0;
  113. 113         img_cb0 <= rgb_b_m1 - rgb_r_m1 - rgb_g_m1 + 16'd32768;
  114. 114         img_cr0 <= rgb_r_m2 - rgb_g_m2 - rgb_b_m2 + 16'd32768;
  115. 115     end
  116. 116
  117. 117 end
  118. 118
  119. 119 //step3 括号内计算的数据右移8位
  120. 120 always @(posedge clk or negedge rst_n) begin
  121. 121     if(!rst_n) begin
  122. 122         img_y1  <= 8'd0;
  123. 123         img_cb1 <= 8'd0;
  124. 124         img_cr1 <= 8'd0;
  125. 125     end
  126. 126     else begin
  127. 127         img_y1  <= img_y0 [15:8];
  128. 128         img_cb1 <= img_cb0[15:8];
  129. 129         img_cr1 <= img_cr0[15:8];
  130. 130     end
  131. 131 end
  132. 132
  133. 133 //延时3拍以同步数据信号
  134. 134 always@(posedge clk or negedge rst_n) begin
  135. 135     if(!rst_n) begin
  136. 136         rgb_vsync_d <= 3'd0;
  137. 137         rgb_clken_d <= 3'd0;
  138. 138         rgb_valid_d <= 3'd0;
  139. 139     end
  140. 140     else begin
  141. 141         rgb_vsync_d <= {rgb_vsync_d[1:0], rgb_vsync};
  142. 142         rgb_clken_d <= {rgb_clken_d[1:0], rgb_clken};
  143. 143         rgb_valid_d <= {rgb_valid_d[1:0], rgb_valid};
  144. 144     end
  145. 145 end
  146. 146
  147. 147 endmodule
复制代码

在RGB转成Ycbcr格式的算法换算过程中,我们需要提取RGB信号的红绿蓝分量,我们只需取24位RGB数据的高8位、中8位和低8位我作为红绿蓝三原色分量就可以了,如代码第48之51行所示;下面就是进行RGB转YCbCr算法的HDL实现:第一步,先计算出算法公式中括号里每一个乘法的乘积,如代码第78至102行所示;第二步,计算出Y、Cb、Cr括号内的值,代码104至117行;第三步,右移 8Bit,由于 Step2 计算结果为 16Bit, 因此直接提取高8位 即可,代码如119至131行所示。下图为RGB转YUV的算法公式:
阿莫论坛发帖领航者专用17716.png

图 25.3.3 RGB转YUV算法公式

实际上从第一步到第三步的运算, 均直接通过寄存器描述,没有顾虑时序问题。但在实际电路中会有一个数据流上的先后顺序,这三步操作同时对连续数据进行处理,通过这种方式实现硬件加速的方法称为流水线设计。前面计算出 Y、cb、 cr 我们消耗了step1、step2、step3这三个时钟, 因此需要将输入的场信号、时钟使能信号和数据有效信号同步移动 3 个时钟,如代码第134值145行。
根据实验任务,我们需要输出的是灰度数据,因此我们需要用计算得到的灰度Y来作为图像cb、cr分量,如代码第59行所示:
59  assign gray_data     = {img_y,img_y,img_y};
我们在设计完代码后,需要将设计好的代码封装成IP核,以便于后续设计,有关IP核的封装请参考第十七章“IP核封装与接口定义”实验。
连线后的 Block Design 如下图所示:
阿莫论坛发帖领航者专用18170.png

图 25.3.4 Block Design整体示意图

接下来验证当前设计。验证完成后弹出对话框提示没有错误或者关键警告,点击“OK”。如果验证结果
报出错误或者警告,则需要重新检查设计。
为工程添加的约束文件与“OV5640 摄像头 LCD 显示”完全相同,有关这一部分内容请读者参考“OV5640 摄像头 LCD 显示”实验。
最后在左侧 Flow Navigator 导航栏中找到 PROGRAM AND DEBUG,点击该选项中的“ Generate
Bitstream”,对设计进行综合、实现、并生成 Bitstream 文件。在生成 Bitstream 之后,在菜单栏中选择 File > Export > Export hardware 导出硬件, 并在弹出的对话框中,勾选“Include bitstream”。然后在菜单栏选择 File > Launch SDK, 启动 SDK 软件。
25.4软件设计
本实验软件设计与OV5640摄像头LCD显示实验像是完全相同,在本章节就不再赘述,有需要的小伙伴可以参考OV5640摄像头LCD显示实验软件设计部分。
25.5下载验证
编译完工程之后我们就可以开始下载程序了。将 OV5640 摄像头模块插在启明星Zynq开发板的“OLED/CAMERA”插座上,并将 LCD 的排线接头插入开发板上的 LCD 接线座。将下载器一端连电脑,
另一端与开发板上的 JTAG 端口连接,连接电源线并打开电源开关。
在 SDK 软件下方的 SDK Terminal 窗口中点击右上角的加号设置并连接串口。然后下载本次实验硬件
设计过程中所生成的 BIT 文件,来对 PL 进行配置。最后下载软件程序,下载完成后, 在下方的 SDK Terminal中可以看到应用程序打印的信息,如下图所示:
阿莫论坛发帖领航者专用18979.png

图 25.5.1 串口打印信息窗口

同时, RGB LCD 液晶屏上显示出 OV5640 摄像头采集的图像的灰度图,说明本次 OV5640 摄像头 LCD 屏显示的实验在启明星 ZYQN 开发板上验证成功,如下图所示:
阿莫论坛发帖领航者专用19134.png

图 25.5.2 LCD屏显示结果

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出16170入6148汤圆

发表于 2020-8-23 12:13:14 来自手机 | 显示全部楼层
打赏!

庆祝论坛“打赏”功能实施, 现在开始发技术主题,可以获得打赏
https://www.amobbs.com/thread-5735948-1-1.html
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 22:18

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表