FPGA-图像处理-色彩空间转换(RGB转YUV和YCBCR)

之前转了一篇定点运算的文章希望大家看完再看这个,

涉及到FPGA的色彩空间转换的知识,一定要提定点运算,其实之前在进行小数运算的时候已经用到了,这里我也不详细说了看文章吧

OV7670摄像头采集的数据格式是RGB565,转换色彩空间计算公式是rgb888的

24位888——>16位565(取高位)

{R7 R6 R5 R4 R3 R2 R1 R0}{G7 G6 G5 G4 G3 G2 G1 G0}{B7 B6 B5 B4 B3 B2 B1 B0}转

{R7 R6 R5 R4 R3}{G7 G6 G5 G4 G3 G2}{B7 B6 B5 B4 B3}

16位565——>24位888(补位)

转换回去

{R4 R3 R2 R1 R0}{G5 G4 G3 G2 G1 G0}{B4 B3 B2 B1 B0}转

{R4 R3 R2 R1 R0 R2 R1 R0}{G5 G4 G3 G2 G1 G0 G1 G0}{B4 B3 B2 B1 B0 B2 B1 B0}

下面给出色彩空间的转换的代码(YUV和YCBCR):

/* 
    RGB转YUV算法
	计算公式:	Y  =  0.299R + 0.587G + 0.114B;
				U = -0.148R - 0.289G + 0.437B; 
				V =  0.615R - 0.515G - 0.100B;
	输入到输出有三个clock的时延。
	第一级流水线计算所有乘法;
	第二级流水线计算所有加法,把正的和负的分开进行加法;
	第三级流水线计算最终的和,若为负数取0
*/
`timescale 1ns/1ps
module rgb2ycbcr(
	input           clk,
	input     [7:0] i_r_8b,
	input     [7:0] i_g_8b,
	input     [7:0] i_b_8b,
	
	input           i_h_sync,
	input           i_v_sync,
	input           i_data_en,
	
	output     [7:0] o_y_8b,
	output     [7:0] o_u_8b,
	output     [7:0] o_v_8b,
	
	output			o_h_sync,
	output			o_v_sync,                                                                                                  
	output			o_data_en 
);

	/*--------------参数列表--------------------*/
	//multiply 256
	parameter   para_0299_10b =10'd77;
	parameter   para_0587_10b =10'd150;
	parameter   para_0114_10b =10'd29;
	parameter   para_0148_10b =10'd38;
	parameter   para_0289_10b =10'd74;
	parameter   para_0437_10b =10'd112;
	parameter   para_0615_10b =10'd158;
	parameter   para_0515_10b =10'd132;
	parameter   para_0100_10b =	10'd26;
	/*---------------------------------------------*/
	wire sign_cb=0;
	wire sign_cr=0;
	reg[17: 0]	mult_r_for_y_18b=0;
	reg[17: 0]	mult_r_for_u_18b=0;
	reg[17: 0]	mult_r_for_v_18b=0;

	reg[17: 0]	mult_g_for_y_18b=0;
	reg[17: 0]	mult_g_for_u_18b=0;
	reg[17: 0]	mult_g_for_v_18b=0;

	reg[17: 0]	mult_b_for_y_18b=0;
	reg[17: 0]	mult_b_for_u_18b=0;
	reg[17: 0]	mult_b_for_v_18b=0;

	reg[17: 0]	add_y_0_18b=0;
	reg[17: 0]	add_u_0_18b=0;
	reg[17: 0]	add_v_0_18b=0;

	reg[17: 0]	add_y_1_18b=0;
	reg[17: 0]	add_u_1_18b=0;
	reg[17: 0]	add_v_1_18b=0;

	reg[17: 0] 	result_y_18b=0;
	reg[17: 0]	result_u_18b=0;
	reg[17: 0]	result_v_18b=0;

	reg[9:0] y_tmp=0;
	reg[9:0] u_tmp=0;
	reg[9:0] v_tmp=0;

	reg	i_h_sync_delay_1=0;
	reg	i_v_sync_delay_1=0;
	reg	i_data_en_delay_1=0;

	reg	i_h_sync_delay_2=0;
	reg	i_v_sync_delay_2=0;
	reg	i_data_en_delay_2=0;

	reg	i_h_sync_delay_3=0;
	reg	i_v_sync_delay_3=0;
	reg	i_data_en_delay_3=0;
	/*----------------一级流水-乘法--------------*/	
	always@(posedge clk)begin
		mult_r_for_y_18b <=para_0299_10b*i_r_8b;
		mult_r_for_u_18b<=para_0587_10b*i_r_8b;
		mult_r_for_v_18b<=para_0114_10b*i_r_8b;
	end
	
	always@(posedge clk)begin
		mult_g_for_y_18b <=para_0148_10b*i_g_8b;
		mult_g_for_u_18b<=para_0289_10b*i_g_8b;
		mult_g_for_v_18b<=para_0437_10b*i_g_8b;
	end
	
	always@(posedge clk)begin
		mult_b_for_y_18b <=para_0615_10b*i_b_8b;
		mult_b_for_u_18b<=para_0515_10b*i_b_8b;
		mult_b_for_v_18b<=para_0100_10b*i_b_8b;
	end
	/*---------------二级流水-分正负项加--------------*/
	always@(posedge clk)begin
		add_y_0_18b<= mult_r_for_y_18b + mult_g_for_y_18b;
		add_y_1_18b <= mult_b_for_y_18b;
	end
	always@(posedge clk)begin
		add_u_0_18b <= mult_b_for_u_18b ;//+
		add_u_1_18b <= mult_r_for_u_18b + mult_g_for_u_18b;//-
	end
	always@(posedge clk)begin
		add_v_0_18b <= mult_r_for_v_18b;//+
		add_v_1_18b <= mult_g_for_v_18b + mult_b_for_v_18b;//-
	end
	/*---------------三级流水-求和--y + cb + cr----------*/
	assign	sign_cb = (add_u_0_18b >= add_u_1_18b);
	assign	sign_cr = (add_v_0_18b >= add_v_1_18b);
	/*---计算求和----*/
	always@(posedge clk)begin
		result_y_18b <= add_y_0_18b + add_y_1_18b;
		result_u_18b <= sign_cb ? (add_u_0_18b - add_u_1_18b) : 18'd0;
		result_v_18b <= sign_cr ? (add_v_0_18b - add_v_1_18b) : 18'd0;
	end
	/*----进位表示---*/
	always@(posedge clk)
	begin
		y_tmp <= result_y_18b[17:8] + {9'd0,result_y_18b[7]};
		u_tmp <= result_u_18b[17:8] + {9'd0,result_u_18b[7]};
		v_tmp <= result_v_18b[17:8] + {9'd0,result_v_18b[7]};
	end
	/*----输出----*/
	assign	o_y_8b 	= (y_tmp[9:8] == 2'b00) ? y_tmp[7 : 0] : 8'hFF;
	assign	o_u_8b 	= (u_tmp[9:8] == 2'b00) ? u_tmp[7 : 0] : 8'hFF;
	assign	o_v_8b 	= (v_tmp[9:8] == 2'b00) ? v_tmp[7 : 0] : 8'hFF;
	
	assign	o_h_sync = i_h_sync_delay_3;
	assign	o_v_sync = i_v_sync_delay_3;
	assign 	o_data_en = i_data_en_delay_3;
	
endmodule

这里给出了三级流水线的操作,当然你也可以,直接进行一个式子的运算,这样的坏处是,在该段的延时较高,导致数据传输的时候的数据的锁存的时间可能会有变化,运算的效率不高。

//输出  解释:

判断条件:(y_tmp[9:8] == 2'b00)的解释

这里是把我们自己规定的两个正负值进行相加后,在最后一位进行想向上取整的运算,在最高位显示其进位的状态,所以是用两位进行判断。

下面是ycbcr转换


/* 
    RGB转YCBCR算法
	计算公式:	Y  =  0.183R + 0.614G + 0.062B + 16;
				CB = -0.101R - 0.338G + 0.439B + 128; 
				CR =  0.439R - 0.399G - 0.040B + 128;
	其中,时序在计算过程中完全没有用到
	输入到输出有三个clock的时延。
	第一级流水线计算所有乘法;
	第二级流水线计算所有加法,把正的和负的分开进行加法;
	第三级流水线计算最终的和,若为负数取0;
	仿真通过
*/
`timescale 1ns/1ps
module	rgb_to_ycbcr(
						input							clk,
						input				[7 : 0]		i_r_8b,
						input				[7 : 0]		i_g_8b,
						input				[7 : 0]		i_b_8b,
  						
						input						    i_h_sync,
						input						    i_v_sync,
						input						    i_data_en,
						
						output			[7 : 0]		o_y_8b,
						output			[7 : 0]		o_cb_8b,
						output			[7 : 0]		o_cr_8b,
						
						output							o_h_sync,
						output							o_v_sync,                                                                                                  
						output						   o_data_en                                                                                                
						);

	/***************************************parameters*******************************************/
	//multiply 256
	parameter	para_0183_10b = 10'd47;    //0.183 定点数
	parameter	para_0614_10b = 10'd157;
	parameter	para_0062_10b = 10'd16;
	parameter	para_0101_10b = 10'd26;
	parameter	para_0338_10b = 10'd86;
	parameter	para_0439_10b = 10'd112;
	parameter	para_0399_10b = 10'd102;
	parameter	para_0040_10b = 10'd10;
	parameter	para_16_18b = 18'd4096;
	parameter	para_128_18b = 18'd32768;
	/********************************************************************************************/

	/***************************************signals**********************************************/
	wire				sign_cb;
	wire				sign_cr;
	reg[17: 0]	mult_r_for_y_18b;
	reg[17: 0]	mult_r_for_cb_18b;
	reg[17: 0]	mult_r_for_cr_18b;

	reg[17: 0]	mult_g_for_y_18b;
	reg[17: 0]	mult_g_for_cb_18b;
	reg[17: 0]	mult_g_for_cr_18b;

	reg[17: 0]	mult_b_for_y_18b;
	reg[17: 0]	mult_b_for_cb_18b;
	reg[17: 0]	mult_b_for_cr_18b;

	reg[17: 0]	add_y_0_18b;
	reg[17: 0]	add_cb_0_18b;
	reg[17: 0]	add_cr_0_18b;

	reg[17: 0]	add_y_1_18b;
	reg[17: 0]	add_cb_1_18b;
	reg[17: 0]	add_cr_1_18b;

	reg[17: 0] 	result_y_18b;
	reg[17: 0]	result_cb_18b;
	reg[17: 0]	result_cr_18b;

	reg[9:0] y_tmp;
	reg[9:0] cb_tmp;
	reg[9:0] cr_tmp;

	reg					i_h_sync_delay_1;
	reg					i_v_sync_delay_1;
	reg					i_data_en_delay_1;

	reg					i_h_sync_delay_2;
	reg					i_v_sync_delay_2;
	reg					i_data_en_delay_2;

	reg					i_h_sync_delay_3;
	reg					i_v_sync_delay_3;
	reg					i_data_en_delay_3;
	/********************************************************************************************/

	/***************************************initial**********************************************/
	initial
	begin
		mult_r_for_y_18b <= 18'd0;
		mult_r_for_cb_18b <= 18'd0;
		mult_r_for_cr_18b <= 18'd0;
		
		mult_g_for_y_18b <= 18'd0;
		mult_g_for_cb_18b <= 18'd0;
		mult_g_for_cr_18b <= 18'd0;
		
		mult_b_for_y_18b <= 18'd0;
		mult_g_for_cb_18b <= 18'd0;
		mult_b_for_cr_18b <= 18'd0;

		
		add_y_0_18b <= 18'd0;
		add_cb_0_18b <= 18'd0;
		add_cr_0_18b <= 18'd0;
		
		add_y_1_18b <= 18'd0;
		add_cb_1_18b <= 18'd0;
		add_cr_1_18b <= 18'd0;
		
		result_y_18b <= 18'd0;
		result_cb_18b <= 18'd0;
		result_cr_18b <= 18'd0;
		
		i_h_sync_delay_1 <= 1'd0;
		i_v_sync_delay_1 <= 1'd0;
		i_data_en_delay_1 <= 1'd0;
		
		i_h_sync_delay_2 <= 1'd0;
		i_v_sync_delay_2 <= 1'd0;
		i_data_en_delay_2 <= 1'd0;
												
	end 
	/********************************************************************************************/
		
	/***************************************arithmetic*******************************************/
	//LV1 pipeline : mult
	always @ (posedge	clk)
	begin
		mult_r_for_y_18b <= i_r_8b * para_0183_10b;
		mult_r_for_cb_18b <= i_r_8b * para_0101_10b;
		mult_r_for_cr_18b <= i_r_8b * para_0439_10b;
	end

	always @ (posedge	clk)
	begin
		mult_g_for_y_18b <= i_g_8b * para_0614_10b;
		mult_g_for_cb_18b <= i_g_8b * para_0338_10b;
		mult_g_for_cr_18b <= i_g_8b * para_0399_10b;
	end

	always @ (posedge	clk)
	begin
		mult_b_for_y_18b <= i_b_8b * para_0062_10b;
		mult_b_for_cb_18b <= i_b_8b * para_0439_10b;
		mult_b_for_cr_18b <= i_b_8b * para_0040_10b;
	end
	//LV2 pipeline : add
	always @ (posedge	clk)
	begin
		add_y_0_18b <= mult_r_for_y_18b + mult_g_for_y_18b;
		add_y_1_18b <= mult_b_for_y_18b + para_16_18b;
		
		add_cb_0_18b <= mult_b_for_cb_18b + para_128_18b;
		add_cb_1_18b <= mult_r_for_cb_18b + mult_g_for_cb_18b;
		
		add_cr_0_18b <= mult_r_for_cr_18b + para_128_18b;
		add_cr_1_18b <= mult_g_for_cr_18b + mult_b_for_cr_18b;
	end
	//LV3 pipeline : y + cb + cr

	assign	sign_cb = (add_cb_0_18b >= add_cb_1_18b);
	assign	sign_cr = (add_cr_0_18b >= add_cr_1_18b);
	always @ (posedge	clk)
	begin
		result_y_18b <= add_y_0_18b + add_y_1_18b;
		result_cb_18b <= sign_cb ? (add_cb_0_18b - add_cb_1_18b) : 18'd0;
		result_cr_18b <= sign_cr ? (add_cr_0_18b - add_cr_1_18b) : 18'd0;
	end

	always @ (posedge	clk)
	begin
		y_tmp <= result_y_18b[17:8] + {9'd0,result_y_18b[7]};
		cb_tmp <= result_cb_18b[17:8] + {9'd0,result_cb_18b[7]};
		cr_tmp <= result_cr_18b[17:8] + {9'd0,result_cr_18b[7]};
	end

	//output
	assign	o_y_8b 	= (y_tmp[9:8] == 2'b00) ? y_tmp[7 : 0] : 8'hFF;
	assign	o_cb_8b 	= (cb_tmp[9:8] == 2'b00) ? cb_tmp[7 : 0] : 8'hFF;
	assign	o_cr_8b 	= (cr_tmp[9:8] == 2'b00) ? cr_tmp[7 : 0] : 8'hFF;
	/********************************************************************************************/

	/***************************************timing***********************************************/
	always @ (posedge	clk)
	begin
		i_h_sync_delay_1 <= i_h_sync;
		i_v_sync_delay_1 <= i_v_sync;
		i_data_en_delay_1 <= i_data_en;
		
		i_h_sync_delay_2 <= i_h_sync_delay_1;
		i_v_sync_delay_2 <= i_v_sync_delay_1;
		i_data_en_delay_2 <= i_data_en_delay_1;
		
		i_h_sync_delay_3 <= i_h_sync_delay_2;
		i_v_sync_delay_3 <= i_v_sync_delay_2;
		i_data_en_delay_3 <= i_data_en_delay_2;
	end	
	//--------------------------------------
	//timing
	//--------------------------------------	
	assign	o_h_sync = i_h_sync_delay_3;
	assign	o_v_sync = i_v_sync_delay_3;
	assign 	o_data_en = i_data_en_delay_3;

	/********************************************************************************************/
	endmodule 

猜你喜欢

转载自blog.csdn.net/weixin_41445387/article/details/89379533
今日推荐