` 一、概述 一般来说,摄像头输出的格式有RGB、YUV(Ycbcr)RAW图像格式,大部分图像算法都是基于灰度图像的,因此在输出格式为rgb时,有必要进行颜色空间转换rgbtoyuv,只提取Y分量灰度处理。 YcbCr:是经过伽马修正(gamma correction)编码处理后的YUV版本,Y'为颜色的亮度(luma)成分、而cb和Cr则为蓝色和红色的浓度偏移量成份。 RGB:是现在运用最广的颜色系统之一,通过红绿蓝三个分量的变化叠加来得到其他颜色。 BGR:把RGB的红色分量和蓝色交换即BGR YUV:是欧洲电视系统采用的一种颜色编码格式,Y表示亮度值(Luminance或Luma),U和V表示色彩及饱和度(Chrominance或Chroma)。 YUV主要格式有:YUV444、YUV 422、YUV 411和YUV420。YUV对原始数据以每4个像素为单元进行压缩处理,处理的方式就是对U和V分量进行降采样,如YUV444就是每4个像素YUV都会被采样4次数据无压缩,YUV422就是每4个像素YUV采样次数分别为422,数据减小了1/3,同理YUV411数据就减小了一半。但是根据奈奎斯特采样定理可以知道,采样后的数据信息损失量很小,不会造成图像的视觉效果变差。 假设有四个YUV空间的像素点{Y0,U0,V0},{Y1,U1,V1},{Y2,U2,V2},{Y3,U3,V3} (1)YUV444 存储格式为:{Y0,U0,V0},{Y1,U1,V1},{Y2,U2,V2},{Y3,U3,V3} 像素表示为:{Y0,U0,V0},{Y1,U1,V1},{Y2,U2,V2},{Y3,U3,V3} 没有压缩。 (2) YUV422 存储格式为:{Y0,U0},{Y1,V1},{Y2,U2},{Y3,V3} 像素表示为:{Y0,U0,V1},{Y1,U0,V1},{Y2,U2,V3}, {Y3,U2,V3} 可以看出四个像素点Y分量全部采样,U保留了偶数,V保留了奇数,四个像素点每两个像素点共用同一个U和V分量,数据压缩了1/3。 (3)YUV411 存储格式为:{Y0,U0,Y1},{Y2,V2,Y3} 像素表示为:{Y0,U0,V2},{Y1,U0,V2},{Y2,U0,V2}, {Y3,U0,V2} 可以看出四个像素点Y分量全部采样,U和V只采样了U0和V2两个值,然后四个像素点的UV分离都是U0和V2,数据压缩了1/2。 (3)YUV420 这个有点特殊,上面的几种每4个像素点中的YUV三个分量都有采样,而YUV420则是第一次四个像素点中只采样Y和U分量,第二次四个像素点总只采用Y和V分量,然后依次交替进行。 存储格式为:{Y0,U0,V0},{Y1,U1,V1},{Y2,U2,V2},{Y3,U3,V3},{Y5,U5,V5}, {Y6,U6,V6}, {Y7,U7,V7} , {Y8,U8,V8} 像素表示为:{Y0,U0,V5},{Y1,U0,V5},{Y2,U2,V7}, {Y3,U2,V7},{Y5,U0,V5}, {Y6,U0,V5},{Y7,U2,V7}, {Y8,U2,V7} 数据压缩了1/2。 RGB和YUV互相转换的公式如下;YUV(256 级别) 可以从8位 RGB 直接计算: Y= 0.299 R + 0.587 G + 0.114 B U= - 0.1687 R - 0.3313 G + 0.5 B + 128 V= 0.5 R - 0.4187 G - 0.0813 B + 128 反过来,RGB 也可以直接从YUV (256级别) 计算: R= Y + 1.402 (Cr-128) G= Y - 0.34414 (Cb-128) - 0.71414 (Cr-128) B= Y + 1.772 (Cb-128) 使用Matlab自己编写的函数rgb2gray.m如图1所示。只完成rgb2yuv的转换;MatlabRGB转换成YCbCr处理后的结果如图2所示:其中Cb表示蓝色分量;Cr表示红色分量,可以看出对于红色分量的提取YCbCr较好些。
图1 rgb2yuv matlab代码
图 2 Y Cb Cr 显示图
图3 R G B显示图 三、Verilog硬件实现 这里不直接使用公式计算,从Verlog的硬件实现的角度,改写matlab程序,从公式中可以看到;由于FPGA不善于处理浮点数;这里完成了浮点数向定点数的转换;各个系数均扩大256倍,最后在计算完之后除以256。 Y = 0.299 R + 0.587 G + 0.114 B U = - 0.1687 R - 0.3313 G + 0.5 B+ 128 (1) V = 0.5 R - 0.4187 G - 0.0813 B + 128
Y=(77*R+150*G+29*B)>>8; U=(-43R-85G+128B+128*256)>>8 (2) V=(128R-107G-21B+128*256)>>8 在Verlog里面,使用组合逻辑不能直接按上述公式(2)在计算,不然组合逻辑延时太大,导致时序不收敛,这里就需要添加寄存器来切割流水线;利用FPGA并行处理的特点加速计算。 Step1 :同时计算9个系数的乘法: reg [15:0]y_temp1,u_temp1,v_temp1; reg[15:0]y_temp2,u_temp2,v_temp2; reg[15:0]y_temp3,u_temp3,v_temp3;
wire[7:0]R; wire[7:0]G; wire[7:0]B; always@(posedge clk or negedge rst_n) if(!rst_n)begin y_temp1<=16'd0; y_temp2<=16'd0; y_temp3<=16'd0; end elsebegin y_temp1<=8'd77*R; y_temp2<=8'd150*G; y_temp3<=8'd29*B; end //---------------------------------------- always@(posedge clk or negedge rst_n) if(!rst_n)begin u_temp1<=16'd0; u_temp2<=16'd0; u_temp3<=16'd0; end elsebegin u_temp1<=8'd43*R; u_temp2<=8'd85*G; u_temp3<=8'd128*B; end //--------------------------------------- always@(posedge clk or negedge rst_n) if(!rst_n)begin v_temp1<=16'd0; v_temp2<=16'd0; v_temp3<=16'd0; end elsebegin v_temp1<=8'd128*R; v_temp2<=8'd107*G; v_temp3<=8'd21*B; end /////////////////////////////////////////// Step2 :同时计算各个加法: reg[15:0] Y_r0,U_r0,V_r0; reg[15:0] Y_r1,U_r1,V_r1; always@(posedge clk or negedge rst_n) if(!rst_n)begin Y_r0<=16'd0; U_r0<=16'd0; V_r0<=16'd0; end elsebegin Y_r0<=y_temp1+y_temp2+y_temp3; U_r0<=16'h8000-u_temp1-u_temp2+u_temp3; V_r0<=16'h8000+v_temp1-v_temp2-v_temp3; End Step3 :同时移位8bit,这里提取和的高八位;省去3个移位运算: //tep3 always@(posedge clk or negedge rst_n) if(!rst_n)begin Y_r1<=8'd0; U_r1<=8'd0; V_r1<=8'd0; end elsebegin Y_r1<=Y_r0[15:8]; U_r1<=U_r0[15:8]; V_r1<=V_r0[15:8]; end
// sync 这里采用移位的方式延时三拍,取MSB作为最终的行场信号输出 reg[2:0] per_frame_vsync_r; reg[2:0] per_frame_href_r ; always@(posedgeclk or negedge rst_n) if(!rst_n) begin per_frame_vsync_r <=3'b0; per_frame_href_r <=3'b0; end else begin per_frame_vsync_r<={per_frame_vsync_r[1:0],per_frame_vsync}; per_frame_href_r<={per_frame_href_r[1:0],per_frame_href}; 欢迎关注微信公众号FPGA自习室
`
|