计算公式
R = Y + 1.402*(V-128) = Y + 1.402*CR - 1.402*128
G = Y - 0.344*(U-128) - 0.714*(V-128) = Y - 0.344*CB -0.714*CR + 1.058*128
B = Y + 1.772*(U-128) = Y + 1.772*CB - 1.772*128
FPGA实现
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2024/08/06 20:34:03
// Design Name:
// Module Name: img_ycbcr_rgb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module img_ycbcr_rgb(
input clk ,
input rst ,
input [ 23: 0] img_data_i ,
input valid_i ,
output [ 23: 0] img_data_o ,
output valid_o
);
reg valid_d1 ;
reg valid_d2 ;
reg valid_d3 ;
wire [ 7: 0] Y,CB,CR ;
assign {Y,CB,CR} = img_data_i;
//YUV转RGB
//R = Y + 1.402*(V-128) = Y + 1.402*CR - 1.402*128
//G = Y - 0.344*(U-128) - 0.714*(V-128) = Y - 0.344*CB -0.714*CR + 1.058*128
//B = Y + 1.772*(U-128) = Y + 1.772*CB - 1.772*128
parameter C0 = 1436 ; //1.402*1024
parameter C1 = 352 ; //0.344*1024
parameter C2 = 731 ; //0.714*1024
parameter C3 = 1814 ; //1.772*1024
parameter R_BASE = 18'd183763;//1.402*128*1024
parameter G_BASE = 18'd138674;//1.058*128*1024
parameter B_BASE = 18'd232260;//1.772*128*1024
reg [ 17: 0] Y_m ;
reg [ 18: 0] R_CR_m ;
reg [ 16: 0] G_CB_m ;
reg [ 17: 0] G_CR_m ;
reg [ 18: 0] B_CB_m ;
reg [ 7: 0] R ;
reg [ 7: 0] G ;
reg [ 7: 0] B ;
//有符号数,最高位为符号位
reg [ 19: 0] R_s ;//最大值,当Y和CB都等于255时,(1024 + C0)*255 - R_BASE = 19'd443537;可能出现负数, 最小负数为 -183763
reg [ 19: 0] G_s ;//最大值,当CR和CB等于0,且Y=255时,1024*255 + G_BASE = 19'd399794;可能出现负数,最小负数为U_BASE - (C1 + C2)*255 = -137491
reg [ 19: 0] B_s ;//最大值,当Y和CR都等于255时,(1024 + C3)*255 - B_BASE = 19'd491430;可能出现负数,最小负数为 -B_BASE = - 232260
always @ (posedge clk or posedge rst)
if (rst)begin
valid_d1 <= 0;
Y_m <= 0;
R_CR_m <= 0;
G_CB_m <= 0;
G_CR_m <= 0;
B_CB_m <= 0;
end else begin
if (valid_i)begin
Y_m <= {Y,10'd0};
R_CR_m <= CR * C0;
G_CB_m <= CB * C1;
G_CR_m <= CR * C2;
B_CB_m <= CB * C3;
end
valid_d1 <= valid_i;
end
always @ (posedge clk or posedge rst)
if (rst)begin
valid_d2 <= 0;
R_s <= 0;
G_s <= 0;
B_s <= 0;
end else begin
if (valid_d1)begin
R_s <= Y_m + R_CR_m - R_BASE;
G_s <= Y_m - G_CB_m - G_CR_m + G_BASE;
B_s <= Y_m + B_CB_m - B_BASE;
end
valid_d2 <= valid_d1;
end
always @ (posedge clk or posedge rst)
if (rst)begin
valid_d3 <= 0;
R <= 0;
G <= 0;
B <= 0;
end else begin
if (valid_d2)begin
R <= R_s[19] ? 'b0 : R_s[18] ? 'd255 : R_s[17:10];
G <= G_s[19] ? 'b0 : G_s[18] ? 'd255 : G_s[17:10];
B <= B_s[19] ? 'b0 : B_s[18] ? 'd255 : B_s[17:10];
end
valid_d3 <= valid_d2;
end
assign img_data_o = {R,G,B};
assign valid_o = valid_d3;
endmodule
仿真
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2024/08/01 20:54:28
// Design Name:
// Module Name: tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
`define INPUT_FILE "../../../../test_img/in/1024x600.bmp" //input image
`define IMG_WIDTH 1024 //Image width
`define IMG_HEIGHT 600 //Image height
`define H_BLANK 400 //横向消影区,仿真可自由设定
`define V_BLANK 30 //纵向消影区,仿真可自由设定
`define OUTPUT_FILE "../../../../test_img/out/result.bmp" //result image frame1
`define LEN_HEADER 54 // 0x33
`define IMG_ALL (`IMG_HEIGHT*`IMG_WIDTH*3)
`define IMG_SIZE (`IMG_HEIGHT*`IMG_WIDTH)
`define IMG_BMP_SIZE (`IMG_ALL + `LEN_HEADER)
`define NULL 0
`define DATA_WIDTH 8
`define SEEK_SET 0
`define SEEK_CUR 1
`define SEEK_END 2
module tb;
parameter TIME = 2;
integer fdI;
integer fdO;
integer ret, i, j, idx, file_end_offset, zero_len;
reg [`DATA_WIDTH-1:0] bmp_head_r[0:`LEN_HEADER-1];//Image 1 Header
reg [`DATA_WIDTH-1:0] imgR_r[0:`IMG_SIZE-1]; //Image-- R Channel
reg [`DATA_WIDTH-1:0] imgG_r[0:`IMG_SIZE-1]; //Image-- G Channel
reg [`DATA_WIDTH-1:0] imgB_r[0:`IMG_SIZE-1]; //Image-- B Channel
wire [31:0] bmp_size, bmp_width, bmp_height;
reg init_r;
reg clk = 1'b0;
reg rst;
reg [31:0] h_cnt_r, v_cnt_r;
reg [31:0] data_cnt_r;
reg [31:0] addr_r;
wire valid_i;
wire [`DATA_WIDTH*3-1:0] img_data_i;
wire valid_o;
wire [`DATA_WIDTH*3-1:0] img_data_o;
reg [31:0] out_data_cnt_r;
reg valid_o_r;
wire [`DATA_WIDTH-1:0] R_o_w, G_o_w, B_o_w;
wire [23:0] rgb_data_ycbcr;
wire rgb_valid_ycbcr;
always
begin
#(TIME/2) clk = ~clk;
end
initial begin
rst = 1'b1;
zero_len = 'b0;
#(TIME*10);
rst = 1'b0;
wait(init_r);
$display("> Initial Done");
wait(out_data_cnt_r == (`IMG_SIZE-1));//检测一幅图像完成?
#(TIME*2);
//文件末尾补0
$fseek(fdO, 0, `SEEK_END);
zero_len = $ftell(fdO);
zero_len = 4- zero_len[1:0];
for(i=0;i < zero_len;i=i+1)
$fwrite(fdO, "%c", 0);
$fclose(fdO);
$display("> Simulate Done");
$stop;
end
///读取BMP文件
assign bmp_size = {bmp_head_r[5], bmp_head_r[4], bmp_head_r[3], bmp_head_r[2]};
assign bmp_width = {bmp_head_r[21], bmp_head_r[20], bmp_head_r[19], bmp_head_r[18]};
assign bmp_height = {bmp_head_r[25], bmp_head_r[24], bmp_head_r[23], bmp_head_r[22]};
initial begin
init_r = 1'b0;
for (i = 0; i < `IMG_SIZE; i=i+1)begin
imgB_r[i] = 0;
imgG_r[i] = 0;
imgR_r[i] = 0;
end
fdI = $fopen(`INPUT_FILE,"rb");
if (fdI == `NULL) begin
$display("> OPEN FAIL: The file not exist !!!");
end else begin
$display("> OPEN file SUCCESS !");
//读取bmp文件头
ret = $fread(bmp_head_r, fdI, 0, `LEN_HEADER);
//读取图像RGB分量值?
//BMP倒序存储数据时,从下到上,从左到右
for(i=`IMG_HEIGHT - 1;i >= 0;i=i-1)
for(j=0;j <`IMG_WIDTH;j=j+1) begin
idx = i*`IMG_WIDTH + j;
imgB_r[idx] = $fgetc(fdI);//b
imgG_r[idx] = $fgetc(fdI);//g
imgR_r[idx] = $fgetc(fdI);//r
end
$display("> Read b,g,r Successful !");
end
fdO = $fopen(`OUTPUT_FILE,"wb");
//写入文件头 ?
for(i=0;i < `LEN_HEADER;i=i+1) begin
$fwrite(fdO, "%c", bmp_head_r[i]);
end
//移动到图片数据最后一行起始位置
file_end_offset = `IMG_ALL + `LEN_HEADER - `IMG_WIDTH*3;
$fseek(fdO, file_end_offset, `SEEK_SET);
init_r = 1'b1;
end
img_rgb_ycbcr img_rgb_ycbcr(
.clk (clk ),
.rst (rst ),
.img_data_i (img_data_i ),
.valid_i (valid_i ),
.img_data_o (rgb_data_ycbcr ),
.valid_o (rgb_valid_ycbcr )
);
img_ycbcr_rgb img_ycbcr_rgb(
.clk (clk ),
.rst (rst ),
.img_data_i (rgb_data_ycbcr ),
.valid_i (rgb_valid_ycbcr ),
.img_data_o (img_data_o ),
.valid_o (valid_o )
);
always @(posedge clk or posedge rst) begin
if (rst) begin
{h_cnt_r, v_cnt_r} <= 'b0;
addr_r <= 'b0;
data_cnt_r <= 'b0;
end else begin
h_cnt_r <= (h_cnt_r == `IMG_WIDTH + `H_BLANK - 1) ? 'b0 : h_cnt_r + 1'b1;
v_cnt_r <= (h_cnt_r == `IMG_WIDTH + `H_BLANK - 1) ? ((v_cnt_r == `IMG_HEIGHT + `V_BLANK - 1) ? 'b0 : v_cnt_r + 1'b1) : v_cnt_r;
addr_r <= (addr_r == `IMG_SIZE - 1) ? 'b0 : valid_i ? (addr_r + 'd1) : addr_r;
data_cnt_r <= valid_i ? ((data_cnt_r == `IMG_WIDTH - 1) ? 'b0 : data_cnt_r + 1) : data_cnt_r;
end
end
assign valid_i = (h_cnt_r < `IMG_WIDTH)&&(v_cnt_r < `IMG_HEIGHT) ? 1'b1 : 1'b0;
assign img_data_i = {imgR_r[addr_r], imgG_r[addr_r], imgB_r[addr_r]};
///写入BMP文件
assign {R_o_w, G_o_w, B_o_w} = img_data_o;
always @(posedge clk or posedge rst) begin
if (rst) begin
out_data_cnt_r <= 'b0;
valid_o_r <= 'b0;
end else begin
valid_o_r <= valid_o;
if(valid_o) begin
$fwrite(fdO, "%c", B_o_w);
$fwrite(fdO, "%c", G_o_w);
$fwrite(fdO, "%c", R_o_w);
out_data_cnt_r <= out_data_cnt_r + 1'b1;
end else if(valid_o_r) begin//行结束
file_end_offset = file_end_offset - `IMG_WIDTH*3;
$fseek(fdO, file_end_offset, `SEEK_SET);
end
end
end
endmodule
结果
原图
仿真图
标签:fpga,img,bmp,YCBCR,RGB,valid,IMG,128,reg From: https://blog.csdn.net/weixin_62953178/article/details/140966816