OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 11562|回复: 0
打印 上一主题 下一主题

[XILINX] 【正点原子FPGA连载】第五十三章基于OV5640的二值化实验--摘自【正点原子】超越者之FPGA开发指南

[复制链接]

1361

主题

1377

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
5813
金钱
5813
注册时间
2019-5-8
在线时间
1598 小时
跳转到指定楼层
楼主
发表于 2021-1-26 15:42:52 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
1)实验平台:正点原子超越者FPGA开发板
2)平台购买地址:https://item.taobao.com/item.htm?&id=631660290421
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz-chaoyuezhe.html
4)本章实例源码下载: 46_ov5640_hdmi_img_binarization.rar (8.86 MB, 下载次数: 27)


5)正点原子FPGA交流群:905624739点击加入:
6)关注正点原子公众号,获取最新资料更新



第五十三章基于OV5640的二值化实验



在数字图像处理中,二值图像占有非常重要的地位,图像的二值化使图像中数据量大为减少,还能凸显出目标的轮廓。图像二值化在计算机视觉、图像分割以及人工智能等方面有着广泛应用。在本章节将进行基于OV5640的二值化实验。
本章包括以下几个部分:
5353.1  简介
53.2  实验任务
53.3  硬件设计
53.4  程序设计
53.5  下载验证


53.1简介
图像二值化(Image Binarization)就是将图像上的像素点的灰度值设置为最大(白色)或最小(黑色),也就是将整个图像呈现出明显的黑白效果的过程。这里以8bit表示的灰度图像为例(灰度值的范围为0~255),二值化就是通过选取适当的阈值,与图像中的256个亮度等级进行比较。亮度高于阈值的像素点设置为白色(255),低于阈值的像素点设置为黑色(0),从而明显地反映出图像的整体和局部特征。
在数字图像处理中,二值图像占有非常重要的地位,特别是在实时的图像处理中,通过二值图像来构成的系统有很多。要进行二值图像的处理与分析,首先要把灰度图像二值化,得到二值化图像,这样有利于在对图像做进一步处理时,图像的集合性质只与像素值为0或255的点的位置有关,不再涉及像素的多级值,使处理变得简单。为了得到理想的二值图像,一般采用封闭、连通的边界定义不交叠的区域。所有灰度大于或等于阈值的像素被判定为属于特定物体,其灰度值用255表示,否则这些像素点被排除在物体区域以外,灰度值为0,表示背景或者例外的物体区域。
实现二值化有两种方法,一种是手动指定一个阈值,通过阈值来进行二值化处理;另一种是一个自适应阈值二值化方法(OTSU算法和Kittle算法等)。使用第一种方法计算量小速度快,但在处理不同图像时颜色分布差别很大;使用第二种方法适用性强,能直接观测出图像的轮廓,但计算相对更复杂。本章节实验将使用第一种方法来实现图像的二值化。
如果某特定物体在内部有均匀一致的灰度值,并且其处在一个具有其他等级灰度值的均匀背景下,使用指定阈值的方法,可以得到比较有效的分割效果。如果物体同背景的差别表现不在灰度值上(比如纹理不同),可以将这个差别特征转换为灰度的差别,然后利用阈值选取技术来分割该图像。
53.2实验任务
本节实验任务是在超越者开发板上实现将OV5640采集到的RGB565彩色图像数据转换为灰度图像数据,然后对灰度图像数据进行二值化处理,并将处理后的二值化图像显示在HDMI显示器上。
53.3硬件设计
本章节中硬件设计与“OV5640摄像头HDMI显示实验”完全相同,此处不再赘述。
53.4程序设计
根据实验任务,可以设计出如图 53.4.1所示的系统框图。本章实验的系统框架延续了“OV5640摄像头HDMI灰度显示实验”的整体架构。本次实验包括以下模块:时钟模块、DDR控制器模块、摄像头驱动模块、图像处理模块和HDMI顶层模块。其中时钟模块、DDR控制器模块、HDMI顶层模块和摄像头驱动模块没有做任何修改,这些模块在“OV5640摄像头HDMI显示实验”中已经说明过,这里不再详述,本次实验只对图像处理模块做了修改。
顶层系统框图如下所示:

