03
色彩空间转换实现
3.1 RGB与YCbCr转换Verilog代码
本节分析基于FPGA实现色彩空间转换方法,在Vivado和Matlab联合仿真的基础上,对Verilog转换实现结果在Matlab中展示,验证代码的可行性。
3.1.1 预处理操作
分析RGB转为YCbCr的原理中存在小数乘法与加法运算,FPGA不擅长小数处理,因此采用扩大2^n倍后向右移n位进行实现,具体实现方法如下:
RGB转YCbCr算法:
Y = 0.257*R + 0.504*G + 0.098*B + 16
Cb = – 0.148*R – 0.291*G + 0.439*B + 128
Cr = 0.439*R – 0.368*G – 0.071*B + 128
将方程扩大256倍后右移8位,算法依然等价:
Y = 256*(0.257*R + 0.504*G + 0.098*B + 16)>>8
Cb = 256*(- 0.148*R – 0.291*G + 0.439*B + 128)>>8
Cr = 256*(0.439*R – 0.368*G – 0.071*B + 128)>>8
算法推导得:
Y = (66*R + 129*G + 25*B + 4096)>>8
Cb = (- 38*R – 74*G + 112*B + 32768)>>8
Cr = (112*R – 94*G – 18*B + 32768)>>8
算法转化为FPGA擅长的乘法与移位运算。
3.1.2 Verilog代码
基于Matlab与Verilog联合仿真工程,添加格式转换模块cx_RGB_YCbCr构建顶层top模块,对top进行仿真。

