FPGA数字图像处理基础:色彩空间转换(Verilog)

电子说

1.3w人已加入

描述

01图像色彩空间概述

色彩本质上是不同频率的光,人眼对于不同频率光线的不同感受产生主观感知,从而得以区分不同的颜色。尽管从客观上而言,色彩仅仅是不同频率的光,但从视觉角度而言,不同颜色的认知难度很大,因此引入色彩空间(Color Space)以便图像色彩的深入研究。

 

常见的色彩空间主要有:RGB、YUV(YCbCr)、Lab、HSV和CMY(CMYK)等。

1.1 RGB空间

RGB空间是基于人眼识别的颜色所定义的色彩空间,以红(R,Red)、绿(G,Green)、蓝(B,Blue)三种基本色为基础进行不同程度的叠加而成。红、绿、蓝作为三原色按亮度分别划分为256个等级,从而可以表示一千六百多万种不同的颜色,且每种颜色是唯一的。

RGB色彩空间的丰富性使其成为数字图像处理与显示的重要格式。通常可将RGB色彩空间模型建立在笛卡尔坐标系中,采用空间坐标的形式表示出超过人眼分辨程度数量的颜色信息。

FPGA

RGB色彩空间直观且易于理解,然而R、G、B三个分量是高度相关的,由于人眼对于常见的红绿蓝三色的敏感程度不同,所以导致RGB颜色空间的均匀性非常差,且两种颜色之间的知觉差异色差不能表示为该颜色空间中两点间的距离,不过利用线性或非线性变换,可以从RGB颜色空间推导出其他的颜色特征空间。

1.2 YUV(YCbCr)空间

YUV色彩空间是彩色设备显示指定的色彩空间,Y表示亮度分量,U和V表示色度分量。YCbCr色彩空间是从YUV色彩空间的基础上演变而来的,与YUV相似,但存在一定差异。

YUV最初是北美NTSC系统和欧洲PAL系统中模拟电视信号编码的基础,采用亮度与色度分离的方式更易于图像处理;YCbCr则是在世界数字组织视频标准研制过程中作为ITU - R BT1601建议的一部分,是YUV经过缩放和偏移的变种。在YUV系列中,YCbCr是在数字图像处理系统中应用最为广泛的格式,JPEG、MPEG、H.264均基于此格式进行处理。

YCbCr色彩空间中,Y表示亮度分量,Cb表示蓝色色度分量,Cr表示红色色度分量。亮度和色度分量相互独立的方式,有利于利用人眼特性降低数字图像所需的存储容量,从而实现图像的压缩编码等处理。

1.3 Lab空间

Lab色彩空间是基于生理特征的颜色系统,与设备无关,即采用数字化的方法描述人的视觉感知。L表示亮度,取值范围为0~100,表示从黑~白;a分量取值范围为 -128~127,表示从绿~红;b分量取值范围为 -128~127,表示从蓝~黄。

FPGA

Lab色彩空间致力于感知均匀性,它的L分量密切匹配人类亮度感知。因此,可以被用来通过修改a和b分量的输出色阶来做精确的颜色平衡,或使用L分量来调整亮度对比。

Lab色彩空间所描述的色域是最大的,因此Lab色彩空间存在大量色彩超出人类视域范围,甚至无法在物理世界再现。同时,RGB等色彩空间的设备依赖性也使得Lab色彩空间无法直接与其他色彩空间进行转换。

1.4 HSV空间

HSV色彩空间是根据颜色的直观特性色调(H,Hue)、饱和度(S,Saturation)和亮度(V,Value)建立的色彩模型。由于H、S、V可以构成锥形坐标系,所以HSV模型通常也称为六角锥体模型(Hexcone Model)。

FPGAFPGA

色调H:图像色彩信息,描述光谱颜色所在位置。采用角度度量,取值范围为0°~360°。若从红色开始按逆时针方向计算:红色为0°,绿色为120°,蓝色为240°,互补色之间相差180°;

饱和度S:图像纯度信息,描述颜色接近光谱色的程度。采用比例值度量,取值范围为0~1。颜色通常可看作某种光谱色与白色的混合结果,饱和度越高,光谱色所占比例越大,颜色越接近光谱色,表现为颜色深;饱和度越低,光谱色所占比例越小,颜色越远离光谱色,表现为颜色浅。饱和度为0时,表现出颜色仅有灰度;

