本帖最后由 UT发布 于 2025-3-31 10:57 编辑
软件版本:Anlogic -TD5.6.1-64bit
操作系统:WIN10 64bit
硬件平台:适用安路(Anlogic)FPGA
登录“米联客”FPGA社区-www.uisrc.com视频课程、答疑解惑!
1概述 本文讲解色彩空间转换的算法,介绍RGB、YUV和YcbCr之间的转换公式,并使用verilog语言实现算法,进行上板实验。 2色彩空间转换算法简介 RGB、YUV和YCbCr都是人为规定的色彩空间。其用途是在某些标准下以通用化的方式对彩色进行描述。本质上,彩色模型是坐标系统和子空间的描述。 RGB是依据人眼识别的颜色定义出的空间,可表示大部分颜色。但在科学研究一般不采用RGB颜色空间,因为它的细节难以进行数字化的调整。它将色调,亮度,饱和度三个量放在一起表示,很难分开。它是最通用的面向硬件的彩色模型。该模型用于彩色监视器和一些彩色视频摄像。 在 YUV色彩空间中,每一个颜色有一个亮度信号Y,和两个色度信号U和V。亮度信号是强度的感觉,它和色度信号断开,这样的话强度就可以在不影响颜色的情况下改变。 YUV使用RGB的信息,但它从全彩色图像中产生一个黑白图像(Y信号),然后提取出三个主要的颜色变成两个额外的信号来描述颜色。把这三个信号组合回来就可以产生一个全彩色图像。 Y 通道描述明亮度信号,值的范围介于亮和暗之间。明亮度是黑白电视可以看到的信号。U (Cb) 和 V (Cr)通道从红 (U) 和蓝 (V) 中提取亮度值来减少颜色信息量。这些值可以从新组合来决定红,绿和蓝的混合信号。 3 YUV与RGB的转换 Y = 0.299 R + 0.587 G + 0.114 B U = -0.1687 R - 0.3313 G + 0.5 B + 128 V = 0.5 R - 0.4187 G - 0.0813 B + 128
R = Y + 1.402 (V-128) G = Y - 0.34414 (U-128) - 0.71414 (V-128) B = Y + 1.772 (U-128) 4 YCbCr与RGB的转换 YCbCr 是在世界数字组织视频标准研制过程中作为ITU - R BT1601 建议的一部分,是YUV经过缩放和偏移的翻版。其中Y与YUV 中的Y含义一致, Cb , Cr 同样都指色彩, 只是在表示方法上不同而已。在YUV家族中, YCbCr 是在计算机系统中应用最多的成员,其应用领域很广泛,JPEG、MPEG均采用此格式。一般人们所讲的YUV大多是指YCbCr。 YCbCr与RGB的相互转换: Y = 0.2568*R + 0.5041*G + 0.0979*B + 16; Cb = -0.1482*R - 0.2910*G + 0.4392*B + 128; Cr = 0.4392*R - 0.3678*G - 0.0714*B + 128; R = 1.1644*(Y- 16) + 1.5960*(Cr - 128); G = 1.1644*(Y - 16) - 0.3918*(Cb- 128) -0.8130*(Cr- 128); B = 1.1644*(Y - 16) + 2.0172*(Cb- 128); 5算法仿真
5.1 Matlab算法仿真
5.1.1Matlab算法代码分析
- %=================================================================================
- %rgb2ycbcr
- %=================================================================================
- T = [ ...
- 0.2568 0.5041 0.0979;...
- -0.1482 -0.2910 0.4392;...
- 0.4392 -0.3678 -0.0714];
- Offset = [16; 128; 128];
- ycbcr1 = zeros(size(image_in), 'like', image_in);
- <font color="#00bfff">for p = 1:3
- ycbcr1(:,:,p) = imlincomb( T(p,1),image_in_r,...
- T(p,2),image_in_g,...
- T(p,3),image_in_b,...
- Offset(p));
- end</font>
- image1_in_y = ycbcr1(:,:,1);
- image1_in_cb = ycbcr1(:,:,2);
- image1_in_cr = ycbcr1(:,:,3);
- %=================================================================================
- %=================================================================================
- %rgb2ycbcr 2
- %=================================================================================
- <font color="#00bfff">ycbcr2 = rgb2ycbcr(image_in);</font>
- image2_in_y = ycbcr2(:,:,1);
- image2_in_cb = ycbcr2(:,:,2);
- image2_in_cr = ycbcr2(:,:,3);
- %=================================================================================
复制代码
蓝色部分为关键计算部分,本次采用了两种方式进行了RGB转YCbCr的计算,一种直接带入系数进行计算,另一种直接使用matlab的库函数rgb2ycbcr进行转换的。可以看到矩阵T为1.2小节中的公式中的系数部分,Offset为常数部分,通过matlab imlincomb的函数进行计算图像线性组合,最后得到YCbCr的图像。 5.1.2Matlab实验结果 第一行为RGB转YCbCr,从左至右分别是原图、Y图、Cb图、Cr图、YCbCr转RGB图。 第二行为matlab库函数RGB转YCbCr,从左至右分别是原图、Y图、Cb图、Cr图、YCbCr转RGB图。 5.2 Verilog算法仿真
5.2.1 Modelsim仿真
5.2.1.1仿真执行 在件夹Algorithm_simulation下进行算法的仿真,分为sim,src和tb三个子文件夹。在sim文件夹下有win系统的快捷执行文件sim.bat,可以一键进行仿真,src文件下放的是Verilog的核心图像算法及其顶层与输入图像激励,tb文件下放的是测试激励文件及输出图像的保存。 双击执行sim文件夹下sim.bat,自动打开Modelsim仿真,自动添加仿真波形,执行完成后自动保存图像,仿真波形如图所示:
5.2.1.2仿真关键部分代码解析- reg clk;
- reg rst_n;
-
- integer image_txt;
-
- reg [31:0] pixel_cnt;
- wire[23:0] data;
- wire de;
- wire [7:0] y;
- wire [7:0] cb;
- wire [7:0] cr;
-
- top u_top
- (
- .i_clk (clk ),
- .i_rst_n (rst_n ),
- .o_hsyn ( ),
- .o_vsyn ( ),
- .o_y (y ),
- .o_cb (cb ),
- .o_cr (cr ),
- .o_de (de )
- );
-
- assign data = {y,cb,cr};
-
- always #(1) clk = ~clk;
-
- initial
- begin
- clk = 1;
- rst_n = 0;
- #100
- rst_n = 1;
-
- end
-
- initial
- begin
- image_txt = $fopen("../../matlab_src/image_720_1280_rgb2ycbcr_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\n",data);
- end
- end
-
- always@(posedge clk )
- begin
- if(pixel_cnt == 720*1280)
- begin
- $display("*******************************************************************************");
- $display("*** Success:image_720_1280_rgb2ycbcr_out.txt is output complete! %t", $realtime, "ps***");
- $display("*******************************************************************************");
- $fclose(image_txt);
- $stop;
- end
- end
复制代码
5.2.2Modelsim实验结果 matlab查看输入输出的图像代码部分: - clear;clear all;clc;
-
- row = 720;
- col = 1280;
- n = 3;
- image_sim_pass = uint8(zeros(row,col,n));
-
- fid = fopen('image_720_1280_rgb2ycbcr_out.txt','r');
-
- for x = 1:row
- for y = 1:col
- RGB = fscanf(fid,'%s',1);
- image_sim_pass(x,y,1) = uint8(hex2dec(RGB(1:2)));
- image_sim_pass(x,y,2) = uint8(hex2dec(RGB(3:4)));
- image_sim_pass(x,y,3) = uint8(hex2dec(RGB(5:6)));
- end
- end
- fclose(fid);
-
- rgb = zeros(size(image_sim_pass), 'like', image_sim_pass);
- 将图像格式转换成RGB格式。
- rgb = ycbcr2rgb(image_sim_pass);
-
- image_1 = imread('lena_1280x720.jpg');
-
- figure;
- subplot(121);
- imshow(image_1), title('The original image');
-
- subplot(122);
- imshow(rgb),title('After processing images');
- imwrite(rgb,'lena_1280x720_rgb2ycbcr_sim_pass.jpg');
复制代码
使用matlab查看输入输出的图像,如图所示: RGB转YCbCr: 6工程实现 6.1代码分析按照1.2小节中的公式中进行公式变换: // ycbcr0(:,:,1) = 0.2568*image_in_r + 0.5041*image_in_g + 0.0979*image_in_b + 16; // ycbcr0(:,:,2) = -0.1482*image_in_r - 0.2910*image_in_g + 0.4392*image_in_b + 128; // ycbcr0(:,:,3) = 0.4392*image_in_r - 0.3678*image_in_g - 0.0714*image_in_b + 128; 先乘以256然后右移8位。 // ycbcr0(:,:,1) = 256*( 0.2568*image_in_r + 0.5041*image_in_g + 0.0979*image_in_b + 16 )>>8; // ycbcr0(:,:,2) = 256*(-0.1482*image_in_r - 0.2910*image_in_g + 0.4392*image_in_b + 128)>>8; // ycbcr0(:,:,3) = 256*( 0.4392*image_in_r - 0.3678*image_in_g - 0.0714*image_in_b + 128)>>8; 最终结果如下: // ycbcr0(:,:,1) = (66*image_in_r + 129*image_in_g + 25*image_in_b + 4096 )>>8; // ycbcr0(:,:,2) = (-38*image_in_r - 74*image_in_g + 112*image_in_b + 32768)>>8; // ycbcr0(:,:,3) = (112*image_in_r - 94*image_in_g - 18*image_in_b + 32768 )>>8; - always@(posedge i_clk or negedge i_rst_n)
- begin
- if(!i_rst_n)
- begin
- r_d0 <= 16'd0;
- g_d0 <= 16'd0;
- b_d0 <= 16'd0;
- r_d1 <= 16'd0;
- g_d1 <= 16'd0;
- b_d1 <= 16'd0;
- r_d2 <= 16'd0;
- g_d2 <= 16'd0;
- b_d2 <= 16'd0;
- end
- else
- begin
- r_d0 <= 66 * i_r;
- g_d0 <= 129 * i_g;
- b_d0 <= 25 * i_b;
- r_d1 <= 38 * i_r;
- g_d1 <= 74 * i_g;
- b_d1 <= 112 * i_b;
- r_d2 <= 112 * i_r;
- g_d2 <= 94 * i_g;
- b_d2 <= 18 * i_b;
- end
- end
复制代码
完成乘法后进行加减法运算: - always@(posedge i_clk or negedge i_rst_n)
- begin
- if(!i_rst_n)
- begin
- y_d0 <= 16'd0;
- cb_d0 <= 16'd0;
- cr_d0 <= 16'd0;
- end
- else
- begin
- y_d0 <= r_d0 + g_d0 + b_d0 + 4096 ;
- cb_d0 <= b_d1 - r_d1 - g_d1 + 32768;
- cr_d0 <= r_d2 - g_d2 - b_d2 + 32768;
- end
- end
- 最后进行信号的同步:
- always@(posedge i_clk )
- begin
- hsyn <= {hsyn[0],i_hsyn};
- vsyn <= {vsyn[0],i_vsyn};
- de <= {de[0],i_de};
- end
-
- assign o_hsyn = hsyn[1];
- assign o_vsyn = vsyn[1];
- assign o_y = y_d0 [15:8];
- assign o_cb = cb_d0[15:8];
- assign o_cr = cr_d0[15:8];
- assign o_de = de[1];
复制代码
最后进行信号的同步: - always@(posedge i_clk )
- begin
- hsyn <= {hsyn[0],i_hsyn};
- vsyn <= {vsyn[0],i_vsyn};
- de <= {de[0],i_de};
- end
-
- assign o_hsyn = hsyn[1];
- assign o_vsyn = vsyn[1];
- assign o_y = y_d0 [15:8];
- assign o_cb = cb_d0[15:8];
- assign o_cr = cr_d0[15:8];
- assign o_de = de[1];
复制代码
6.2工程结构 工程结构如图所示: 图像数据通过摄像头采集进来,先缓存在fifo中,然后通过写状态机,将图像数据送进DDR进行缓存,缓存后的图像数据从DDR中取出,通过读状态机送出到fifo中,然后算法处理模块在fifo中取出数据,完成数据处理后送到LCD进行显示输出。
7上板实验 插好摄像头,连接好板子与液晶屏之间的连接,如图所示: 然后给开发板上电,连接JTAG下载器到电脑,然后打开下载界面,如图所示: 点击下载后,可以看到正常的输出如下所示,摄像头的分辨率为640x480,
|