各模块代码如下:
1. 顶层模块 cx_top.v:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Cascatrix
// Engineer: Carson
//
// Create Date: 2023/02/12
// Design Name: Image_Color_Space
// Module Name: cx_top
// Tool Versions: v1.0
// Description: Covert RGB into YUV(YCbCr) and generate gray value
//
//////////////////////////////////////////////////////////////////////////////////
module cx_top(
input wire clk,
input wire rst_n,
output wireen,
outputwirehsyn,
output wirevsyn,
output wire [23:0]ycbcr_data
);
wire [23:0] data;
cx_image inst_cx_image(
.clk(clk),
.hsyn(hsyn),
.vsyn(vsyn),
.en (en ),
.data(data)
);
cx_RGB_YCbCr inst_cx_RGB_YCbCr
(
.clk(clk),
.rst_n (rst_n ),
.rgb_data(data),
.ycbcr_data(ycbcr_data)
);
endmodule
2. 图像文件读取模块 cx_image.v:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Cascatrix
// Engineer: Carson
//
// Create Date: 2023/02/12
// Design Name: Image_Color_Space
// Module Name: cx_image
// Tool Versions: v1.0
// Description: Covert RGB into YUV(YCbCr) and generate gray value
//
//////////////////////////////////////////////////////////////////////////////////
`define PIXEL_1920_1080
//`define PIXEL_1680_1050
//`define PIXEL_1280_1024
//`define PIXEL_1280_720
//`define PIXEL_1024_768
//`define PIXEL_800_600
//`define PIXEL_640_480
module cx_image(
inputwireclk,
outputreghsyn,
outputregvsyn,
outputwireen,
outputreg [23:0]data
);
//1920×1080 148.5Mhz
`ifdef PIXEL_1920_1080
parameter H_ACTIVE = 1920;// 行数据有效时间
parameter H_FRONT_PORCH = 88; // 行消隐前肩时间
parameter H_SYNC_TIME = 44; // 行同步信号时间
parameter H_BACK_PORCH = 148; // 行消隐后肩时间
parameter V_ACTIVE = 1080;// 列数据有效时间
parameter V_FRONT_PORCH = 4; // 列消隐前肩时间
parameter V_SYNC_TIME = 5; // 列同步信号时间
parameter V_BACK_PORCH = 36; // 列消隐后肩时间
`endif
//1680×1050 119Mhz
`ifdef PIXEL_1680_1050
parameter H_ACTIVE = 1680;// 行数据有效时间
parameter H_FRONT_PORCH = 48; // 行消隐前肩时间
parameter H_SYNC_TIME = 32; // 行同步信号时间
parameter H_BACK_PORCH = 80; // 行消隐后肩时间
parameter V_ACTIVE = 1050;// 列数据有效时间
parameter V_FRONT_PORCH = 3; // 列消隐前肩时间
parameter V_SYNC_TIME = 6; // 列同步信号时间
parameter V_BACK_PORCH = 21; // 列消隐后肩时间
`endif
//1280×1024 108Mhz
`ifdef PIXEL_1280_1024
parameter H_ACTIVE = 1280;// 行数据有效时间
parameter H_FRONT_PORCH = 48; // 行消隐前肩时间
parameter H_SYNC_TIME = 112; // 行同步信号时间
parameter H_BACK_PORCH = 248; // 行消隐后肩时间
parameter V_ACTIVE = 1024;// 列数据有效时间
parameter V_FRONT_PORCH = 1; // 列消隐前肩时间
parameter V_SYNC_TIME = 3; // 列同步信号时间
parameter V_BACK_PORCH = 38; // 列消隐后肩时间
`endif
//1280X720 74.25MHZ
`ifdef PIXEL_1280_720
parameter H_ACTIVE = 1280;// 行数据有效时间
parameter H_FRONT_PORCH = 110; // 行消隐前肩时间
parameter H_SYNC_TIME = 40; // 行同步信号时间
parameter H_BACK_PORCH = 220; // 行消隐后肩时间
parameter V_ACTIVE = 720; // 列数据有效时间
parameter V_FRONT_PORCH = 5; // 列消隐前肩时间
parameter V_SYNC_TIME = 5; // 列同步信号时间
parameter V_BACK_PORCH = 20; // 列消隐后肩时间
`endif
//1024×768 65Mhz
`ifdef PIXEL_1024_768
parameter H_ACTIVE = 1024;// 行数据有效时间
parameter H_FRONT_PORCH = 24; // 行消隐前肩时间
parameter H_SYNC_TIME = 136; // 行同步信号时间
parameter H_BACK_PORCH = 160; // 行消隐后肩时间
parameter V_ACTIVE = 768; // 列数据有效时间
parameter V_FRONT_PORCH = 3; // 列消隐前肩时间
parameter V_SYNC_TIME = 6; // 列同步信号时间
parameter V_BACK_PORCH = 29; // 列消隐后肩时间
`endif
//800×600 40Mhz
`ifdef PIXEL_800_600
parameter H_ACTIVE = 800;// 行数据有效时间
parameter H_FRONT_PORCH = 40 ;// 行消隐前肩时间
parameter H_SYNC_TIME = 128;// 行同步信号时间
parameter H_BACK_PORCH = 88 ;// 行消隐后肩时间
parameter V_ACTIVE = 600;// 列数据有效时间
parameter V_FRONT_PORCH = 1 ;// 列消隐前肩时间
parameter V_SYNC_TIME = 4 ;// 列同步信号时间
parameter V_BACK_PORCH = 23 ;// 列消隐后肩时间
`endif
//640×480 25.175Mhz
`ifdef PIXEL_640_480
parameter H_ACTIVE = 640; // 行数据有效时间
parameter H_FRONT_PORCH = 16 ; // 行消隐前肩时间
parameter H_SYNC_TIME = 96 ; // 行同步信号时间
parameter H_BACK_PORCH = 48 ; // 行消隐后肩时间
parameter V_ACTIVE = 480; // 列数据有效时间
parameter V_FRONT_PORCH = 10 ; // 列消隐前肩时间
parameter V_SYNC_TIME = 2 ; // 列同步信号时间
parameter V_BACK_PORCH = 33 ; // 列消隐后肩时间
`endif
parameter H_TOTAL_TIME = H_ACTIVE + H_FRONT_PORCH + H_SYNC_TIME + H_BACK_PORCH;
parameter V_TOTAL_TIME = V_ACTIVE + V_FRONT_PORCH + V_SYNC_TIME + V_BACK_PORCH;
reg h_act = d0;
reg v_act = d0;
reg [12:0] h_syn_cnt = d0;
reg [12:0] v_syn_cnt = d0;
reg [23:0] dout = d0;
reg [23:0] image [0 : H_ACTIVE*V_ACTIVE-1];
reg [31:0] image_cnt = d0;
assign en = h_act & v_act;
//读取txt文件到image数组中
initial begin
$readmemh(“D:/FPGA_Document/CX_Document/CX_Image /02_Image_color_space/image_src/image_in.txt”, image);
end
// 行扫描计数器
always@(posedge clk)
begin
if(h_syn_cnt == H_TOTAL_TIME-1)
h_syn_cnt <= 13b0;
else
h_syn_cnt <= h_syn_cnt + 1b1;
end
// 列扫描计数器
always@(posedge clk)
begin
if(h_syn_cnt == H_TOTAL_TIME-1)
begin
if(v_syn_cnt == V_TOTAL_TIME-1)
v_syn_cnt <= 13b0;
else
v_syn_cnt <= v_syn_cnt + 1b1;
end
end
// 行同步控制
always@(posedge clk)
begin
if(h_syn_cnt < H_SYNC_TIME)
hsyn <= 1b0;
else
hsyn <= 1b1;
end
// 场同步控制
always@(posedge clk)
begin
if(v_syn_cnt < V_SYNC_TIME)
vsyn <= 1b0;
else
vsyn <= 1b1;
end
always@(posedge clk)
begin
if(v_syn_cnt == V_SYNC_TIME + V_BACK_PORCH – 1 && h_syn_cnt == 0)
v_act = 1b1;
else if(v_syn_cnt == V_SYNC_TIME + V_BACK_PORCH + V_ACTIVE – 1 && h_syn_cnt == 0)
v_act = 1b0;
end
always@(posedge clk)
begin
if(h_syn_cnt == H_SYNC_TIME + H_BACK_PORCH – 1)
h_act = 1b1;
else if(h_syn_cnt == H_SYNC_TIME + H_BACK_PORCH + H_ACTIVE – 1)
h_act = 1b0;
end
always@(posedge clk)
begin
if(h_act & v_act)
image_cnt <= image_cnt + 1b1;
else if(image_cnt == H_ACTIVE*V_ACTIVE – 1)
image_cnt <= 32b0;
end
always@(posedge clk)
begin
if(h_act & v_act)
data <= image[image_cnt][23:0];
else
data <= 24b0;
end
endmodule
3. RGB转YCbCr模块 cx_RGB_YCbCr:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Cascatrix
// Engineer: Carson
//
// Create Date: 2023/02/12
// Design Name: Image_Color_Space
// Module Name: cx_RGB_YCbCr
// Tool Versions: v1.0
// Description: Covert RGB into YUV(YCbCr) and generate gray value
//
//////////////////////////////////////////////////////////////////////////////////
module cx_RGB_YCbCr(
input wireclk,
input wirerst_n,
inputwire [23:0]rgb_data,
output wire [23:0]ycbcr_data
);
reg [7:0] r;
reg [7:0] g;
reg [7:0] b;
reg [15:0] y;
reg [15:0] cb;
reg [15:0] cr;
always@(*)
begin
r <= rgb_data[7:0];
g <= rgb_data[15:8];
b <= rgb_data[23:16];
end
always@(*)
begin
if(!rst_n)
begin
y <= 16d0;
cb <= 16d0;
cr <= 16d0;
end
else
begin
y <= 66 * r + 129 * g + 25 * b + 4096 ;
cb <= – 38 * r – 74 * g + 112 * b + 32768;
cr <= 112 * r – 94 * g – 18 * b + 32768;
end
end
assign ycbcr_data = {y[15:8], cb[15:8], cr[15:8]};
endmodule
4. 仿真模块 sim_tb.v:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Cascatrix
// Engineer: Carson
//
// Create Date: 2023/02/12
// Design Name: Image_Color_Space
// Module Name: top
// Tool Versions: v1.0
// Description: Image output simulation
//
//////////////////////////////////////////////////////////////////////////////////
module sim_tb(
);
reg clk;
reg rst_n;
reg [31:0] pixel_cnt;
wire de;
wire [23:0] data;
integer image_txt;
parameter PIXEL_TOTAL = 1920*1080;
//parameter PIXEL_TOTAL = 1680*1050;
//parameter PIXEL_TOTAL = 1280*1024;
//parameter PIXEL_TOTAL = 1280*720;
//parameter PIXEL_TOTAL = 1024*768;
//parameter PIXEL_TOTAL = 800*600;
//parameter PIXEL_TOTAL = 640*480;
cx_top inst_cx_top
(
.clk (clk ),
.en (de ),
.hsyn ( ),
.vsyn ( ),
.ycbcr_data (data )
);
always #1 clk = ~clk;
initial
begin
clk = 1;
rst_n = 0;
#100
rst_n = 1;
end
initial
begin
image_txt = $fopen(“D:/FPGA_Document/ CX_Document/ CX_Image/02_Image_color_space/image_src/image_out.txt”);
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
pixel_cnt <= 0;
end
else if(de)
begin
pixel_cnt = pixel_cnt + 1;
$fwrite(image_txt,”%h “,data);
end
end
always@(posedge clk)
begin
if(pixel_cnt == PIXEL_TOTAL)
begin
$display(“CX: image_out.txt is output completed successfully! %t”, $realtime, “ps”);
$fclose(image_txt);
$stop;
end
end
endmodule
免责声明:文章内容来自互联网,本站不对其真实性负责,也不承担任何法律责任,如有侵权等情况,请与本站联系删除。
转载请注明出处:FPGA数字图像处理基础:色彩空间转换(Verilog)-fpga颜色识别 https://www.yhzz.com.cn/a/4507.html