首页 > 其他分享 >RGB转YCbCr——基于《基于MATLAB与FPGA的图像处理教程》

RGB转YCbCr——基于《基于MATLAB与FPGA的图像处理教程》

时间:2023-12-01 17:15:37浏览次数:40  
标签:sys 基于 FPGA img Image per YCbCr post IMG1

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');

image.png

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

相关文章

  • XmlRPC入门_基于组合类型的客户端、服务端
    1、客户端#include<stdlib.h>#include<stdio.h>#include<xmlrpc-c/base.h>#include<xmlrpc-c/client.h>#include"config.h"/*informationaboutthisbuildenvironment*/#defineNAME"Xmlrpc-cTestClient"#d......
  • XmlRPC入门_基于C的服务端、客户端
    以下客户端与服务端的代码内容为官网给出的示例,此处拷贝记录,了解基础使用方式。1、服务端#include<iostream>#include<winsock2.h>#include<windows.h>#include"xmlrpc-c/base.h"#include"xmlrpc-c/server.h"#include"xmlrpc-c/server_abyss.h"#incl......
  • 基于AI的架构优化:创新数据集构造法提升Feature envy坏味道检测与重构准确率
    本文分享自华为云社区《华为云基于AI实现架构坏味道重构取得业界突破,相应文章已被软工顶会FSE2023收录》,作者:华为云软件分析Lab。基于AI技术实现架构坏味道检测与重构建议是当前业界比较流行的做法,但此做法往往存在一个通病,即训练数据集的质量问题,如何构建大规模、高质量的训练......
  • 软考架构师(15)——基于构件的开发
    一:构件与软件的重用1:软件重用软件重用(软件复用)是使用已有的软件产品(如设计、代码、文档等)来开发新的软件系统的过程。软件重用的形式大体可分为垂直式重用和水平式重用。水平式重用是重用不同应用领域中的软件元素,例如数据结构、排序算法、人机界面构件等。标准函数库是一种典......
  • 基于RK3568高性价比全国产EMS储能解决方案(一)概述
    储能产业链框架储能产业链可分为上游“原材料及生产设备”、中游“储能系统”、下游“储能场景应用及后市场服务”。图1储能产业链框架图产业链中游的“储能电池系统”主要包括“能量管理系统(EMS)”、“电池管理系统(BMS)”、“储能逆变器(PCS)”、“电池组”四个部分。电池组将......
  • ENTROFORMER: A TRANSFORMER-BASED ENTROPY MODEL基于transformer的熵模型
    目录简介模型核心代码性能实验简介\(\quad\)由于cnn在捕获全局依赖关系方面效率低,因此该文章提出了基于tansformer的熵模型——Entoformer;并针对图像压缩进行了top-kself-attention和adiamondrelativepositionencoding的优化;同时使用双向上下文模型加快解码。模型核心代......
  • 基于LSTM的股票价格预测模型【附源码】
    导语本文介绍了LSTM的相关内容和在股票价格预测上的应用。LSTM的股票价格预测LSTM(LongShortTermMemory)是一种特殊的RNN类型,同其他的RNNs相比可以更加方便地学习长期依赖关系,因此有很多人试图将其应用于时间序列的预测问题上。汇丰银行全球资产管理开发副总裁JakobAun......
  • 基于Lora的环境检测
    2023-11-301.两个灯闪烁出现了问题解决方法:程序中定时器分频系数和想要设置的分频系数少一位经验:LED灯闪烁出现问题很有可能是定时器分频系数或者重装载值因为大意敲错了2.软件模拟IIC3.宏定义如果一个对象(1)在程序中多次出现,而且后续可能会进行改动(一旦更改就会改好多......
  • 基于SpringBoot的在线视频教育平台-计算机毕业设计源码+LW文档
    一、选题背景及选题意义(国内外研究现状、初步设想及拟解决的问题):选题背景及意义:在线教育顾名思义,是以网络为介质的教学方式,通过网络,学员与教师即使相隔万里也可以开展教学活动;此外,借助网络课件,学员还可以随时随地进行学习,真正打破了时间和空间的限制,对于工作繁忙,学习时间不固定的......
  • 基于FPGA的图像白平衡算法实现,包括tb测试文件和MATLAB辅助验证
    1.算法运行效果图预览    2.算法运行软件版本vivado2019.2 matlab2022a 3.算法理论概述       FPGA(Field-ProgrammableGateArray)是一种可编程逻辑电路,可以通过编程实现各种算法,包括图像白平衡算法。图像白平衡算法是一种用于调整图像颜色温度的方法,......