之前转了一篇定点运算的文章希望大家看完再看这个,
涉及到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第四级流水线进位计算*/`timescale1ns/1psmodulergb2ycbcr( inputclk, input [7:0] i_r_8b, input [7:0] i_g_8b, input [7:0] i_b_8b, inputi_h_sync, inputi_v_sync, inputi_data_en, output [7:0] o_y_8b, output [7:0] o_u_8b, output [7:0] o_v_8b, outputo_h_sync, outputo_v_sync, outputo_data_en); /*--------------参数列表--------------------*///multiply256parameterpara_0299_10b=10'd77;parameterpara_0587_10b=10'd150;parameterpara_0114_10b=10'd29;parameterpara_0148_10b=10'd38;parameterpara_0289_10b=10'd74;parameterpara_0437_10b=10'd112;parameterpara_0615_10b=10'd158;parameterpara_0515_10b=10'd132;parameterpara_0100_10b=10'd26;/*---------------------------------------------*/wiresign_cb=0; wiresign_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; regi_h_sync_delay_1=0; regi_v_sync_delay_1=0; regi_data_en_delay_1=0; regi_h_sync_delay_2=0; regi_v_sync_delay_2=0; regi_data_en_delay_2=0; regi_h_sync_delay_3=0; regi_v_sync_delay_3=0; regi_data_en_delay_3=0; regi_h_sync_delay_4=0; regi_v_sync_delay_4=0; regi_data_en_delay_4=0; /*----------------一级流水-乘法--------------*/always@(posedgeclk)beginmult_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; endalways@(posedgeclk)beginmult_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; endalways@(posedgeclk)beginmult_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@(posedgeclk)beginadd_y_0_18b<=mult_r_for_y_18b+mult_g_for_y_18b; add_y_1_18b<=mult_b_for_y_18b; endalways@(posedgeclk)beginadd_u_0_18b<=mult_b_for_u_18b ;//+add_u_1_18b<=mult_r_for_u_18b+mult_g_for_u_18b;//-endalways@(posedgeclk)beginadd_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----------*/assignsign_cb= (add_u_0_18b>=add_u_1_18b); assignsign_cr= (add_v_0_18b>=add_v_1_18b); /*---计算求和----*/always@(posedgeclk)beginresult_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@(posedgeclk) beginy_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/*----输出----*/assigno_y_8b= (y_tmp[9:8] ==2'b00) ? y_tmp[7 : 0] : 8'hFF; assigno_u_8b= (u_tmp[9:8] ==2'b00) ? u_tmp[7 : 0] : 8'hFF; assigno_v_8b= (v_tmp[9:8] ==2'b00) ? v_tmp[7 : 0] : 8'hFF; /***************************************timing***********************************************/always@ (posedgeclk) begini_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; i_h_sync_delay_4<=i_h_sync_delay_2; i_v_sync_delay_4<=i_v_sync_delay_2; i_data_en_delay_4<=i_data_en_delay_2; end//--------------------------------------//timing//--------------------------------------assigno_h_sync=i_h_sync_delay_4; assigno_v_sync=i_v_sync_delay_4; assigno_data_en=i_data_en_delay_4; 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;第四级流水线计算进位仿真通过*/`timescale1ns/1psmodulergb_to_ycbcr( inputclk, input [7 : 0] i_r_8b, input [7 : 0] i_g_8b, input [7 : 0] i_b_8b, inputi_h_sync, inputi_v_sync, inputi_data_en, output [7 : 0] o_y_8b, output [7 : 0] o_cb_8b, output [7 : 0] o_cr_8b, outputo_h_sync, outputo_v_sync, outputo_data_en ); /***************************************parameters*******************************************///multiply256parameterpara_0183_10b=10'd47; //0.183 定点数parameterpara_0614_10b=10'd157;parameterpara_0062_10b=10'd16;parameterpara_0101_10b=10'd26;parameterpara_0338_10b=10'd86;parameterpara_0439_10b=10'd112;parameterpara_0399_10b=10'd102;parameterpara_0040_10b=10'd10;parameterpara_16_18b=18'd4096;parameterpara_128_18b=18'd32768;/********************************************************************************************//***************************************signals**********************************************/wiresign_cb; wiresign_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; regi_h_sync_delay_1; regi_v_sync_delay_1; regi_data_en_delay_1; regi_h_sync_delay_2; regi_v_sync_delay_2; regi_data_en_delay_2; regi_h_sync_delay_3; regi_v_sync_delay_3; regi_data_en_delay_3; regi_h_sync_delay_4; regi_v_sync_delay_4; regi_data_en_delay_4; /********************************************************************************************//***************************************initial**********************************************/initialbeginmult_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*******************************************///LV1pipeline : multalways@ (posedgeclk) beginmult_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; endalways@ (posedgeclk) beginmult_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; endalways@ (posedgeclk) beginmult_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//LV2pipeline : addalways@ (posedgeclk) beginadd_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//LV3pipeline : y+cb+crassignsign_cb= (add_cb_0_18b>=add_cb_1_18b); assignsign_cr= (add_cr_0_18b>=add_cr_1_18b); always@ (posedgeclk) beginresult_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;endalways@ (posedgeclk) beginy_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//outputassigno_y_8b= (y_tmp[9:8] ==2'b00) ? y_tmp[7 : 0] : 8'hFF; assigno_cb_8b= (cb_tmp[9:8] ==2'b00) ? cb_tmp[7 : 0] : 8'hFF; assigno_cr_8b= (cr_tmp[9:8] ==2'b00) ? cr_tmp[7 : 0] : 8'hFF; /********************************************************************************************//***************************************timing***********************************************/always@ (posedgeclk) begini_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; i_h_sync_delay_4<=i_h_sync_delay_2; i_v_sync_delay_4<=i_v_sync_delay_2; i_data_en_delay_4<=i_data_en_delay_2; end//--------------------------------------//timing//--------------------------------------assigno_h_sync=i_h_sync_delay_4; assigno_v_sync=i_v_sync_delay_4; assigno_data_en=i_data_en_delay_4; /********************************************************************************************/endmodule