亮度V:图像亮度信息,描述色彩的明亮程度。采用比例值度量,取值范围为0~1。对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。

1.5 CMY(CMYK)空间

CMYK色彩空间是一种减色模式色彩空间,常用于彩色印刷。CMYK是基于C(Cyan)、M(Megenta)、Y(Yellow)和K(Black)四种颜色叠加而成的,由于在实际应用中青色(Cyan)、洋红色(Megenta)和黄色(Yellow)叠加很难形成真正的黑色(Black),而是褐色,因此引入黑色K(Black)强化暗调,加深暗部色彩。

CMYK与RGB根本的区别在于CMYK采用减色色彩模式——当阳光照射到一个物体上时,物体将吸收一部分光线并反射剩下的光线,反射的光线就是所看见的物体颜色,即减色色彩模式。因此,CMYK色彩模式更接近于真实效果,尽管不如RGB模式下的色彩多,但更适合印刷。

02

色彩空间转换原理

尽管RGB是日常生活中彩色视频图像最常用的图像格式,但RGB格式图像将色调、亮度和饱和度综合在一起,细节上难以进行数字化调整,因此在科学研究中通常采用YUV(YCbCr)或灰度图格式,掌握RGB与YUV(YCbCr)/灰度图之间的转换原理有利于后续数字图像处理分析。

2.1 RGB与YUV转换原理

RGB与YUV依据以下公式进行转换:

RGB转为YUV:

Y = 0.299*R + 0.587*G + 0.114*B

U = - 0.169*R - 0.331*G + 0.5*B + 128

V = 0.5*R - 0.419*G - 0.081*B  + 128

YUV转为RGB:

R = Y + 1.402*(V-128)

G = Y - 0.344*(U-128) - 0.714*(V-128)

B = Y + 1.772*(U-128) 

通过Matlab对转换算法进行验证:

FPGA

Matlab转换代码:

%********************************************************************** 

% -------------------------------------------------------------------

% Company: Cascatrix

% Engineer: Carson

% Create Date: 2023/02/11

% Design Name: rgb_yuv

% Module Name: rgb_yuv

% Tool Versions: v1.0

% Description: Convert RGB888 into YUV

%------------------------------------------------------------------- 

%*********************************************************************/

clear;clear all;clc;

% Load image

image_in = imread('cascatrix.jpg');  

% Seperate R G B

image_r = int16(image_in(:,:,1));          

image_g = int16(image_in(:,:,2));          

image_b = int16(image_in(:,:,3));          

% Get image size 

[row,col,n] = size(image_in);

% Calculate Y U V

image_y  = 0.299*image_r + 0.587*image_g + 0.114*image_b;      

image_u = - 0.169*image_r - 0.331*image_g + 0.5*image_b + 128;          

image_v = 0.5*image_r - 0.419*image_g - 0.081*image_b + 128;

% Recover R G B

image_out_r = image_y + 1.402*(image_v - 128);

image_out_g = image_y - 0.344*(image_u - 128) - 0.714*(image_v - 128);         

image_out_b = image_y + 1.772*(image_u - 128);

% Output processed RGB image

image_out = cat(3,image_out_r,image_out_g,image_out_b);

% Display before/after processed image

figure(1)

subplot(121);

imshow(uint8(image_in)), title('Image in');

subplot(122);

imshow(uint8(image_out));title('Image out');

% Display Y U V

figure(2)

subplot(131);

imshow(uint8(image_y)),title('Image Y');

subplot(132);

imshow(uint8(image_u)),title('Image U');

subplot(133);

imshow(uint8(image_v)),title('Image V');

Matlab代码将输出结果:

1. 转换前/后图像对比:

FPGA

2. Y、U、V三通道图像显示:

FPGA

2.2 RGB与YCbCr转换原理

RGB与YCbCr依据以下公式进行转换:

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

YCbCr转为RGB:

R = 1.164*(Y-16) + 1.596*(Cr-128)

G = 1.164*(Y-16) - 0.392*(Cb-128) - 0.813*(Cr-128)

B = 1.164*(Y-16) + 2.017*(Cb-128)

通过Matlab对转换算法进行验证:

FPGA

Matlab转换代码:

%********************************************************************** 

% -------------------------------------------------------------------

