抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

RGB YUV色域转换Verilog实现

在最近一次的FPGA比赛中,其他指标都没做出来,就这个做出来了,狠狠地寄掉了。但是查了一圈网上似乎没有该算法的Verilog实现,所以现在来写写。(才不是因为图床挂了更不了复习笔记)

RGB888是最常见的色彩空间表示,但在我们的显示设备例如电视,显示屏中其实都是走的YUV色域,这种色域可以方便地接收黑白信号和彩色信号,通常看见的YCbCr其实就是YUV色域。

YUV色域其实还分很多种规格,有模拟信号的,有数字信号的,还有高清,超高清等等很多种。在测试过程中发现如果变换公式没有匹配上,会出现非常严重的色偏现象。

这里就贴一下个人电脑常用的数字信号RGB到YCbCr色域的变换矩阵:

逆变换矩阵如下:

有了矩阵就好办了,Verilog中只能使用定点数,选取10位定点计算出变换方程:

逆变换方程:

Verilog实现分三拍,第一拍用寄存器存一下乘法器输出,第二拍做加减法,第三拍右移,输出的时候需要打三拍不然时序会乱。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//正变换运算模块
//Step 1
reg [31:0] img_red_r0, img_red_r1, img_red_r2;
reg [31:0] img_green_r0, img_green_r1, img_green_r2;
reg [31:0] img_blue_r0, img_blue_r1, img_blue_r2;
always@(posedge clk)
begin
img_red_r0 <= per_img_red * 10'd306;
img_green_r0 <= per_img_green * 10'd601;
img_blue_r0 <= per_img_blue * 10'd117;

img_red_r1 <= per_img_red * 10'd173;
img_green_r1 <= per_img_green * 10'd339;
img_blue_r1 <= per_img_blue * 10'd512;

img_red_r2 <= per_img_red * 10'd512;
img_green_r2 <= per_img_green * 10'd429;
img_blue_r2 <= per_img_blue * 10'd83;
end
//--------------------------------------------------
//Step 2
reg signed[31:0] img_Y_r0;
reg signed[31:0] img_Cb_r0;
reg signed[31:0] img_Cr_r0;
always@(posedge 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+18'd131072 ;
img_Cr_r0 <= img_red_r2 - img_green_r2 - img_blue_r2+18'd131072 ;
end
//--------------------------------------------------
//Step 3
reg [7:0] img_Y_r1;
reg [7:0] img_Cb_r1;
reg [7:0] img_Cr_r1;
always@(posedge clk)
begin
img_Y_r1 <= img_Y_r0[31:10];
img_Cb_r1 <= img_Cb_r0[31:10];
img_Cr_r1 <= img_Cr_r0[31:10];
end

寄存器用的signed型32位主要是怕有溢出和负数风险,但实际上应该是没有的,不过现在编译器都已经很智能了,开这么大它布线的时候会计算具体需要多少位然后优化的(编译器比我聪明多了)

正变换的代码是我在一本书里看到的,逆变换就是我如法炮制的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//逆变换运算
//Step 1
reg signed[31:0] img_y_r0;
reg signed[31:0] img_v_r0, img_v_r1;
reg signed[31:0] img_u_r0, img_u_r1;
always@(posedge clk)
begin
img_y_r0 <= per_img_y*12'd1024;
img_v_r0 <= (per_img_v-8'd128) * 11'd1437;
img_u_r0 <= (per_img_u-8'd128) * 11'd352;
img_v_r1 <= (per_img_v-8'd128) * 11'd731;
img_u_r1 <= (per_img_u-8'd128) * 11'd1815;
end
//--------------------------------------------------
//Step 2
reg signed[31:0] img_r_r0;
reg signed[31:0] img_g_r0;
reg signed[31:0] img_b_r0;
always@(posedge clk)
begin
img_r_r0 <= img_y_r0+ img_v_r0;
img_g_r0 <= img_y_r0- img_u_r0 - img_v_r1;
img_b_r0 <= img_y_r0+img_u_r1;
end
//--------------------------------------------------
//Step 3
reg [7:0] img_r_r1;
reg [7:0] img_g_r1;
reg [7:0] img_b_r1;
always@(posedge clk)
begin
img_r_r1 <= img_r_r0[31:10];
img_g_r1 <=img_g_r0[31:10];
img_b_r1 <=img_b_r0[31:10];
end

最后接上HDMI输出就可以啦,能够实现保证色度不变的情况下调整亮度。

评论




博客内容遵循 [署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)
本站使用 Volantis 作为主题