Verilog语言编写 RGB文件转YCbCr模块

YCbCr是色彩空间的一种,通常会用于影片中的影像连续处理,或是数字摄影系统中。Y(luminance)为颜色的亮度和浓度、Cb(chrominance-blue)为蓝色色度分量,Cr(chrominance-rad)则为红色色度分量。

从摄像头采集到的RGB数据转换到显示器使用的YCbCr数据,按照官方给出的计算公式

Y    =  0.299 R + 0.587 G + 0.114 B
Cb  = -0.1687 R - 0.3313 G + 0.5 B + 128
Cr   = 0.5 R - 0.4187 G - 0.0813 B + 128

我们的数据转换模块,也正是基于上述转换公式设计

考虑到使用Verilog语言无法描述浮点数运算,所以将所等式两边同时*256(即2^8)后,再统一除2^8即可得到正确的值。

     Y     =    (77 *R     +     150*G     +     29 *B)>>8
    Cb     =    (-43*R    -     85 *G    +     128*B)>>8 + 128
    Cr     =    (128*R     -    107*G      -    21 *B)>>8 + 128

将128*256后带入括号

    Y     =    (77 *R     +     150*G     +     29 *B)>>8
    Cb     =    (-43*R    -     85 *G    +     128*B + 32768)>>8
    Cr     =    (128*R     -    107*G      -    21 *B + 32768)>>8

module RGB888_To_YCbCr444
(
	//system signal
	input				clk,  				//cmos video pixel clock
	input				rst_n,				//global reset

	//Image data and control signals prepred to be processd
	input				per_frame_vsync,	
	input				per_frame_href,		
	input				per_frame_clken,	
	
    wire		[7:0]	per_img_red,		
    wire		[7:0]	per_img_green,		
    wire		[7:0]	per_img_blue,		
	
	//Image data and control signals have been processd
	output				new_frame_vsync,	
	output				new_frame_href,	
	output				new_frame_clken,	
	
    output		[7:0]	img_Y,			
	output		[7:0]	img_Cb,		
	output		[7:0]	img_Cr			
);

  

     Y     =    (77 *R     +     150*G     +     29 *B)>>8
    Cb     =    (-43*R    -     85 *G    +     128*B + 32768)>>8
    Cr     =    (128*R     -    107*G      -    21 *B + 32768)>>8

在这里我们进行一个流水线设计,将先乘再加的转换公式中乘和加的部分断开

//step 1 operate the multiplication
reg	[15:0]	img_red_r0,		img_red_r1,		img_red_r2;	
reg	[15:0]	img_green_r0,	img_green_r1,	img_green_r2; 
reg	[15:0]	img_blue_r0,	img_blue_r1,	img_blue_r2; 
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
		img_red_r0		<=	0; 		
		img_red_r1		<=	0; 		
		img_red_r2		<=	0; 	
		img_green_r0	<=	0; 		
		img_green_r1	<=	0; 		
		img_green_r2	<=	0; 	
		img_blue_r0		<=	0; 		
		img_blue_r1		<=	0; 		
		img_blue_r2		<=	0; 			
		end
	else
		begin
		img_red_r0		<=	per_img_red 	* 	8'd77; 		
		img_red_r1		<=	per_img_red 	* 	8'd43; 	
		img_red_r2		<=	per_img_red 	* 	8'd128; 		
		img_green_r0	<=	per_img_green 	* 	8'd150; 		
		img_green_r1	<=	per_img_green 	* 	8'd85; 			
		img_green_r2	<=	per_img_green 	* 	8'd107; 
		img_blue_r0		<=	per_img_blue 	* 	8'd29; 		
		img_blue_r1		<=	per_img_blue 	* 	8'd128; 			
		img_blue_r2		<=	per_img_blue 	* 	8'd21; 		
		end
end

接下来是按照公式和对应位置将乘积对应相加

//step 2 add the product
reg	[15:0]	img_Y_r0;	
reg	[15:0]	img_Cb_r0; 
reg	[15:0]	img_Cr_r0; 
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
		img_Y_r0	<=	0; 		
		img_Cb_r0	<=	0; 		
		img_Cr_r0	<=	0; 	
		end
	else
		begin
		img_Y_r0	<=	img_red_r0 	+ 	img_green_r0 	+ 	img_blue_r0; 		
		img_Cb_r0	<=	img_blue_r1 - 	img_red_r1 		- 	img_green_r1	+	16'd32768; 		
		img_Cr_r0	<=	img_red_r2 	+ 	img_green_r2 	+ 	img_blue_r2		+	16'd32768; 		
		end
end

 最后一步只需要将计算出的数据除以256,便完成了RGB到YCbCr的转换

reg	[7:0]	img_Y_r1;	
reg	[7:0]	img_Cb_r1; 
reg	[7:0]	img_Cr_r1; 
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
		img_Y_r1	<=	0; 		
		img_Cb_r1	<=	0; 		
		img_Cr_r1	<=	0; 	
		end
	else
		begin
		img_Y_r1	<=	img_Y_r0[15:8];
		img_Cb_r1	<=	img_Cb_r0[15:8];
		img_Cr_r1	<=	img_Cr_r0[15:8]; 
		end
end

接下来就是对时序的调整了,在上面的转换过程中,我们采取了三段流水线的处理方式,所以控制信号为了保持同步要打三拍

reg	[2:0]	per_frame_vsync_r;
reg	[2:0]	per_frame_href_r;	
reg	[2:0]	per_frame_clken_r;
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
		per_frame_vsync_r <= 0;
		per_frame_href_r <= 0;
		per_frame_clken_r <= 0;
		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};
		per_frame_clken_r 	<= 	{per_frame_clken_r[1:0], 	per_frame_clken};
		end
end
assign	new_frame_vsync 	= 	per_frame_vsync_r[2];
assign	new_frame_href 	    = 	per_frame_href_r[2];
assign	new_frame_clken 	= 	per_frame_clken_r[2];

将处理好的YCrCb接到输出上

assign	img_Y 	= 	new_frame_href ? img_Y_r1 : 8'd0;
assign	img_Cb  =	new_frame_href ? img_Cb_r1: 8'd0;
assign  img_Cr  = 	new_frame_href ? img_Cr_r1: 8'd0;

到此为止,所有模块功能完成

endmodule

你可能感兴趣的:(图像处理,fpga)