% Company: Cascatrix

% Engineer: Carson

% Create Date: 2023/02/11

% Design Name: rgb_ycbcr

% Module Name: rgb_ycbcr

% Tool Versions: v1.0

% Description: Convert RGB888 into YCbCr

%------------------------------------------------------------------- 

%*********************************************************************/

clear;clear all;clc;

% Load image

image_in = imread('cascatrix.jpg');  

% Seperate R G B

image_r = int16(image_in(:,:,1));          

image_g = int16(image_in(:,:,2));          

image_b = int16(image_in(:,:,3));          

% Get image size 

[row,col,n] = size(image_in);

% Calculate Y Cb Cr

image_y  = 0.257*image_r + 0.504*image_g + 0.098*image_b + 16;      

image_cb = - 0.148*image_r - 0.291*image_g + 0.439*image_b + 128;          

image_cr = 0.439*image_r - 0.368*image_g - 0.071*image_b + 128;

% Recover R G B

image_out_r = 1.164*(image_y - 16) + 1.596*(image_cr - 128);

image_out_g = 1.164*(image_y - 16) - 0.392*(image_cb - 128) - 0.813*(image_cr - 128);         

image_out_b = 1.164*(image_y - 16) + 2.017*(image_cb - 128);

% Output processed RGB image

image_out = cat(3,image_out_r,image_out_g,image_out_b);

% Display before/after processed image

figure(1)

subplot(121);

imshow(uint8(image_in)), title('Image in');

subplot(122);

imshow(uint8(image_out));title('Image out');

% Display Y Cb Cr

figure(2)

subplot(131);

imshow(uint8(image_y)),title('Image Y');

subplot(132);

imshow(uint8(image_cb)),title('Image Cb');

subplot(133);

imshow(uint8(image_cr)),title('Image Cr');

Matlab代码将输出结果:

1. 转换前/后图像对比:

FPGA

2. Y、Cb、Cr三通道图像显示:

FPGA

2.3 RGB生成灰度图像原理

RGB生成灰度图像的方法较多,常用转换公式如下:

采用RGB中任意单通道表示灰度值:

Gray = R (Gray = G or Gray = B)

采用RGB三通道的平均值表示灰度值:

Gray = (R + G + B) / 3

采用RGB三通道的加权均值表示灰度值:

Gray = 0.299*R + 0.587*G + 0.114*B

采用RGB三通道的最大/最小值的均值表示灰度值:

Gray = ( max(R, G, B) + min(R, G, B) ) / 2

通过Matlab对转换算法进行验证:

FPGA

Matlab转换代码(采用不同方法,转换结果略有区别):

%********************************************************************** 

% -------------------------------------------------------------------

% Company: Cascatrix

% Engineer: Carson

% Create Date: 2023/02/11

% Design Name: rgb_gray

% Module Name: rgb_gray

% Tool Versions: v1.0

% Description: Convert RGB888 into gray value

%------------------------------------------------------------------- 

%*********************************************************************/

clear;clear all;clc;

% Load image

image_in = imread('cascatrix.jpg');  

% Seperate R G B

image_r = int16(image_in(:,:,1));          

image_g = int16(image_in(:,:,2));          

image_b = int16(image_in(:,:,3));          

% Get image size 

[row,col,n] = size(image_in);

% Calculate gray value by different methods

gray = rgb2gray(image_in);

% gray =  image_r;

% gray =  0.299 * image_r + 0.587 * image_g + 0.114 * image_b;

% gray =  (image_r + image_g + image_b) / 3;

% Display before/after processed image

figure

subplot(121);

imshow(uint8(image_in)), title('Image in');

subplot(122);

imshow(uint8(gray));title('Image out');

Matlab代码将输出转换前/后图像:

FPGA

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进行仿真。

FPGA

各模块代码如下:

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

    );

//1920x1080 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

//1680x1050 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

//1280x1024 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

//1024x768 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

//800x600 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

//640x480 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 <= 13'b0;

    else

        h_syn_cnt <= h_syn_cnt + 1'b1;

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 <= 13'b0;

        else

            v_syn_cnt <= v_syn_cnt + 1'b1;

end

end

// 行同步控制

always@(posedge clk)

begin

    if(h_syn_cnt < H_SYNC_TIME)

        hsyn <= 1'b0;

    else

        hsyn <= 1'b1;

