完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1)实验平台:正点原子开拓者FPGA 开发板
2)摘自《开拓者FPGA开发指南》关注官方微信号公众号,获取更多资料:正点原子 3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-13912-1-1.html 第五十三章 OV5640 摄像头灰度图 VGA 显示实验 前面的实验我们介绍了OV5640摄像头的VGA显示实验,而在数字图像处理领域YUV是一种很 常用的图像格式,其特点是将亮度和色度进行分离。在本章实验中,我们将进行RGB565到YUV 的颜色空间转换,并通过VGA显示摄像头采集到的图像的灰度图的实验。 本章包括以下几个部分: 53.1 YUV 简介 53.2 实验任务 53.3 硬件设计 53.4 程序设计 53.5 下载验证 YUV 简介 人眼中的锥状细胞是负责彩色视觉的传感器,可分为三个主要的感知类别,分别对应红色、 绿色、蓝色,我们人眼看到的彩色实际上是红、绿、蓝三原色的各种组合。前面我们用到的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 信号的提出,是因为国际上出现彩色电视,为了兼容黑白电视的信号而设计的,在视 频码率,压缩,兼容性等方面有很大优势。一般意义上 YCbCr即为 YUV信号,没有严格的划 分。CbCr 分别为蓝色色度分量、红色色度分量。其主要采样格式有YCbCr4:2:2、YCbCr4:2:0、 YCbCr4:4:4、YCbCr4:1:1。下面将介绍这四种采样格式。 (1)YCbCr4:4:4: YUV三个信道的抽样率相同,因此在生成的图像里,每个象素的三个分量信息完整(每个 分量通常8比特),经过8比特量化之后,未经压缩的每个像素占用3个字节。 下面的四个像素为: [Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3] 存放的码流为: Y0 U0 V0 Y1 U1 V1 Y2 U2 V2 Y3 U3 V3 图 53.1.1 YUV444像素格式 根据存储顺序不同,YUV444又分为以下两种形式: 图 53.1.2 两种不同格式的YUV444像素 (2)YCbCr4:2:2: 每个色差信道的抽样率是亮度信道的一半,所以水平方向的色度抽样率只是4:4:4的一半。 对非压缩的8比特量化的图像来说,每个由两个水平方向相邻的像素组成的宏像素需要占用4字 节内存。 下面的四个像素为: [Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3] 存放的码流为: Y0 U0 Y1 V1 Y2 U2 Y3 V3 映射出像素点为:[Y0 U0 V1] [Y1 U0 V1] [Y2 U2 V3] [Y3 U2 V3] 图 53.1.3 YUV422像素格式 同样,根据存储顺序,YUV422可以分为六种不同格式: 图 53.1.4 六种不同的YUV422格式 (3)YCbCr4:2:0 4:2:0并不意味着只有Y,Cb而没有Cr分量。它指得是对每行扫描线来说,只有一种色度分 量以2:1的抽样率存储。相邻的扫描行存储不同的色度分量,也就是说,如果一行是4:2:0的话, 下一行就是4:0:2,再下一行是4:2:0...以此类推。对每个色度分量来说,水平方向和竖直方 向的抽样率都是2:1,所以可以说色度的抽样率是4:1。对非压缩的8比特量化的视频来说,每 个由2x2个2行2列相邻的像素组成的宏像素需要占用6字节内存。 下面八个像素为:[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3][Y5 U5 V5] [Y6 U6 V6] [Y7U7 V7] [Y8 U8 V8] 存放的码流为:Y0 U0 Y1 Y2 U2 Y3Y5 V5 Y6 Y7 V7 Y8 映射出的像素点为:[Y0 U0 V5] [Y1 U0 V5] [Y2 U2 V7] [Y3 U2 V7][Y5 U0 V5] [Y6 U0 V5] [Y7U2 V7] [Y8 U2 V7] (4)YCbCr4:1:1: 4:1:1的色度抽样,是在水平方向上对色度进行4:1抽样。对于低端用户和消费类产品这仍 然是可以接受的。对非压缩的8比特量化的视频来说,每个由4个水平方向相邻的像素组成的宏 像素需要占用6字节内存。 下面的四个像素为: [Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3] 存放的码流为: Y0 U0 Y1 Y2 V2 Y3 映射出像素点为:[Y0 U0 V2] [Y1 U0 V2] [Y2 U0 V2] [Y3 U0 V2] 下面为 RGB 与 YCbCr 色彩空间转换的算法公式, RGB 转 YCbCr 的公式如下所示: 图 53.1.5 RGB 转 YcbCr算法 由于 Verilog HDL 无法进行浮点运算,因此使用扩大 256 倍,再向右移 8Bit的方式, 来转换公式,如下所示: 图 53.1.6 RGB 转 YcbCr算法 为了防止运算过程中出现负数,我们对上述公式进行进一步变换,得到如下公式: 图 53.1.7 RGB 转 YcbCr算法 实际上OV5640本身支持输出RGB、YUV格式的数据,本章节实验是着重于实RGB转YUV的HDL 算法实现,因此我们把摄像头设置为RGB565格式。当我们需要显示器显示灰度图时,我们只需 要将转换后的Y值作为R、G、B三原色通道的输入就可以实现了。 实验任务 本节实验任务是使用开拓者开发板及OV5640摄像头采集RGB565格式的数据,并通过算法转 换,将RGB565格式转换为YCbCr格式,然后通过VGA显示器实时显示灰度图。 硬件设计 本章节中硬件设计与OV5640的VGA显示实验完全相同,在此就不在赘述。 程序设计 下图是根据本章实验任务画出的系统框图。对比OV5640摄像头VGA显示实验,本实验中添 加了rgb2ycbcr模块,该模块用于将摄像头采集到的RGB565数据转换成YCbCr格式数据,并将转 换后的数据写入SDRAM。 OV5640摄像头VGA显示灰度图系统框图如下图所示: 图 53.4.1 OV5640摄像头VGA显示灰度图系统框图 顶层模块原理图如下图所示: 图 53.4.2 rgb2yuv模块原理图 有关各个模块的功能可以参考“OV5640摄像头VGA显示实验”的相关描述,在本实验中我 们添加了rgb2ycbcr模块,在这里我们将对rgb2ycbcr模块的功能进行描述。 rgb2ycbcr模块的原理图如下: 图 53.4.3 rgb2ycbcr模块原理图 在该模块以摄像头采集的16位RGB565红、绿、蓝三原色数据作为输入数据,通过算法实现 RGB到YCbCr的转换,并输出三路8位数据和数据输出使能信号。 有关于摄像头、SDRAM的配置,VGA的驱动在前面的章节以有过介绍,本章节我们着重介绍 RGB转YUV的算法模块。 RGB转YUV模块的代码如下: 1 module rgb2ycbcr 2 ( 3 //module clock 4 input clk , // 模块驱动时钟 5 input rst_n , // 复位信号 6 7 //图像处理前的数据接口 8 input pre_frame_vsync , // vsync信号 9 input pre_frame_hsync , // hsync信号 10 input pre_frame_de , // data enable信号 11 input [4:0] img_red , // 输入图像数据R 12 input [5:0] img_green , // 输入图像数据G 13 input [4:0] img_blue , // 输入图像数据B 14 15 //图像处理后的数据接口 16 output post_frame_vsync, // vsync信号 17 output post_frame_hsync, // hsync信号 18 output post_frame_de , // data enable信号 19 output [7:0] img_y, // 输出图像Y数据 20 output [7:0] img_cb, 21 output [7:0] img_cr 22 ); 23 24 //reg define 25 reg [15:0] rgb_r_m0, rgb_r_m1, rgb_r_m2; 26 reg [15:0] rgb_g_m0, rgb_g_m1, rgb_g_m2; 27 reg [15:0] rgb_b_m0, rgb_b_m1, rgb_b_m2; 28 reg [15:0] img_y0 ; 29 reg [15:0] img_cb0; 30 reg [15:0] img_cr0; 31 reg [ 7:0] img_y1 ; 32 reg [ 7:0] img_cb1; 33 reg [ 7:0] img_cr1; 34 reg [ 2:0] pre_frame_vsync_d; 35 reg [ 2:0] pre_frame_hsync_d; 36 reg [ 2:0] pre_frame_de_d ; 37 38 //wire define 39 wire [ 7:0] rgb888_r; 40 wire [ 7:0] rgb888_g; 41 wire [ 7:0] rgb888_b; 42 43 //***************************************************** 44 //** main code 45 //***************************************************** 46 47 //RGB565 to RGB 888 48 assign rgb888_r = {img_red , img_red[4:2] }; 49 assign rgb888_g = {img_green, img_green[5:4]}; 50 assign rgb888_b = {img_blue , img_blue[4:2] }; 51 //同步输出数据接口信号 52 assign post_frame_vsync = pre_frame_vsync_d[2] ; 53 assign post_frame_hsync = pre_frame_hsync_d[2] ; 54 assign post_frame_de = pre_frame_de_d[2] ; 55 assign img_y = post_frame_hsync ? img_y1 : 8'd0; 56 assign img_cb = post_frame_hsync ? img_cb1: 8'd0; 57 assign img_cr = post_frame_hsync ? img_cr1: 8'd0; 58 59 //-------------------------------------------- 60 //RGB 888 to YCbCr 61 62 /******************************************************** 63 RGB888 to YCbCr 64 Y = 0.299R +0.587G + 0.114B 65 Cb = 0.568(B-Y) + 128 = -0.172R-0.339G + 0.511B + 128 66 CR = 0.713(R-Y) + 128 = 0.511R-0.428G -0.083B + 128 67 68 Y = (77 *R + 150*G + 29 *B)>>8 69 Cb = (-43*R - 85 *G + 128*B)>>8 + 128 70 Cr = (128*R - 107*G - 21 *B)>>8 + 128 71 72 Y = (77 *R + 150*G + 29 *B )>>8 73 Cb = (-43*R - 85 *G + 128*B + 32768)>>8 74 Cr = (128*R - 107*G - 21 *B + 32768)>>8 75 *********************************************************/ 76 77 //step1 计算括号内的各乘法项 78 always @(posedge clk or negedge rst_n) begin 79 if(!rst_n) begin 80 rgb_r_m0 <= 16'd0; 81 rgb_r_m1 <= 16'd0; 82 rgb_r_m2 <= 16'd0; 83 rgb_g_m0 <= 16'd0; 84 rgb_g_m1 <= 16'd0; 85 rgb_g_m2 <= 16'd0; 86 rgb_b_m0 <= 16'd0; 87 rgb_b_m1 <= 16'd0; 88 rgb_b_m2 <= 16'd0; 89 end 90 else begin 91 rgb_r_m0 <= rgb888_r * 8'd77 ; 92 rgb_r_m1 <= rgb888_r * 8'd43 ; 93 rgb_r_m2 <= rgb888_r * 8'd128; 94 rgb_g_m0 <= rgb888_g * 8'd150; 95 rgb_g_m1 <= rgb888_g * 8'd85 ; 96 rgb_g_m2 <= rgb888_g * 8'd107; 97 rgb_b_m0 <= rgb888_b * 8'd29 ; 98 rgb_b_m1 <= rgb888_b * 8'd128; 99 rgb_b_m2 <= rgb888_b * 8'd21 ; 100 end 101 end 102 103 //step2 括号内各项相加 104 always @(posedge clk or negedge rst_n) begin 105 if(!rst_n) begin 106 img_y0 <= 16'd0; 107 img_cb0 <= 16'd0; 108 img_cr0 <= 16'd0; 109 end 110 else begin 111 img_y0 <= rgb_r_m0 + rgb_g_m0 + rgb_b_m0; 112 img_cb0 <= rgb_b_m1 - rgb_r_m1 - rgb_g_m1 + 16'd32768; 113 img_cr0 <= rgb_r_m2 - rgb_g_m2 - rgb_b_m2 + 16'd32768; 114 end 115 116 end 117 118 //step3 括号内计算的数据右移8位 119 always @(posedge clk or negedge rst_n) begin 120 if(!rst_n) begin 121 img_y1 <= 8'd0; 122 img_cb1 <= 8'd0; 123 img_cr1 <= 8'd0; 124 end 125 else begin 126 img_y1 <= img_y0 [15:8]; 127 img_cb1 <= img_cb0[15:8]; 128 img_cr1 <= img_cr0[15:8]; 129 end 130 end 131 132 //延时3拍以同步数据信号 133 always@(posedge clk or negedge rst_n) begin 134 if(!rst_n) begin 135 pre_frame_vsync_d <= 3'd0; 136 pre_frame_hsync_d <= 3'd0; 137 pre_frame_de_d <= 3'd0; 138 end 139 else begin 140 pre_frame_vsync_d <= {pre_frame_vsync_d[1:0], pre_frame_vsync}; 141 pre_frame_hsync_d <= {pre_frame_hsync_d[1:0], pre_frame_hsync}; 142 pre_frame_de_d <= {pre_frame_de_d[1:0] , pre_frame_de }; 143 end 144 end 145 146 endmodule 在RGB转成YUV格式的算法换算过程中数据都是以8位的数据进行的,因而我们需要将 RGB565格式的数据转换成RGB888的格式,如代码第47之50行所示,此处采用的是高位补充地位 的方法。转换后就是进行RGB565转YCbCr算法的HDL实现:第一步,先计算出前面公式中括号里 每一个乘法的乘积,如代码第77至101行所示;第二步,计算出Y、Cb、Cr括号内的值,代码103 至116行;第三步,右移 8Bit,由于 Step2 计算结果为 16Bit, 因此直接提取高8位 即可, 代码如118至130行所示。 实际上从第一步到第三步的运算, 均直接通过寄存器描述,没有顾虑行场有效时序等。 但在实际电路中会有一个数据流上的先后顺序,这三步操作同时对连续数据进行处理,通过这 种方式实现硬件加速的方法称为流水线设计。前面计算出 Y、 Cb、 Cr 我们消耗了step1、 step2、step3这三个时钟, 因此需要将输入的行场信号、使能信号同步移动 3 个时钟,如代 码第132值144行。 在代码第21至22行可以看出,转换后输出的数据分别为8位的Y(灰度)、Cb(蓝色色度分 量)、Cr(红色色度分量),而我们实验中需要的是表示灰度的数据,因此我们只需取Y值的 高5位、高6位、高5位数据作为VGA显示的红、绿、蓝三通道输入数据,如顶层代码第171行所 示: 170 .wr_en (wr_en), //写端口FIFO: 写使能 171 .wr_data ({img_y[7:3],img_y[7:2],img_y[7:3]}), //写端口FIFO: 写数据 172 .wr_min_addr (24'd0), //写SDRAM的起始地址 下载验证 首 先 我 们 打 开 OV5640 摄 像 头 VGA 显 示 实 验 工 程 , 在 工 程 所 在 的 路 径 下 打 开 ov5640_rgb565_yuv_vga/par文件夹,在里面找“ov5640_rgb565_yuv_vga.qpf”并双击打开。 注意工程所在的路径名只能由字母、数字以及下划线组成,不能出现中文、空格以及特殊字符 等。工程打开后如下图所示: 图 53.5.1 OV5640摄像头VGA显示实验工程 然后将OV5640摄像头插入开发板上的摄像头扩展接口(注意摄像头镜头朝外),将VGA连 接线一端连接显示器,另一端与开发板上的VGA接口连接。再将下载器一端连电脑,另一端与 开发板上对应端口连接,最后连接电源线并打开电源开关。 开拓者开发板实物图如下所示: 图 53.5.2 ov5640摄像头连接图 接下来我们下载程序,验证OV5640摄像头VGA实时显示的功能。工程打开后通过点击工具 栏中的“Programmer”图标打开下载界面,通过“Add File”按钮选择ov5640_rgb565 _vga_yuv /par/output_files目录下的“ov5640_rgb565_yuv_vga.sof”文件。开发板电源打开后, 在 程序下载界面点击“Hardware Setup”,在弹出的对话框中选择当前的硬件连接为“USB Blaster[USB-0]”。然后点击“Start”将工程编译完成后得到的sof文件下载到开发板中,如 图所示: 图 53.5.3 程序下载完成界面 下载完成后观察显示器的显示图像如下所示,说明OV5640摄像头VGA显示程序下载验证成 功。 图 53.5.4 VGA实时显示图像 |
|
相关推荐
|
|
1367 浏览 1 评论
助力AIoT应用:在米尔FPGA开发板上实现Tiny YOLO V4
1046 浏览 0 评论
2442 浏览 1 评论
2146 浏览 0 评论
矩阵4x4个按键,如何把识别结果按编号01-16(十进制)显示在两个七段数码管上?
2408 浏览 0 评论
1889 浏览 50 评论
6018 浏览 113 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 16:04 , Processed in 5.225964 second(s), Total 61, Slave 44 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号