正点原子 发表于 2020-12-10 10:47:16

【正点原子FPGA连载】第四十六章基于OV5640的二值化实验

本帖最后由 正点原子 于 2021-1-23 15:31 编辑

1)实验平台:正点原子达芬奇FPGA开发板
2)章节摘自【正点原子】达芬奇之FPGA开发指南
3)购买链接:https://detail.tmall.com/item.htm?id=624335496505
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz_dafenqi.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)对正点原子FPGA感兴趣的同学可以加群讨论:905624739 点击加入:





第四十六章基于OV5640的二值化实验


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

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

图 46.4.1 顶层系统框图
由上图可知,时钟模块(clk_wiz_0)为HDMI顶层模块、DDR控制模块以及OV5640驱动模块提供驱动时钟。OV5640驱动模块控制着传感器初始化的开始与结束,传感器初始化完成后将采集到的数据写入图像处理模块。图像处理模块将摄像头数据进行处理后存入DDR控制模块。顶层模块从DDR控制模块中读出数据并驱动显示器显示,这时整个系统才完成了数据的采集、缓存与显示。需要注意的是图像数据采集模块是在DDR3和传感器都初始化完成之后才开始输出数据的,避免了在DDR3初始化过程中向里面写入数据。
顶层模块的原理图如下图所示:

图 46.4.2 顶层模块原理图
FPGA顶层模块(ov5640_hdmi_img_binarization)例化了以下五个模块:时钟模块(clk_wiz_0)、OV5640驱动模块(ov5640_dri)、图像处理模块(vip)、DDR控制模块(ddr3_top)和HDMI顶层模块(hdmi_top)。   
时钟模块(clk_wiz_0):时钟模块通过调用MMCM IP核实现,共输出4个时钟,频率分别为200Mhz(DDR3参考时钟)、50Mhz时钟、65Mhz时钟和325M时钟(HDMI像素时钟的5倍频)。200Mhz时钟作为DDR控制模块的参考时钟,由MIG IP核产生的ui_clk(本次设计为100Mhz)作为DDR控制模块的驱动时钟,50Mhz时钟作为OV5640驱动模块驱动时钟,65Mhz时钟和325M时钟(HDMI像素时钟的5倍频)负责驱动HDMI顶层模块。
OV5640驱动模块(ov5640_dri):OV5640驱动模块负责驱动OV5640 SCCB接口总线,将像素时钟驱动下的传感器输出的场同步信号、行同步信号以及8位数据转换成DDR读写控制模块的写使能信号和16位写数据信号,完成对OV5640传感器图像的采集。
图像处理模块(vip):对采集后的图像数据进行处理,并将处理后的数据存入DDR控制模块。
DDR控制模块(ddr3_top):DDR读写控制器模块负责驱动DDR片外存储器,缓存图像传感器输出的图像数据。该模块将MIG IP核复杂的读写操作封装成类似FIFO的用户接口,非常方便用户的使用。
有关DDR控制模块的详细介绍请大家参考“OV7725摄像头RGB-LCD显示实验”章节。
HDMI顶层模块(hdmi_top):HDMI顶层模块负责驱动HDMI显示器的驱动信号的输出,同时为其他模块提供显示器参数、场同步信号和数据请求信号。关HDMI顶层模块的详细介绍请大家参考“OV5640摄像头HDMI显示实验”章节。
VIP模块框图如下图所示:


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

