YCbCr介绍
YCbCr由Y、Cb、Cr组成。为一种数字信号
1、Y:表示颜色的明亮度和浓度,也可叫灰度阶。(通过RGB转换YCBCR提取Y分量也可以得到灰度图像)
2、Cb:表示颜色的蓝色浓度偏移量即RGB输入信号蓝色部分与RGB信号亮度值之间的差异。
3、Cr:表示颜色的红色浓度偏移量即RGB输入信号红色部分与RGB信号亮度值之间的差异。
转换公式
:::info
Y=0.299R+0.587G+0.114B R=Y+1.371(Cr-128)
Cb=128-0.169R-0.331G+0.500B G=Y-0.698(Cr-128)-0.336(Cb-128)
Cr=128+0.5R-0.419G-0.081B B=Y+1.732(Cb-128)
R、G、B、Y、Cb、Cr [0,255]
:::
FPGA硬件实现推导
Y=0.299R+0.587G+0.114B
1、去掉浮点数,暂不考虑精度,将数值扩大256倍。
Y1=76.544R+150.272G+29.184B≈76R+150G+29B
2、数值扩大了256倍,2的8次方,因此右移8bit(或取高8bit)。
Y2=Y1>>8
matlab代码实现
clc;
IMG1 = imread('./picture./19.jpg'); %读取照片
h=size(IMG1,1);
w=size(IMG1,2);%读取照片的长宽
subplot(2,2,1);imshow(IMG1);title('RGB Image')
IMG1 = double(IMG1);
IMG_YCbCr = zeros(h,w,3);
for i = 1:h
for j = 1:w
IMG_YCbCr(i,j,1) = bitshift((IMG1(i,j,1)*76 + IMG1(i,j,2)*150 + IMG1(i,j,3)*29),-8);
IMG_YCbCr(i,j,2) = bitshift((-IMG1(i,j,1)*43 - IMG1(i,j,2)*84 + IMG1(i,j,3)*128 + 32768),-8);
IMG_YCbCr(i,j,3) = bitshift((IMG1(i,j,1)*128 - IMG1(i,j,2)*107 - IMG1(i,j,3)*20 + 32768),-8);
end
end
IMG_YCbCr = uint8(IMG_YCbCr);%0~255
subplot(2,2,2);imshow(IMG_YCbCr(:, :, 1));title('Y Channel1');
subplot(2,2,3);imshow(IMG_YCbCr(:,:,2));title('Cb Channel1');
subplot(2,2,4);imshow(IMG_YCbCr(:,:,3));title('Cr Channel1');
FPGA代码实现
`timescale 1ns / 1ns
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/11/08 17:35:05
// Design Name:
// Module Name: RGB888_YCbCr444
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module RGB888_YCbCr444
(
//global clock
input sys_clk, //cmos video pixel clock
input sys_rst_n, //global reset
//Image data prepred to be processed
input per_img_vsync, //Prepared Image data vsync valid signal
input per_img_href, //Prepared Image data href vaild signal
input [7:0] per_img_red, //Prepared Image red data to be processed
input [7:0] per_img_green, //Prepared Image green data to be processed
input [7:0] per_img_blue, //Prepared Image blue data to be processed
//Image data has been processed
output post_img_vsync, //Processed Image data vsync valid signal
output post_img_href, //Processed Image data href vaild signal
output [7:0] post_img_Y, //Processed Image brightness output
output [7:0] post_img_Cb, //Processed Image blue shading output
output [7:0] post_img_Cr //Processed Image red shading output
);
//--------------------------------------------
/*********************************************
//Refer to full/pc range YCbCr format
Y = R*0.299 + G*0.587 + B*0.114
Cb = -R*0.169 - G*0.331 + B*0.5 + 128
Cr = R*0.5 - G*0.419 - B*0.081 + 128
--->
Y = (76 *R + 150*G + 29 *B)>>8
Cb = (-43*R - 84 *G + 128*B + 32768)>>8
Cr = (128*R - 107*G - 20 *B + 32768)>>8
**********************************************/
//Step 1
reg [15:0] img_red_r0, img_red_r1, img_red_r2;
reg [15:0] img_green_r0, img_green_r1, img_green_r2;
reg [15:0] img_blue_r0, img_blue_r1, img_blue_r2;
always@(posedge sys_clk)
begin
img_red_r0 <= per_img_red * 8'd76;
img_red_r1 <= per_img_red * 8'd43;
img_red_r2 <= per_img_red * 8'd128;
img_green_r0 <= per_img_green * 8'd150;
img_green_r1 <= per_img_green * 8'd84;
img_green_r2 <= per_img_green * 8'd107;
img_blue_r0 <= per_img_blue * 8'd29;
img_blue_r1 <= per_img_blue * 8'd128;
img_blue_r2 <= per_img_blue * 8'd20;
end
//--------------------------------------------------
//Step 2
reg [15:0] img_Y_r0;
reg [15:0] img_Cb_r0;
reg [15:0] img_Cr_r0;
always@(posedge sys_clk)
begin
img_Y_r0 <= img_red_r0 + img_green_r0 + img_blue_r0;
img_Cb_r0 <= img_blue_r1 - img_red_r1 - img_green_r1 + 16'd32768;
img_Cr_r0 <= img_red_r2 - img_green_r2 - img_blue_r2 + 16'd32768;
end
//--------------------------------------------------
//Step 3
reg [7:0] img_Y_r1;
reg [7:0] img_Cb_r1;
reg [7:0] img_Cr_r1;
always@(posedge sys_clk)
begin
img_Y_r1 <= img_Y_r0[15:8];
img_Cb_r1 <= img_Cb_r0[15:8];
img_Cr_r1 <= img_Cr_r0[15:8];
end
//------------------------------------------
//lag 3 clocks signal sync
reg [2:0] per_img_vsync_r;
reg [2:0] per_img_href_r;
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
begin
per_img_vsync_r <= 0;
per_img_href_r <= 0;
end
else
begin
per_img_vsync_r <= {per_img_vsync_r[1:0], per_img_vsync};
per_img_href_r <= {per_img_href_r[1:0], per_img_href};
end
end
assign post_img_vsync = per_img_vsync_r[2];
assign post_img_href = per_img_href_r[2];
assign post_img_Y = post_img_href ? img_Y_r1 : 8'd0;
assign post_img_Cb = post_img_href ? img_Cb_r1: 8'd0;
assign post_img_Cr = post_img_href ? img_Cr_r1: 8'd0;
endmodule
testbench
`timescale 1ns / 1ns
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/11/30 19:10:17
// Design Name:
// Module Name: testbench
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module testbench();
localparam image_width = 640;
localparam image_height = 480;
//----------------------------------------------------------------------
// sys_clk & sys_rst_n
reg sys_clk;
reg sys_rst_n;
initial
begin
sys_clk = 1'b0;
sys_rst_n <= 1'b0;
#10
sys_rst_n <= 1'b1;
end
always #10 sys_clk=~sys_clk;
//----------------------------------------------------------------------
// Image data prepred to be processed
reg per_img_vsync; //场同步信号、低电平有效
reg per_img_href; //行同步信号 低电平有效
reg [7:0] per_img_red;
reg [7:0] per_img_green;
reg [7:0] per_img_blue;
// Image data has been processed
wire post_img_vsync;
wire post_img_href;
wire [7:0] post_img_Y;
wire [7:0] post_img_Cb;
wire [7:0] post_img_Cr;
//----------------------------------------------------------------------
// task and function //读取图像RGB数据,并按照一定时序产生视频激励
task image_input;
begin:img_input
reg [31:0] row_cnt;//列
reg [31:0] col_cnt;//行
reg [7:0] mem [image_width*image_height*3-1:0]; //memory存储器
$readmemh("../../../../../data/img_RGB.dat",mem); //读取数据
for(row_cnt = 0;row_cnt < image_height;row_cnt=row_cnt+1) //循环480次
begin
repeat(5) @(posedge sys_clk);
per_img_vsync = 1'b1; //一帧数据传输开始
repeat(5) @(posedge sys_clk);
for(col_cnt = 0;col_cnt < image_width;col_cnt=col_cnt+1)
begin
per_img_href = 1'b1; //一行数据传输开始
per_img_red = mem[(row_cnt*image_width+col_cnt)*3+0];
per_img_green = mem[(row_cnt*image_width+col_cnt)*3+1];
per_img_blue = mem[(row_cnt*image_width+col_cnt)*3+2];
@(posedge sys_clk);
end
per_img_href = 1'b0; //一行数据传输完成
end
per_img_vsync = 1'b0;//一帧数据传输完成
@(posedge sys_clk);
end
endtask : image_input
reg post_img_vsync_r;
always @(posedge sys_clk) //打一拍
begin
if(sys_rst_n == 1'b0)
post_img_vsync_r <= 1'b0;
else
post_img_vsync_r <= post_img_vsync;
end
wire post_img_vsync_pos;
wire post_img_vsync_neg;
assign post_img_vsync_pos = ~post_img_vsync_r & post_img_vsync; //上升沿
assign post_img_vsync_neg = post_img_vsync_r & ~post_img_vsync; //下降沿
task image_result_check; //检测数据转换的数据与原始数据不同的地方
begin:check
reg frame_flag; //帧信号
reg [31:0] row_cnt; //列计数
reg [31:0] col_cnt; //行计数
reg [ 7:0] mem [image_width*image_height*3-1:0];
frame_flag = 0;
$readmemh("../../../../../data/img_YCbCr.dat",mem);
while(1)
begin
@(posedge sys_clk);
if(post_img_vsync_pos == 1'b1) //一帧开始 上升沿
begin
frame_flag = 1;
row_cnt = 0;
col_cnt = 0;
$display("##############image result check begin##############");
end
if(frame_flag == 1'b1)
begin
if(post_img_href == 1'b1) //一行传输信号开始
begin
if((post_img_Y != mem[(row_cnt*image_width+col_cnt)*3+0])||(post_img_Cb != mem[(row_cnt*image_width+col_cnt)*3+1])||(post_img_Cr != mem[(row_cnt*image_width+col_cnt)*3+2]))
begin //如果Y、Cb、Cr与初始数据不同
$display("result error ---> row_num : %0d;col_num : %0d;pixel data(y cb cr) : (%h %h %h);reference data(y cb cr) : (%h %h %h)",row_cnt+1,col_cnt+1,post_img_Y,post_img_Cb,post_img_Cr,mem[(row_cnt*image_width+col_cnt)*3+0],mem[(row_cnt*image_width+col_cnt)*3+1],mem[(row_cnt*image_width+col_cnt)*3+2]);
end
col_cnt = col_cnt + 1;
end
if(col_cnt == image_width)
begin
col_cnt = 0;
row_cnt = row_cnt + 1;
end
end
if(post_img_vsync_neg == 1'b1)//下降沿
begin
frame_flag = 0;
$display("##############image result check end##############");
end
end
end
endtask : image_result_check
//----------------------------------------------------------------------
RGB888_YCbCr444 u_RGB888_YCbCr444
(
// global clock
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
// Image data prepred to be processed
.per_img_vsync (per_img_vsync ),
.per_img_href (per_img_href ),
.per_img_red (per_img_red ),
.per_img_green (per_img_green ),
.per_img_blue (per_img_blue ),
// Image data has been processed
.post_img_vsync (post_img_vsync ),
.post_img_href (post_img_href ),
.post_img_Y (post_img_Y ),
.post_img_Cb (post_img_Cb ),
.post_img_Cr (post_img_Cr )
);
initial
begin
per_img_vsync = 0;
per_img_href = 0;
per_img_red = 0;
per_img_green = 0;
per_img_blue = 0;
end
initial
begin
wait(sys_rst_n);
fork
begin
repeat(5) @(posedge sys_clk);
image_input;
end
image_result_check;
join
end
endmodule
标签:sys,基于,FPGA,img,Image,per,YCbCr,post,IMG1
From: https://www.cnblogs.com/fangrunze/p/17870462.html