end

// 场同步控制

always@(posedge clk)

begin

    if(v_syn_cnt < V_SYNC_TIME)

        vsyn <= 1'b0;

    else

        vsyn <= 1'b1;

end

always@(posedge clk)

begin

    if(v_syn_cnt == V_SYNC_TIME + V_BACK_PORCH - 1 && h_syn_cnt == 0) 

        v_act = 1'b1;

    else if(v_syn_cnt == V_SYNC_TIME + V_BACK_PORCH + V_ACTIVE - 1 && h_syn_cnt == 0)

        v_act = 1'b0;

end

always@(posedge clk)

begin

    if(h_syn_cnt == H_SYNC_TIME + H_BACK_PORCH - 1) 

        h_act = 1'b1;

    else if(h_syn_cnt == H_SYNC_TIME + H_BACK_PORCH + H_ACTIVE - 1)

        h_act = 1'b0;

end

always@(posedge clk)

begin

    if(h_act & v_act)

        image_cnt <= image_cnt + 1'b1;

    else if(image_cnt == H_ACTIVE*V_ACTIVE - 1)

    image_cnt <= 32'b0;

end

always@(posedge clk)

begin

    if(h_act & v_act)

        data <= image[image_cnt][23:0];

    else 

        data <= 24'b0;

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  <= 16'd0;

cb <= 16'd0;

cr <= 16'd0;

    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

3.1.3 实现效果分析

通过Matlab显示Verilog处理后的image_out.txt文件:

%********************************************************************** 

% -------------------------------------------------------------------

% Company: Cascatrix

% Engineer: Carson

%  

% Create Date: 2023/02/13

% Design Name: ycbcr_display

% Module Name: ycbcr_display

% Tool Versions: v1.0

% Description: Convert .txt into YCbCr and display image in RGB

%------------------------------------------------------------------- 

%*********************************************************************/

clear;clear all;clc;

% Image resolution

row = 1080;  

col = 1920;  

n   = 3;    

% Create output image

image_out = uint8(zeros(row,col,n));

% Write data into output image 

FileImage = fopen('image_out.txt','r');

for x = 1:row

    for y = 1:col

        YCbCr = fscanf(FileImage,'%s',1);

        image_out(x,y,1) = uint8(hex2dec(YCbCr(1:2)));

        image_out(x,y,2) = uint8(hex2dec(YCbCr(3:4)));

        image_out(x,y,3) = uint8(hex2dec(YCbCr(5:6)));              

    end 

end

fclose(FileImage);

% Convert YCbCr into RGB

image_out = ycbcr2rgb(image_out);

% Vivado reads image in BGR

image_out = cat(3,image_out(:,:,3),image_out(:,:,2),image_out(:,:,1));

% Show the output image

imshow(image_out),title('Image output');

% Create image in .jpg format

imwrite(image_out,'cascatrix_output.jpg');  

Matlab图像显示结果:

FPGA

3.2 RGB生成灰度图像Verilog代码

本节分析基于FPGA实现RGB生成灰度图算法,在Vivado和Matlab联合仿真的基础上,对Verilog转换实现结果在Matlab中展示,验证代码的可行性。

3.2.1 预处理操作

类似于RGB转为YCbCr,由RGB生成灰度图中同样存在小数乘法与加法运算,FPGA不擅长小数处理,因此采用扩大2^n倍后向右移n位进行实现,具体实现方法如下:

RGB生成灰度图算法:

Gray = 0.299*R + 0.587*G + 0.114*B 

将方程扩大256倍后右移8位,算法依然等价:

Gray = 256*(0.299*R + 0.587*G + 0.114*B)>>8

算法推导得:

Gray = (77*R + 150*G + 29*B)>>8

算法转化为FPGA擅长的乘法与移位运算。

3.2.2 Verilog代码

基于Matlab与Verilog联合仿真工程,添加格式转换模块cx_RGB_gray构建顶层top模块,对top进行仿真。

FPGA

各模块代码如下:

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,

    output  wirehsyn,

    output  wirevsyn,

    output  wire [7:0]gray_data

    );

wire [23:0] data;

cx_image inst_cx_image(

.clk    (clk),

.hsyn  (hsyn),

.vsyn  (vsyn),

.en      (en    ),

.data   (data)

);