图 46.4.4 vip模块原理图
如上图所示,摄像头采集到16位rgb565输入vip模块,经过“rgb2ycbcr”模块转化为8位的yuv444数据,然后在将转化后的灰度数据(img_y)作为“vip_gray_median_filter”模块的输入,对灰度进行中值滤波处理,再将中值滤波后的数据输入进二值化模块,对数据进行二值化处理,最后输出经过二值化处理后的灰度数据“monoc”。
图像处理模块负责图像数据的格式转换,代码如下:
1module vip(
2      //module clock
3      input         clk            ,   // 时钟信号
4      input         rst_n          ,   // 复位信号(低有效)
5
6      //图像处理前的数据接口
7      input         pre_frame_vsync,   
8      input         pre_frame_hsync,
9      input         pre_frame_de   ,
10   input    pre_rgb      ,
11   input    xpos         ,
12   input    ypos         ,
13
14   //图像处理后的数据接口
15   output          post_frame_vsync,// 场同步信号
16   output          post_frame_hsync,// 行同步信号
17   output          post_frame_de   ,// 数据输入使能
18   output    post_rgb         // RGB565颜色数据
19
20
21 );
22
23 //wire define
24 wire   [ 7:0]         img_y;
25 wire   [ 7:0]         post_img_y;
26 wire            post_rgb;
27 wire                  post_frame_vsync;
28 wire                  post_frame_hsync;
29 wire                  post_frame_de;
30 wire                  pe_frame_vsync;
31 wire                  pe_frame_href;
32 wire                  pe_frame_clken;
33 wire                  ycbcr_vsync;
34 wire                  ycbcr_hsync;
35 wire                  ycbcr_de;
36 wire                  monoc;
37 //*****************************************************
38 //**                  main code
39 //*****************************************************
40
41 assignpost_rgb = {16{monoc}};
42
43 //RGB转YCbCr模块
44 rgb2ycbcr u_rgb2ycbcr(
45   //module clock
46   .clk             (clk    ),            // 时钟信号
47   .rst_n         (rst_n),            // 复位信号(低有效)
48   //图像处理前的数据接口
49   .pre_frame_vsync (pre_frame_vsync),    // vsync信号
50   .pre_frame_hsync (pre_frame_hsync),    // href信号
51   .pre_frame_de    (pre_frame_de   ),    // data enable信号
52   .img_red         (pre_rgb ),
53   .img_green       (pre_rgb ),
54   .img_blue      (pre_rgb[ 4:0 ] ),
55   //图像处理后的数据接口
56   .post_frame_vsync(pe_frame_vsync),   // vsync信号
57   .post_frame_hsync(pe_frame_href),      // href信号
58   .post_frame_de   (pe_frame_clken),   // data enable信号
59   .img_y         (img_y),            //灰度数据
60   .img_cb          (),
61   .img_cr          ()
62 );
63
64 //灰度图中值滤波
65 vip_gray_median_filter u_ vip_gray_median_filter (
66   .clk    (clk),   
67   .rst_n(rst_n),
68   
69   //预处理图像数据
70   .pe_frame_vsync (pe_frame_vsync),      // vsync信号
71   .pe_frame_href(pe_frame_href),       // href信号
72   .pe_frame_clken (pe_frame_clken),      // data enable信号
73   .pe_img_y       (img_y),               
74                                          
75   //处理后的图像数据                     
76   .pos_frame_vsync (ycbcr_vsync),      // vsync信号
77   .pos_frame_href(ycbcr_hsync),      // href信号
78   .pos_frame_clken (ycbcr_de),         // data enable信号
79   .pos_img_y       (post_img_y)          //中值滤波后的灰度数据
80 );
81
82 //二值化模块
83 binarizationu_binarization(
84   .clk         (clk),
85   .rst_n       (rst_n),
86   //图像处理前的数据接口   
87   .ycbcr_vsync (ycbcr_vsync),
88   .ycbcr_hsync (ycbcr_hsync),
89   .ycbcr_de    (ycbcr_de),
90   .luminance   (post_img_y),
91   //图像处理后的数据接口   
92   .post_vsync(post_frame_vsync),
93   .post_hsync(post_frame_hsync),
94   .post_de   (post_frame_de),
95   .monoc       (monoc)                   //二值化后的数据
96 );
97 endmodule
代码的第37行表示对二值化后的1bit灰度数据进行位拼接,形成16bit的RGB565格式的数据输出。
代码的第39行至58行是对灰度转换模块的例化,在该模块以摄像头采集的16位RGB565红、绿、蓝三原色数据作为输入数据,通过算法实现RGB到YCbCr的转换,并输出8位灰度数据,并输出数据输出使能信号。有关RGB转YCbCr模块的详细介绍请大家参考“OV5640摄像头HDMI灰度显示实验”章节。
代码的第61行至75行是对中值滤波模块的例化,该模块负责将YUV格式的视频图像进行中值滤波后输出。有关中值滤波模块的详细介绍请大家参考“基于OV5640的中值滤波实验”章节。
代码的第83行至96行是对二值化模块的例化,该模块主要是根据设定阈值,将图像化分为黑白两种颜色。
中值滤波模块和灰度转换模块在前面的章节已经讲解过,本次实验不在讲述。本次实验重点讲解二值化模块,下面是二值化模块的代码。
1module binarization(
2      //module clock
3      input               clk             ,   // 时钟信号
4      input               rst_n         ,   // 复位信号(低有效)
5
6      //图像处理前的数据接口
7      input               ycbcr_vsync   ,   // vsync信号
8      input               ycbcr_hsync   ,   // hsync信号
9      input               ycbcr_de      ,   // data enable信号
10   input          luminance       ,
11
12   //图像处理后的数据接口
13   output            post_vsync      ,   // vsync信号
14   output            post_hsync      ,   // hsync信号
15   output            post_de         ,   // data enable信号
16   output   reg      monoc               // monochrome(1=白,0=黑)
17 );
18
19 //reg define
20 reg    ycbcr_vsync_d;
21 reg    ycbcr_hsync_d;
22 reg    ycbcr_de_d   ;
23
24 //*****************************************************
25 //**                  main code
26 //*****************************************************
27
28 assignpost_vsync = ycbcr_vsync_d;
29 assignpost_hsync = ycbcr_hsync_d;
30 assignpost_de    = ycbcr_de_d   ;
31
32 //二值化
33 always @(posedge clk or negedge rst_n) begin
34   if(!rst_n)
35         monoc <= 1'b0;
36   else if(luminance > 8'd64)//阈值
37         monoc <= 1'b1;
38   else
39         monoc <= 1'b0;
40 end
41
42 //延时1拍以同步时钟信号
43 always@(posedge clk or negedge rst_n) begin
44   if(!rst_n) begin
45         ycbcr_vsync_d <= 1'd0;
46         ycbcr_hsync_d <= 1'd0;
47         ycbcr_de_d    <= 1'd0;
48   end
49   else begin
50         ycbcr_vsync_d <= ycbcr_vsync;
51         ycbcr_hsync_d <= ycbcr_hsync;
52         ycbcr_de_d    <= ycbcr_de   ;
53   end
54 end
55
56 endmodule
二值化的主要原理就是,给出一个设定的阈值,将灰度值与该阈值比较,若灰度值大于该阈值则monoc为1,若小于阈值,则monoc为0,如代码第33到40行。理论上阈值可以是0到255中的任意值,但阈值过大,会提取多余的部分;而阈值过小,又会丢失所需的部分,因此阈值选取就是一个很重要的步骤。
在代码第43到54行,通过寄存操作对gray_vsync、gray_clken等信号作了一个时钟周期的延迟。这是因为在进行二值判定时消耗了一个时钟,因此相应的同步信号也要延迟一个时钟周期,以实现与数据的同步。
46.5下载验证
编译完工程之后就可以开始下载程序了。将OV5640摄像头模块插在达芬奇开发板的“OLED/CAMERA”插座上,并将HDMI电缆一端连接到开发板上的HDMI_B插座、另一端连接到显示器。将下载器一端连电脑,另一端与开发板上的JTAG端口连接,连接电源线并打开电源开关。接下来我们下载程序,下载完成后观察HDMI显示器显示的二值化后的图案。如下图所示:


图 46.5.1HDMI实时显示二值化图像
页: [1]
查看完整版本: 【正点原子FPGA连载】第四十六章基于OV5640的二值化实验