图 53.4.1 顶层系统框图

由上图可知,时钟模块(clock)为HDMI顶层模块、DDR控制模块以及摄像头驱动模块提供驱动时钟。摄像头驱动模块控制着传感器初始化的开始与结束,传感器初始化完成后图像采集模块将采集到的数据写入图像处理模块,图像处理模块将处理后的数据存入DDR3,HDMI顶层模块从DDR控制模块中读出数据并驱动显示器显示,这时整个系统才完成了数据的采集、缓存与显示。需要注意的是图像数据采集模块是在DDR3和传感器都初始化完成之后才开始输出数据的,避免了在DDR3初始化过程中向里面写入数据。
顶层模块的代码如下:
  1. 1   module ov5640_hdmi_img_binarization (   
  2. 2       input                 sys_clk,         //系统时钟
  3. 3       input                 sys_rst_n,       //系统复位,低电平有效
  4. 4       //摄像头接口                          
  5. 5       input                 cam_pclk,        //cmos 数据像素时钟
  6. 6       input                 cam_vsync,       //cmos 场同步信号
  7. 7       input                 cam_href,        //cmos 行同步信号
  8. 8       input   [7:0]         cam_data,        //cmos 数据
  9. 9       output                cam_rst_n,       //cmos 复位信号,低电平有效
  10. 10      output                cam_pwdn ,       //电源休眠模式选择 0:正常模式 1:电源休眠模式
  11. 11      output                cam_scl,         //cmos SCCB_SCL线
  12. 12      inout                 cam_sda,         //cmos SCCB_SDA线      
  13. 13    //ddr3 port
  14. 14      inout   [15:0]        mcb3_dram_dq,     
  15. 15      output  [13:0]        mcb3_dram_a,      
  16. 16      output  [2:0]         mcb3_dram_ba,     
  17. 17      output                mcb3_dram_ras_n,  
  18. 18      output                mcb3_dram_cas_n,   
  19. 19      output                mcb3_dram_we_n,   
  20. 20      output                mcb3_dram_reset_n,
  21. 21      output                mcb3_dram_cke,   
  22. 22      output                mcb3_dram_dm,     
  23. 23      inout                 mcb3_dram_udqs,   
  24. 24      inout                 mcb3_dram_udqs_n,
  25. 25      inout                 mcb3_rzq,         
  26. 26      inout                 mcb3_zio,         
  27. 27      output                mcb3_dram_udm,   
  28. 28      inout                 mcb3_dram_dqs,   
  29. 29      inout                 mcb3_dram_dqs_n,  
  30. 30      output                mcb3_dram_ck,     
  31. 31      output                mcb3_dram_ck_n,      
  32. 32  
  33. 33      output                init_calib_complete,   
  34. 34      //hdmi接口                              
  35. 35      output                tmds_clk_p,         // TMDS 时钟通道
  36. 36      output                tmds_clk_n,
  37. 37      output  [2:0]         tmds_data_p,        // TMDS 数据通道
  38. 38      output  [2:0]         tmds_data_n  
  39. 39      );
  40. 40  
  41. 41  //parameter define
  42. 42  parameter  V_CMOS_DISP = 11'd768;                  //CMOS分辨率--行
  43. 43  parameter  H_CMOS_DISP = 11'd1024;                 //CMOS分辨率--列
  44. 44  parameter  TOTAL_H_PIXEL = H_CMOS_DISP + 12'd1216;
  45. 45  parameter  TOTAL_V_PIXEL = V_CMOS_DISP + 12'd504;   
  46. 46                                                                     
  47. 47  //wire define                          
  48. 48  wire         clk_50m                   ;  //50mhz时钟
  49. 49  wire         locked_100m               ;  //时钟锁定信号
  50. 50  wire         locked_300m               ;  //时钟锁定信号
  51. 51  wire         rst_n                     ;  //全局复位                                                               
  52. 52  wire         wr_en                     ;  //DDR3控制器模块写使能
  53. 53  wire  [15:0] wr_data                   ;  //DDR3控制器模块写数据
  54. 54  wire         rdata_req                 ;  //DDR3控制器模块读使能
  55. 55  wire  [15:0] rd_data                   ;  //DDR3控制器模块读数据
  56. 56  wire         cmos_frame_valid          ;  //数据有效使能信号
  57. 57  wire         init_calib_complete       ;  //DDR3初始化完成init_calib_complete
  58. 58  wire         sys_init_done             ;  //系统初始化完成(DDR初始化+摄像头初始化)
  59. 59  wire         cmos_frame_vsync          ;  //输出帧有效场同步信号
  60. 60  wire         lcd_de                    ;  //LCD 数据输入使能
  61. 61  wire         cmos_frame_href           ;  //输出帧有效行同步信号
  62. 62  wire  [10:0] h_disp                    ;  //水平分辨率
  63. 63  wire  [10:0] v_disp                    ;  //垂直分辨率     
  64. 64  wire  [29:0] ddr3_addr_max             ;  //存入DDR3的最大读写地址
  65. 65  wire  [15:0] post_rgb                  ;  //处理后的图像数据
  66. 66  wire         post_frame_vsync          ;  //处理后的场信号
  67. 67  wire         post_frame_de             ;  //处理后的数据有效使能
  68. 68  wire  [10:0] pixel_xpos                ;  //像素点横坐标
  69. 69  wire  [10:0] pixel_ypos                ;  //像素点纵坐标  
  70. 70  
  71. 71  //*****************************************************
  72. 72  //**                    main code
  73. 73  //*****************************************************
  74. 74  //待时钟锁定后产生复位结束信号
  75. 75  assign  rst_n = sys_rst_n & locked_100m & locked_300m;
  76. 76  
  77. 77  //系统初始化完成:DDR3初始化完成
  78. 78  assign  sys_init_done = init_calib_complete;
  79. 79  
  80. 80  //DDR3的最大读写地址
  81. 81  assign  ddr3_addr_max = V_CMOS_DISP * H_CMOS_DISP;
  82. 82     
  83. 83   //ov5640 驱动
  84. 84  ov5640_dri u_ov5640_dri(
  85. 85      .clk               (clk_50m),
  86. 86      .rst_n             (rst_n),
  87. 87  
  88. 88      .cam_pclk          (cam_pclk ),
  89. 89      .cam_vsync         (cam_vsync),
  90. 90      .cam_href          (cam_href ),
  91. 91      .cam_data          (cam_data ),
  92. 92      .cam_rst_n         (cam_rst_n),
  93. 93      .cam_pwdn          (cam_pwdn ),
  94. 94      .cam_scl           (cam_scl  ),
  95. 95      .cam_sda           (cam_sda  ),
  96. 96      
  97. 97      .capture_start     (init_calib_complete),
  98. 98      .cmos_h_pixel      (H_CMOS_DISP),
  99. 99      .cmos_v_pixel      (V_CMOS_DISP),
  100. 100     .total_h_pixel     (TOTAL_H_PIXEL),
  101. 101     .total_v_pixel     (TOTAL_V_PIXEL),
  102. 102     .cmos_frame_vsync  (cmos_frame_vsync),
  103. 103     .cmos_frame_href   (cmos_frame_href),
  104. 104     .cmos_frame_valid  (cmos_frame_valid),
  105. 105     .cmos_frame_data   (wr_data)
  106. 106     );
  107. 107
  108. 108  //图像处理模块
  109. 109 vip u_vip(
  110. 110     //module clock
  111. 111     .clk              (cam_pclk),          // 时钟信号
  112. 112     .rst_n            (rst_n ),            // 复位信号(低有效)
  113. 113     //图像处理前的数据接口
  114. 114     .pre_frame_vsync  (cmos_frame_vsync),
  115. 115     .pre_frame_hsync  (cmos_frame_href),
  116. 116     .pre_frame_de     (cmos_frame_valid),
  117. 117     .pre_rgb          (wr_data),
  118. 118     .xpos             (pixel_xpos),
  119. 119     .ypos             (pixel_ypos),
  120. 120     //图像处理后的数据接口
  121. 121     .post_frame_vsync (post_frame_vsync),  // 处理后的场信号
  122. 122     .post_frame_hsync ( ),                 // 处理后的行信号
  123. 123     .post_frame_de    (post_frame_de),     // 处理后的数据有效使能
  124. 124     .post_rgb         (post_rgb)           // 处理后的图像数据
  125. 125
  126. 126 );  
  127. 127     
  128. 128 //ddr控制器
  129. 129 ddr3_control
  130. 130  #(
  131. 131    .C3_NUM_DQ_PINS         (16),
  132. 132    .C3_MEM_ADDR_WIDTH      (14),
  133. 133    .C3_MEM_BANKADDR_WIDTH  (3)
  134. 134    )
  135. 135  u_ddr3_control(
  136. 136   .clk_ddr                (clk_ddr),                              
  137. 137   .clk_100m               (clk_100m),                             
  138. 138   .rst_n                  (sys_rst_n),                           
  139. 139   .mcb3_dram_dq           (mcb3_dram_dq     ),                    
  140. 140   .mcb3_dram_a            (mcb3_dram_a      ),                    
  141. 141   .mcb3_dram_ba           (mcb3_dram_ba     ),                    
  142. 142   .mcb3_dram_ras_n        (mcb3_dram_ras_n  ),                    
  143. 143   .mcb3_dram_cas_n        (mcb3_dram_cas_n  ),                    
  144. 144   .mcb3_dram_we_n         (mcb3_dram_we_n   ),                    
  145. 145   .mcb3_dram_reset_n      (mcb3_dram_reset_n),                    
  146. 146   .mcb3_dram_cke          (mcb3_dram_cke    ),                    
  147. 147   .mcb3_dram_dm           (mcb3_dram_dm     ),                    
  148. 148   .mcb3_dram_udqs         (mcb3_dram_udqs   ),                    
  149. 149   .mcb3_dram_udqs_n       (mcb3_dram_udqs_n ),                    
  150. 150   .mcb3_rzq               (mcb3_rzq         ),                    
  151. 151   .mcb3_zio               (mcb3_zio         ),                    
  152. 152   .mcb3_dram_udm          (mcb3_dram_udm    ),                    
  153. 153   .mcb3_dram_dqs          (mcb3_dram_dqs    ),                    
  154. 154   .mcb3_dram_dqs_n        (mcb3_dram_dqs_n  ),                    
  155. 155   .mcb3_dram_ck           (mcb3_dram_ck     ),                    
  156. 156   .mcb3_dram_ck_n         (mcb3_dram_ck_n   ),                    
  157. 157   .c3_calib_done          (init_calib_complete),                  
  158. 158                                                                  
  159. 159   .ddr3_read_valid        (1'b1 ),                                
  160. 160   .ddr3_pingpang_en       (1'b1),                                 
  161. 161                                                                  
  162. 162   //摄像头                                                        
  163. 163   .clk_write              (cam_pclk),              //写时钟                          
  164. 164   .wr_en                  (post_frame_de),         //写使能                        
  165. 165   .wr_data                (post_rgb),              //写数据  
  166. 166   .wr_load                (post_frame_vsync),      //写端更新信号   
  167. 167   .wr_length              (H_CMOS_DISP[10:3]),     //一次写长度                          
  168. 168   .wr_max_addr            (ddr3_addr_max),         //写最大地址   
  169. 169   .wr_min_addr            (0),                     //写最小地址                        
  170. 170                                                                             
  171. 171   .clk_read               (pixel_clk),             //读时钟   
  172. 172   .rd_load                (video_vs),              //读端更新信号   
  173. 173   .rd_en                  (rdata_req),             //读使能                        
  174. 174   .rd_max_addr            (ddr3_addr_max),         //读最大地址   
  175. 175   .rd_min_addr            (0),                     //读最小地址                        
  176. 176   .rd_length              (H_CMOS_DISP[10:3]),     //一次读长度                        
  177. 177   .rd_data                (rd_data)                //读数据                        
  178. 178                                                                  
  179. 179   );
  180. 180
  181. 181 //时钟模块
  182. 182 clock u_clock(
  183. 183     .sys_clk      (sys_clk),       //系统输入时钟
  184. 184
  185. 185     .clk_ddr      (clk_ddr),       //ddr运行时钟
  186. 186     .clk_50m      (clk_50m),       //50m时钟
  187. 187     .clk_100m     (clk_100m),      //100m时钟
  188. 188     .locked_100m  (locked_100m),   //时钟稳定信号
  189. 189     .locked_300m  (locked_300m)    //时钟稳定信号
  190. 190     
  191. 191 );
  192. 192
  193. 193 //HDMI驱动显示模块   
  194. 194 hdmi_top u_hdmi_top(
  195. 195     .clk_50m              (clk_50m),  
  196. 196     .pixel_clk            (pixel_clk),  
  197. 197     .sys_rst_n            (sys_init_done & rst_n),
  198. 198     //hdmi接口                  
  199. 199     .tmds_clk_p           (tmds_clk_p   ),   // TMDS 时钟通道
  200. 200     .tmds_clk_n           (tmds_clk_n   ),
  201. 201     .tmds_data_p          (tmds_data_p  ),   // TMDS 数据通道
  202. 202     .tmds_data_n          (tmds_data_n  ),
  203. 203     //用户接口
  204. 204     .h_disp               (h_disp),          //HDMI屏水平分辨率
  205. 205     .v_disp               (v_disp),          //HDMI屏垂直分辨率
  206. 206     .video_vs             (video_vs),   
  207. 207     .pixel_xpos           (pixel_xpos),
  208. 208     .pixel_ypos           (pixel_ypos),      
  209. 209     .data_in              (rd_data),         //数据输入     
  210. 210     .data_req             (rdata_req)        //请求数据输入   
  211. 211 );
  212. 212
  213. 213 endmodule
复制代码

FPGA顶层模块(ov5640_hdmi_img_binarization)例化了以下五个模块:时钟模块(clock)、OV5640驱动模块(ov5640_dri)、图像处理模块(vip)、DDR控制模块(ddr3_control)和HDMI顶层模块(hdmi_top)。
时钟模块(clock):时钟模块通过调用DCM_CLKGEN IP核实现,共输出3个时钟,频率分别为300Mhz、50Mhz时钟和100Mhz时钟。300Mhz时钟作为DDR控制模块的运行时钟;100Mhz时钟作为DDR控制模块的驱动时钟;50Mhz时钟作为OV5640驱动模块和HDMI顶层模块的驱动时钟。
OV5640驱动模块(ov5640_dri):OV5640驱动模块负责驱动OV5640 SCCB接口总线,以及将像素时钟驱动下的传感器输出的场同步信号、行同步信号以及8位数据转换成DDR读写控制模块的写使能信号和16位写数据信号,完成对OV5640传感器图像的采集。
图像处理模块(vip):对采集后的图像数据进行处理,并将处理后的数据存入DDR控制模块。
DDR控制模块(ddr3_control):DDR读写控制器模块负责驱动DDR片外存储器,缓存图像传感器输出的图像数据。该模块将MIG IP核复杂的读写操作封装成类似FIFO的用户接口,非常方便用户的使用。有关DDR控制模块的详细介绍请大家参考“DDR读写测试实验”章节。
HDMI顶层模块(hdmi_top):HDMI顶层模块负责驱动HDMI显示器的驱动信号的输出,同时为其他模块提供参数和数据请求信号。HDMI顶层模块例化了HDMI驱动模块(video_driver)和RGB转DVI模块(rgbtodvi_top)。HDMI驱动模块负责产生行场信号和数据有效使能信号和像素点的横纵坐标,并将内部信号data_req(数据请求信号)输出至端口,方便从DDR控制器中读取数据。RGB转DVI模块负责将RGB888格式的视频图像转换成TMDS数据输出。有关HDMI驱动模块、RGB转DVI模块的详细介绍请大家参考“HDMI彩条显示实验”章节。
VIP模块框图如下图所示:

图 53.4.2 vip模块框图

vip模块例化了RGB转YCbCr模块(rgb2ycbcr)、中值滤波模块(vip_gray_median_jilter)和二值化模块(binarization)。RGB转YCbCr模块负责将摄像头采集的RGB565格式的彩色图像转换为灰度图像。中值滤波模块负责对图像进行中值滤波后输出。二值化模块负责将中值滤波后的视频图像进行二值化处理再输出。有关RGB转YCbCr模块的详细介绍请大家参考“OV5640摄像头HDMI灰度显示实验”章节。有关中值滤波模块的详细介绍请大家参考“基于OV5640的中值滤波实验”章节。
vip模块原理图如下图所示:

图 53.4.3 vip模块原理图

如上图所示,摄像头采集到16位rgb565输入vip模块,经过“rgb2ycbcr”模块转化为8位的灰度值img_y(YUV中的亮度Y),然后在将转化后的灰度数据(img_y)作为“vip_gray_median_filter”模块的输入,对灰度进行中值滤波处理,再将中值滤波后的数据输入进二值化模块,对数据进行二值化处理,最后输出经过二值化处理后的灰度数据“monoc”。
图像处理模块负责图像数据的格式转换,代码如下:
  1. 1  module vip(
  2. 2      //module clock
  3. 3      input           clk            ,   // 时钟信号
  4. 4      input           rst_n          ,   // 复位信号(低有效)
  5. 5  
  6. 6      //图像处理前的数据接口
  7. 7      input           pre_frame_vsync,   
  8. 8      input           pre_frame_hsync,
  9. 9      input           pre_frame_de   ,
  10. 10     input    [15:0] pre_rgb        ,
  11. 11     input    [10:0] xpos           ,
  12. 12     input    [10:0] ypos           ,
  13. 13
  14. 14     //图像处理后的数据接口
  15. 15     output          post_frame_vsync,  // 场同步信号
  16. 16     output          post_frame_hsync,  // 行同步信号
  17. 17     output          post_frame_de   ,  // 数据输入使能
  18. 18     output   [15:0] post_rgb           // RGB565颜色数据
  19. 19
  20. 20
  21. 21 );
  22. 22
  23. 23 //wire define
  24. 24 wire   [ 7:0]         img_y;
  25. 25 wire   [ 7:0]         post_img_y;
  26. 26 wire   [15:0]         post_rgb;
  27. 27 wire                  post_frame_vsync;
  28. 28 wire                  post_frame_hsync;
  29. 29 wire                  post_frame_de;
  30. 30 wire                  pe_frame_vsync;
  31. 31 wire                  pe_frame_href;
  32. 32 wire                  pe_frame_clken;
  33. 33 wire                  ycbcr_vsync;
  34. 34 wire                  ycbcr_hsync;
  35. 35 wire                  ycbcr_de;
  36. 36 wire                  monoc;
  37. 37
  38. 38 //*****************************************************
  39. 39 //**                    main code
  40. 40 //*****************************************************
  41. 41
  42. 42 assign  post_rgb = {16{monoc}};
  43. 43
  44. 44 //RGB转YCbCr模块
  45. 45 rgb2ycbcr u_rgb2ycbcr(
  46. 46     //module clock
  47. 47     .clk             (clk    ),            // 时钟信号
  48. 48     .rst_n           (rst_n  ),            // 复位信号(低有效)
  49. 49     //图像处理前的数据接口
  50. 50     .pre_frame_vsync (pre_frame_vsync),    // vsync信号
  51. 51     .pre_frame_hsync (pre_frame_hsync),    // href信号
  52. 52     .pre_frame_de    (pre_frame_de   ),    // data enable信号
  53. 53     .img_red         (pre_rgb[15:11] ),
  54. 54     .img_green       (pre_rgb[10:5 ] ),
  55. 55     .img_blue        (pre_rgb[ 4:0 ] ),
  56. 56     //图像处理后的数据接口
  57. 57     .post_frame_vsync(pe_frame_vsync),     // vsync信号
  58. 58     .post_frame_hsync(pe_frame_href),      // href信号
  59. 59     .post_frame_de   (pe_frame_clken),     // data enable信号
  60. 60     .img_y           (img_y),              //灰度数据
  61. 61     .img_cb          (),
  62. 62     .img_cr          ()
  63. 63 );
  64. 64
  65. 65 //灰度图中值滤波
  66. 66 vip_gray_median_filter u_vip_gray_median_filter(
  67. 67     .clk    (clk),   
  68. 68     .rst_n  (rst_n),
  69. 69     
  70. 70     //预处理图像数据
  71. 71     .pe_frame_vsync (pe_frame_vsync),      // vsync信号
  72. 72     .pe_frame_href  (pe_frame_href),       // href信号
  73. 73     .pe_frame_clken (pe_frame_clken),      // data enable信号
  74. 74     .pe_img_y       (img_y),               
  75. 75                                            
  76. 76     //处理后的图像数据                     
  77. 77     .pos_frame_vsync (ycbcr_vsync),        // vsync信号
  78. 78     .pos_frame_href  (ycbcr_hsync),        // href信号
  79. 79     .pos_frame_clken (ycbcr_de),           // data enable信号
  80. 80     .pos_img_y       (post_img_y)          //中值滤波后的灰度数据
  81. 81 );
  82. 82
  83. 83 //二值化模块
  84. 84 binarization  u_binarization(
  85. 85     .clk         (clk),
  86. 86     .rst_n       (rst_n),
  87. 87     //图像处理前的数据接口     
  88. 88     .ycbcr_vsync (ycbcr_vsync),
  89. 89     .ycbcr_hsync (ycbcr_hsync),
  90. 90     .ycbcr_de    (ycbcr_de),
  91. 91     .luminance   (post_img_y),
  92. 92     //图像处理后的数据接口     
  93. 93     .post_vsync  (post_frame_vsync),
  94. 94     .post_hsync  (post_frame_hsync),
  95. 95     .post_de     (post_frame_de),
  96. 96     .monoc       (monoc)                   //二值化后的数据
  97. 97 );
  98. 98 endmodule
复制代码

代码的第42行表示对二值化后的1bit灰度数据进行位拼接,形成16bit的RGB565格式的数据输出。
代码的第45行至63行是对灰度转换模块的例化,在该模块以摄像头采集的16位RGB565红、绿、蓝三原色数据作为输入数据,通过算法实现RGB到YCbCr的转换,并输出8位灰度数据以及数据输出使能信号。有关RGB转YCbCr模块的详细介绍请大家参考“OV5640摄像头HDMI灰度显示实验”章节。
代码的第66行至81行是对中值滤波模块的例化,该模块负责将转换后的灰度图像进行中值滤波后输出。有关中值滤波模块的详细介绍请大家参考“基于OV5640的中值滤波实验”章节。
代码的第84行至96行是对二值化模块的例化,该模块主要是根据设定阈值,将图像化分为黑白两种颜色。
中值滤波模块和灰度转换模块在前面的章节已经讲解过,本次实验不再赘述。本次实验重点讲解二值化模块,下面是二值化模块的代码:
  1. 1  module binarization(
  2. 2      //module clock
  3. 3      input               clk             ,   // 时钟信号
  4. 4      input               rst_n           ,   // 复位信号(低有效)
  5. 5  
  6. 6      //图像处理前的数据接口
  7. 7      input               ycbcr_vsync     ,   // vsync信号
  8. 8      input               ycbcr_hsync     ,   // hsync信号
  9. 9      input               ycbcr_de        ,   // data enable信号
  10. 10     input   [7:0]       luminance       ,
  11. 11
  12. 12     //图像处理后的数据接口
  13. 13     output              post_vsync      ,   // vsync信号
  14. 14     output              post_hsync      ,   // hsync信号
  15. 15     output              post_de         ,   // data enable信号
  16. 16     output   reg        monoc               // monochrome(1=白,0=黑)
  17. 17 );
  18. 18
  19. 19 //reg define
  20. 20 reg    ycbcr_vsync_d;
  21. 21 reg    ycbcr_hsync_d;
  22. 22 reg    ycbcr_de_d   ;
  23. 23
  24. 24 //*****************************************************
  25. 25 //**                    main code
  26. 26 //*****************************************************
  27. 27
  28. 28 assign  post_vsync = ycbcr_vsync_d  ;
  29. 29 assign  post_hsync = ycbcr_hsync_d  ;
  30. 30 assign  post_de    = ycbcr_de_d     ;
  31. 31
  32. 32 //二值化
  33. 33 always @(posedge clk or negedge rst_n) begin
  34. 34     if(!rst_n)
  35. 35         monoc <= 1'b0;
  36. 36     else if(luminance > 8'd64)  //阈值
  37. 37         monoc <= 1'b1;
  38. 38     else
  39. 39         monoc <= 1'b0;
  40. 40 end
  41. 41
  42. 42 //延时1拍以同步时钟信号
  43. 43 always@(posedge clk or negedge rst_n) begin
  44. 44     if(!rst_n) begin
  45. 45         ycbcr_vsync_d <= 1'd0;
  46. 46         ycbcr_hsync_d <= 1'd0;
  47. 47         ycbcr_de_d    <= 1'd0;
  48. 48     end
  49. 49     else begin
  50. 50         ycbcr_vsync_d <= ycbcr_vsync;
  51. 51         ycbcr_hsync_d <= ycbcr_hsync;
  52. 52         ycbcr_de_d    <= ycbcr_de   ;
  53. 53     end
  54. 54 end
  55. 55
  56. 56 endmodule
复制代码

二值化的主要原理就是,给出一个设定的阈值,将灰度值与该阈值比较,若灰度值大于该阈值则monoc为1,若小于阈值,则monoc为0,如代码第33到40行。理论上阈值可以是0到255中的任意值,但阈值过大,会提取多余的部分;而阈值过小,又会丢失所需的部分,因此阈值选取就是一个很重要的步骤。
在代码第43到54行,通过寄存操作对gray_vsync、gray_clken等信号作了一个时钟周期的延迟。这是因为在进行二值判定时消耗了一个时钟,因此相应的同步信号也要延迟一个时钟周期,以实现与数据的同步。
53.5下载验证
编译完工程之后就可以开始下载程序了。将OV5640摄像头模块插在超越者开发板的“OLED/CAMERA”插座上,并将HDMI电缆一端连接到开发板上的HDMI插座、另一端连接到显示器。将下载器一端连电脑,另一端与开发板上的JTAG端口连接,连接电源线并打开电源开关。接下来我们下载程序,下载完成后HDMI显示器上会显示OV5640摄像头采集到的经FPGA处理后的二值化图像,如下图所示:

图 53.5.1 HDMI实时显示二值化图像


回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

如发现本坛存在违规或侵权内容, 请点击这里发送邮件举报 (或致电020-38271790)。请提供侵权说明和联系方式。我们将及时审核依法处理,感谢配合。

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2026-7-7 18:35

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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