cx_RGB_gray inst_cx_RGB_gray

(

.clk            (clk),

.rst_n         (rst_n    ),

.rgb_data    (data),

.gray_data  (gray_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

    );

//1920x1080 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

//1680x1050 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

//1280x1024 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

//1024x768 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

//800x600 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

//640x480 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 <= 13'b0;

    else

        h_syn_cnt <= h_syn_cnt + 1'b1;

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 <= 13'b0;

        else

            v_syn_cnt <= v_syn_cnt + 1'b1;

end

end

// 行同步控制

always@(posedge clk)

begin

    if(h_syn_cnt < H_SYNC_TIME)

        hsyn <= 1'b0;

    else

        hsyn <= 1'b1;

end

// 场同步控制

always@(posedge clk)

begin

    if(v_syn_cnt < V_SYNC_TIME)

        vsyn <= 1'b0;

    else

        vsyn <= 1'b1;

end

always@(posedge clk)

begin

    if(v_syn_cnt == V_SYNC_TIME + V_BACK_PORCH - 1 && h_syn_cnt == 0) 

        v_act = 1'b1;

    else if(v_syn_cnt == V_SYNC_TIME + V_BACK_PORCH + V_ACTIVE - 1 && h_syn_cnt == 0)

        v_act = 1'b0;

end

always@(posedge clk)

begin

    if(h_syn_cnt == H_SYNC_TIME + H_BACK_PORCH - 1) 

        h_act = 1'b1;

    else if(h_syn_cnt == H_SYNC_TIME + H_BACK_PORCH + H_ACTIVE - 1)

        h_act = 1'b0;

end

always@(posedge clk)

begin

    if(h_act & v_act)

        image_cnt <= image_cnt + 1'b1;

    else if(image_cnt == H_ACTIVE*V_ACTIVE - 1)

    image_cnt <= 32'b0;

end

always@(posedge clk)

begin

    if(h_act & v_act)

        data <= image[image_cnt][23:0];

    else 

        data <= 24'b0;

end

endmodule

3. RGB转gray模块 cx_RGB_gray:

`timescale 1ns / 1ps

//////////////////////////////////////////////////////////////////////////////////

// Company: Cascatrix

// Engineer: Carson

// 

// Create Date: 2023/02/12 

// Design Name: Image_Color_Space

// Module Name: cx_RGB_gray

// Tool Versions: v1.0

// Description: Covert RGB into YUV(YCbCr) and generate gray value 

// 

//////////////////////////////////////////////////////////////////////////////////

module cx_RGB_gray(

    input   wireclk,

    input   wirerst_n,

    input  wire [23:0]rgb_data,

    output  wire [7:0]gray_data

    );

reg [7:0] r;

reg [7:0] g;

reg [7:0] b;

reg [15:0] gray_value;

always@(*)

begin

    r <= rgb_data[7:0];

    g <= rgb_data[15:8];

    b <= rgb_data[23:16];

end 

always@(*) 

begin

    if(!rst_n)

    begin

        gray_value  <= 16'd0;

    end

    else 

    begin

        gray_value <= 77 * r + 150 * g + 29 * b;

    end

end

assign gray_data = gray_value[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 [7: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               (                   ),

    .gray_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

3.2.3 实现效果分析

通过Matlab显示Verilog处理后的image_out.txt文件:

%********************************************************************** 

% -------------------------------------------------------------------

% Company: Cascatrix

% Engineer: Carson

%  

% Create Date: 2023/02/13

% Design Name: gray_display

% Module Name: gray_display

% Tool Versions: v1.0

% Description: Display Gray Image

%------------------------------------------------------------------- 

%*********************************************************************/

clear;clear all;clc;

% Image resolution

row = 1080;  

col = 1920;  

% Create output image

image_out = uint8(zeros(row,col));

% Write data into output image 

FileImage = fopen('image_out.txt','r');

for x = 1:row

    for y = 1:col

        Gray = fscanf(FileImage,'%s',1);

        image_out(x,y) = uint8(hex2dec(Gray(1:2)));             

    end 

end

fclose(FileImage);

% Show the output image

imshow(image_out),title('Image output');

% Create image in .jpg format

imwrite(image_out,'cascatrix_output.jpg');   

Matlab图像显示结果:

FPGA

  审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分