之前转了一篇定点运算的文章希望大家看完再看这个,
涉及到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;
wire sign_cr;
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;
reg i_h_sync_delay_4=0;
reg i_v_sync_delay_4=0;
reg i_data_en_delay_4=0;
/*----------------一级流水-乘法--------------*/
always@(posedge clk)begin
mult_r_for_y_18b <=para_0299_10b*i_r_8b;
mult_r_for_u_18b<=para_0148_10b*i_r_8b;
mult_r_for_v_18b<=para_0615_10b*i_r_8b;
end
always@(posedge clk)begin
mult_g_for_y_18b <=para_0587_10b*i_g_8b;
mult_g_for_u_18b<=para_0289_10b*i_g_8b;
mult_g_for_v_18b<=para_0515_10b*i_g_8b;
end
always@(posedge clk)begin
mult_b_for_y_18b <=para_0114_10b*i_b_8b;
mult_b_for_u_18b<=para_0437_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;
/***************************************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;
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
//--------------------------------------
assign o_h_sync = i_h_sync_delay_4;
assign o_v_sync = i_v_sync_delay_4;
assign o_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;
第四级流水线计算进位
仿真通过
*/
`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;
reg i_h_sync_delay_4;
reg i_v_sync_delay_4;
reg i_data_en_delay_4;
/********************************************************************************************/
/***************************************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;
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
//--------------------------------------
assign o_h_sync = i_h_sync_delay_4;
assign o_v_sync = i_v_sync_delay_4;
assign o_data_en = i_data_en_delay_4;
/********************************************************************************************/
endmodule