首页 > 其他分享 >fpga图像处理实战-YCBCR转RGB

fpga图像处理实战-YCBCR转RGB

时间:2024-08-09 08:54:36浏览次数:15  
标签:fpga img bmp YCBCR RGB valid IMG 128 reg

计算公式   

    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

相关文章

  • 【教程4>第3章>第5节】8ASK解调系统的FPGA开发与matlab验证
    本课程学习成果预览 欢迎订阅FPGA/MATLAB/Simulink系列教程《★教程1:matlab入门100例》《★教程2:fpga入门100例》《★教程3:simulink入门60例》《★教程4:FPGA/MATLAB/Simulink联合开发入门与进阶X例》目录1.软件版本2.8ASK解调理论简介3.8ASK解调过程的MATLA......
  • 第6章>>实验6:PS(ARM)端Linux RT与PL端FPGA之间(通过Reg寄存器进行通信和交互)-《LabVIEW Z
    1、实验内容       前面第五章入门实验和上一个实验5里面我们向大家展示通过了布尔类型的Reg寄存器通道实现了ZYNQPS端ARM和PL端FPGA二者之间的开关量交互,抛砖引玉。       从本节实验开始,接下来4个实验我们将着重向大家讲解更为通用和更为全面的4种交互方......
  • FPGA设计之跨时钟域(CDC)设计篇(5)----同步FIFO的两种设计方法(计数器法/高位扩展法 | 手撕
    1、什么是FIFO?        FIFO(FirstInFirstOut)是一种先进先出的数据缓存器,在逻辑设计里面用的非常多。它是一种存储器结构,被广泛应用于芯片设计中。FIFO由存储单元队列或阵列构成,第一个被写入队列的数据也是第一个从队列中读出的数据。        FIFO设计可......
  • FPGA MIPI DSI LCD彩条显示
    1MIPI简介MIPI(MobileIndustryProcessorInterface)是一种针对移动设备和嵌入式系统的接口标准,由MIPI联盟制定。其主要目的是提高移动设备之间的通信效率,降低功耗,并支持高速数据传输。MIPI的主要标准包括:MIPIDSI(DisplaySerialInterface):用于连接显示模块,支持高清视......
  • GD32使用PWM+DMA调试WS2812-RGB灯调试记录(附GD32中的TIMER定时器和DMA的踩坑记录)
    一、前言目的:对于使用STM32驱动WS2812-RGB灯,已经有很多大佬进行了分享,同时写得很好!但是对于GD32的调试WS2812确实偏少,刚好最近的项目有用到,顺便记录一下踩过的坑。开源不易,谢谢大家!感谢:特别感谢三位大佬的的博文贡献;1.GD32F470通过DMA输出PWM_gd32pwmdma-CSDN博客2.基于G......
  • FPGA知识基础之--500ms计数器,边沿检测,按键消抖
    目录前言一、边沿检测1.1使用背景1.2方法:打拍法1.2.1背景1.2.2原理1.2.3上升沿二、计数器2.1原理2.2RTL代码三、按键消抖前言一、边沿检测1.1使用背景在我们设计电路时,经常会遇到需要继续检测上升沿和下降沿的电路,因此需要对边沿继续检测1.2方法:打......
  • 基于FPGA的出租车计费系统设计---第一版--郝旭帅电子设计团队
    欢迎各位朋友关注“郝旭帅电子设计团队”,本篇为各位朋友介绍基于FPGA的出租车计费系统设计---第一版 功能说明:    1.收费标准(里程):起步价5元,包括三公里;三公里之后,每公里2元(不到一公里,不收费)。   2.收费标准(低速等待费):当计费开始,车辆速度低于某一速度时,开始收取......
  • 如何在 PySpark 中将二进制图像数据转换为 RGB 数组?
    我有一个具有以下架构的pysparkdf:root|--array_bytes:binary(nullable=true)我希望能够将其转换为图像数组。我可以使用以下代码在Pandas中完成此操作:df_pandas=df.toPandas()defbytes_to_array(byte_data):arr=np.frombuffer(byte_data,dtype=np......
  • FPGA开发——按键控制LED的实现
    一、概述在上一篇文章中我们学习了按键的相关消抖及其使用,在这篇文章当中我们就针对通过按键实现LED的控制。1、按键原理图2、基本框架通过我们前面编写的按键消抖的文件和LED文件将按键和LED两个模块进行交互,从而达到按键控制LED的目的。 二、代码编写1、首先是按键......
  • FPGA开发——数码管的使用(二)
    一、概述   在上一篇文章中我们针对单个数码管的静态显示和动态显示进行了一个设计和实现,这篇文章中我们针对多个数码管同时显示进行一个设计。这里和上一篇文章唯一不同的是就是数码管位选进行了一个改变,原来是单个数码管的显示,所以位选就直接赋值就可以了,但在本篇文章......