• 笔记——H264移植中从DDR读出的YUV数据处理


    待处理的数据

    图片中的数据是 720P YUV420YV12格式下,解码端在DDR存储的数据。这是第一个 BLOCK的数据(16*16像素),所以要有 Y值16*16个 ,UV 各有8*8个(由YUV44行列均隔行抽样得到YUV420格式)。如图中示意,16行Y,8行V,8行U。

    整个decoder_data_720p.txt中的数据是按 BLOCK 存储的,而且是按列遍历整张照片。一张720p(1280*720像素)照片的BLOCK示意图,即先存满BLOCK1,1~45,到第二行的BLOCK2,1~45。在解析时要注意存储顺序。

    问题来了:本来每个像素值应该是8bit,刚好2个十六进制数,但是由于FPGA系统内部的处理,每个值占了10bits 。因此如下的数据是需要解析bit的。

    图1 从DDR导出的待处理数据

    如何解析出数据呢?

    以第一行数据为例:300c0300c0300c0300c0300c0300c0300c0300c0,16个Y值,有16*10 bits(高8位有效,补2个0) = 20 Byte 数据。

    假设给第一行数据按字节编号:B0B1B2...B19。可以看出每5个字节呈现出一定的规律,阴影表示补的0。20Byte/5 = 4次循环。

    从单行来看像素Y值,

    Y0 = B0,

    Y1高4位数据 = (B1>>2)<<4,Y1低4位数据 = (B1&0x03) + (B2>>6)&0x03 (这里要注意右移时最高位是否市符号位拓展,保险起见 &0X03), Y1=Y1高4位数据 +Y1低4位数据。

    Y2 = B2<<4 + B3>>4

    Y3 = (B3&0x03)<<6 + (B4>>2)

    ...

    这样循环4次就能遍历一行,取出16个Y值。

    其他UV等数据类似取出。

     

    看看如何取出1个BLOCK?

    读取数据

    posy = 1;posv = 2;posu = 3; %根据数据来定义的顺序

    inblock = zeros(16,20,3);
    inblock(:,:,posy) = fscanf(fid_txtin,'%02x',[20 16])';
    tempuv = fscanf(fid_txtin,'%02x',[20 8])';
    

     取出V,前10列数据是V,然后补满 inblock 其他位置,方便处理。

    inblock(1:8,1:10,posv) = tempuv(1:8,1:10); 
    inblock(1:8,11:20,posv) = tempuv(1:8,1:10);
    inblock(9:16,:,posv) = inblock(1:8,:,posv); 

    取出U,后10列数据是U,然后补满 inblock 其他位置,方便处理。

    inblock(1:8,1:10,posu) = tempuv(1:8,11:20);
    inblock(1:8,11:20,posu) = inblock(1:8,1:10,posu);
    inblock(9:16,:,posu) = inblock(1:8,:,posu);
    inblock = uint8(inblock); 

    这样YUV的数据按相应位置存储到数组 inblock里面了。维度 16x20。

    解析inblock的数据 存入到 imgblock,分别解析 YUV数据。列遍历时(每次循环5个字节),解析出4个YUV值。解释见上面的字节图形说明。

    imgblock = zeros(16,16,3);
    for yuv=1:3
        for row=1:16
            incol = 1;
            for column=1:4:16
                %
                imgblock(row,column+0,yuv) = inblock(row,incol+0,yuv); 
                %
                tempH = bitshift(inblock(row,incol+1,yuv),-2);
                tempH = bitshift(tempH,4);
                tempL = bitand(inblock(row,incol+1,yuv),3);
                tempL = bitshift(tempL,2);
                tempL = tempL + bitshift(inblock(row,incol+2,yuv),-6);
                temp = tempH+tempL;
                imgblock(row,column+1,yuv) = temp;
                %
                tempH = bitshift(inblock(row,incol+2,yuv),4);
                tempL = bitshift(inblock(row,incol+3,yuv),-4);
                temp = tempH+tempL;
                imgblock(row,column+2,yuv) = temp;    
                %
                tempH = bitand(inblock(row,incol+3,yuv),3);
                tempH = bitshift(tempH,6);
                tempL = bitshift(inblock(row,incol+4,yuv),-2);
                temp = tempH + tempL;
                imgblock(row,column+3,yuv) = temp;  
                incol = incol+5;
            end
        end
    end
    

    取出解析后的一个BLOCK YUV数据,fliplr 用于将矩阵对折,这个是和李师兄对数据时,发现的其输出的数据格式问题。

    tempy = imgblock(:,:,1);
    tempu = imgblock(1:8,1:8,posu);
    tempv = imgblock(1:8,1:8,posv);
    tempy = fliplr(tempy);
    tempu = fliplr(tempu);
    tempv = fliplr(tempv);
    

     如: tempv值如下,

     

    对折后:

    存下每 16行中所有列的BLOCK数据

    Y = [Y tempy];
    U = [U tempu];
    V = [V tempv];

    对这16行的BLOCK数据整理,以保证与输出数据的格式对应。 Y0,Y1,Y2...

    Y = uint8(Y)';
    Y = reshape(Y,1,16*16*Vs/16);
    U = uint8(U)';
    U = reshape(U,1,16*16*Vs/16/4);
    V = uint8(V)';
    V = reshape(V,1,16*16*Vs/16/4);  

     存下所有行的数据

    YY = [YY Y];
    UU = [UU U];
    VV = [VV V];
    

      

    处理数据的Matlab完整代码

    %
    % 2016-01-18 hy
    %   1.读取文本中的第一个BLOCK,数据为4:2:0的YUV数据
    %   2.从文本中取出Y,U,V的数据,然后输出到 *.yuv文件,
    % 用软件 “7yuv”打开,调整格式为 YVU420 planar YV12 可正常显示
    %   3.运行程序时,注意修改输入、输出数据的文件名。
    %   4.本程序读入的是一张完整的720p的图片数据,要用于1080P需要略作修改
    %
    %  这个420的转换显示脚本先修改图片尺寸Vs*Hs (720P或1080P),
    % 然后直接运行,点击选择输入文件(不必拷贝到当前目录下),即可等待运行结果
    clc;close all;clear 
    
    %%
    % rgb2ycbcr
    posy = 1;posv = 2;posu = 3; %根据数据来定义的顺序
    
    %%通过 GUI 选择 *.txt 输入文件
    [FileName, PathName, FilterIndex] = uigetfile('*.txt');
    filename = [PathName,FileName]  
    fid_txtin = fopen(filename,'r');
    %
    %86400/24 = 3600
    %%
    %!!!!
    %%请更改图像对应的尺寸Vs*Hs
    FRAME_NUM = 1            %%帧数, txt文件中有几帧yuv数据
    % Hs = 96; Vs = 128;       %%128*96
    Hs = 720; Vs = 1280;    %%720p
    % Hs = 1080;Vs = 1920;   %%1080p
    Hs = FRAME_NUM*Hs
    Vs = FRAME_NUM*Vs
    YY = []; UU=[]; VV=[]; 
    for rcount = 1:Hs/16            %45*16 = 720 如果是1080P的照片请修改45为 1080/16=67
        Y = []; U=[]; V=[];
        for colcount = 1:Vs/16      %80*16=1280 如果是1080P的照片请修改80为 1920/16=120
            inblock = zeros(16,20,3);
            inblock(:,:,posy) = fscanf(fid_txtin,'%02x',[20 16])';
            tempuv = fscanf(fid_txtin,'%02x',[20 8])';
            %inblock(1:8,:,posv) = fscanf(fid_txtin,'%2x',[8 20]);
    
            inblock(1:8,1:10,posv) = tempuv(1:8,1:10); 
            inblock(1:8,11:20,posv) = tempuv(1:8,1:10);
            inblock(9:16,:,posv) = inblock(1:8,:,posv);
    
            inblock(1:8,1:10,posu) = tempuv(1:8,11:20);
            inblock(1:8,11:20,posu) = inblock(1:8,1:10,posu); 
            inblock(9:16,:,posu) = inblock(1:8,:,posu);
            inblock = uint8(inblock);
            % Y = inblock(:,:,posy);
            % U = inblock(:,:,posu);
            % V = inblock(:,:,posv);
            %%
            imgblock = zeros(16,16,3);
            for yuv=1:3
                for row=1:16
                    incol = 1;
                    for column=1:4:16
                        %
                        imgblock(row,column+0,yuv) = inblock(row,incol+0,yuv); 
                        %
                        tempH = bitshift(inblock(row,incol+1,yuv),-2);
                        tempH = bitshift(tempH,4);
                        tempL = bitand(inblock(row,incol+1,yuv),3);
                        tempL = bitshift(tempL,2);
                        tempL = tempL + bitshift(inblock(row,incol+2,yuv),-6);
                        temp = tempH+tempL;
                        imgblock(row,column+1,yuv) = temp;
                        %
                        tempH = bitshift(inblock(row,incol+2,yuv),4);
                        tempL = bitshift(inblock(row,incol+3,yuv),-4);
                        temp = tempH+tempL;
                        imgblock(row,column+2,yuv) = temp;    
                        %
                        tempH = bitand(inblock(row,incol+3,yuv),3);
                        tempH = bitshift(tempH,6);
                        tempL = bitshift(inblock(row,incol+4,yuv),-2);
                        temp = tempH + tempL;
                        imgblock(row,column+3,yuv) = temp;  
                        incol = incol+5;
                    end
                end
            end
            tempy = imgblock(:,:,1);
            tempu = imgblock(1:8,1:8,posu);
            tempv = imgblock(1:8,1:8,posv);
            tempy = fliplr(tempy);
            tempu = fliplr(tempu);
            tempv = fliplr(tempv);
            Y = [Y tempy];
            U = [U tempu];
            V = [V tempv];
            %tempy = uint8(imgblock(:,:,1))';
            %tempy = reshape(tempy,1,16*16);
            %tempu = uint8(imgblock(:,:,2))';
            %tempu = reshape(tempu,1,16*16);
            %tempv = uint8(imgblock(:,:,3))';
            %tempv = reshape(tempv,1,16*16);
        end
        Y = uint8(Y)';
        Y = reshape(Y,1,16*16*Vs/16);
        U = uint8(U)';
        U = reshape(U,1,16*16*Vs/16/4);
        V = uint8(V)';
        V = reshape(V,1,16*16*Vs/16/4);
        YY = [YY Y];
        UU = [UU U];
        VV = [VV V];
    end
    fclose(fid_txtin);
    
    % % imgYUV = uint8(cat(3,Y,U,V));
    % % imgRGB = ycbcr2rgb(imgYUV);
    % % imshow(imgRGB(1:16,:));
    
    %%
    % 输出数据的文件名
    % datestr(now) 获取时间函数
    %
    filename_out = ['yuvout_',datestr(now,30),'.yuv'] %
    fid_txtout = fopen(filename_out,'wb');
        fwrite(fid_txtout,YY,'uint8');
        fwrite(fid_txtout,VV,'uint8');
        fwrite(fid_txtout,UU,'uint8');
    fclose(fid_txtout);
    filename_buff = 'yuvout_dispbuff.yuv'
    cmd_str = ['copy ',filename_out,' ',filename_buff]
    dos(cmd_str)
    % yuvpath = [pwd,'\',filename_buff]
    cmd_str = ['7yuv.exe ',filename_buff]  %%添加7yuv 路径工具到用户环境变量
    dos(cmd_str)
    

      

    %
    % 2016-01-18
    %   1.读取文本中的第一个BLOCK,数据为4:2:0的YUV数据
    %   2.从文本中取出Y,U,V的数据,然后输出到 *.yuv文件,
    % 用软件 “7yuv”打开,调整显示格式为 YVU420 planar YV12 可正常显示
    %   3.运行程序时,注意修改输入、输出数据的文件名。
    %   4.本程序读入的是一张完整的720p的图片数据,要用于1080P需要略作修改
    %
    %
    clc;close all;clear 
    
    %%
    % rgb2ycbcr
    posy = 1;posv = 2;posu = 3; %根据数据来定义的顺序
    %
    % 输入数据的文件名
    filename = 'huyong.txt';  
    fid_txtin = fopen(filename,'r');
    %
    %86400/24 = 3600
    
    Hs = 720; Vs = 1280; %%720p
    % Hs = 1080;Vs = 1920; %%1080p
    YY = []; UU=[]; VV=[]; 
    for rcount = 1:Hs/16  %45*16 = 720 如果是1080P的照片请修改45为 1080/16=67
        Y = []; U=[]; V=[];
        for colcount = 1:Vs/16 %80*16=1280 如果是1080P的照片请修改80为 1920/16=120
            inblock = zeros(16,20,3);
            inblock(:,:,posy) = fscanf(fid_txtin,'%02x',[20 16])';
            tempuv = fscanf(fid_txtin,'%02x',[20 8])';
            %inblock(1:8,:,posv) = fscanf(fid_txtin,'%2x',[8 20]);
    
            inblock(1:8,1:10,posu) = tempuv(1:8,1:10); 
            inblock(1:8,11:20,posu) = tempuv(1:8,1:10);
            inblock(9:16,:,posu) = inblock(1:8,:,posu);
    
            inblock(1:8,1:10,posv) = tempuv(1:8,11:20);
            inblock(1:8,11:20,posv) = inblock(1:8,1:10,posv) ; 
            inblock(9:16,:,posv) = inblock(1:8,:,posv);
            inblock = uint8(inblock);
            % Y = inblock(:,:,posy);
            % U = inblock(:,:,posu);
            % V = inblock(:,:,posv);
            %%
            imgblock = zeros(16,16,3);
            for yuv=1:3
                for row=1:16
                    incol = 1;
                    for column=1:4:16
                        %
                        imgblock(row,column+0,yuv) = inblock(row,incol+0,yuv); 
                        %
                        tempH = bitshift(inblock(row,incol+1,yuv),-2);
                        tempH = bitshift(tempH,4);
                        tempL = bitand(inblock(row,incol+1,yuv),3);
                        tempL = bitshift(tempL,2);
                        tempL = tempL + bitshift(inblock(row,incol+2,yuv),-6);
                        temp = tempH+tempL;
                        imgblock(row,column+1,yuv) = temp;
                        %
                        tempH = bitshift(inblock(row,incol+2,yuv),4);
                        tempL = bitshift(inblock(row,incol+3,yuv),-4);
                        temp = tempH+tempL;
                        imgblock(row,column+2,yuv) = temp;    
                        %
                        tempH = bitand(inblock(row,incol+3,yuv),3);
                        tempH = bitshift(tempH,6);
                        tempL = bitshift(inblock(row,incol+4,yuv),-2);
                        temp = tempH + tempL;
                        imgblock(row,column+3,yuv) = temp;  
                        incol = incol+5;
                    end
                end
            end
            tempy = imgblock(:,:,1);
            tempu = imgblock(1:8,1:8,2);
            tempv = imgblock(1:8,1:8,3);
            tempy = fliplr(tempy);
            tempu = fliplr(tempu);
            tempv = fliplr(tempv);
            Y = [Y tempy];
            U = [U tempu];
            V = [V tempv];
            %tempy = uint8(imgblock(:,:,1))';
            %tempy = reshape(tempy,1,16*16);
            %tempu = uint8(imgblock(:,:,2))';
            %tempu = reshape(tempu,1,16*16);
            %tempv = uint8(imgblock(:,:,3))';
            %tempv = reshape(tempv,1,16*16);
        end
        Y = uint8(Y)';
        Y = reshape(Y,1,16*16*Vs/16);
        U = uint8(U)';
        U = reshape(U,1,16*16*Vs/16/4);
        V = uint8(V)';
        V = reshape(V,1,16*16*Vs/16/4);
        YY = [YY Y];
        UU = [UU U];
        VV = [VV V];
    end
    fclose(fid_txtin);
    
    % imgYUV = uint8(cat(3,Y,U,V));
    % imgRGB = ycbcr2rgb(imgYUV);
    % imshow(imgRGB(1:16,:));
    
    %%
    %输出数据的文件名
    fid_txtout = fopen('huyong_out_24.yuv','wb');
        fwrite(fid_txtout,YY,'uint8');
        fwrite(fid_txtout,VV,'uint8');
        fwrite(fid_txtout,UU,'uint8');
    fclose(fi
    •  7yuv的显示

     

    图2 用7yuv打开输出的 *.yuv文件  

  • 相关阅读:
    Android中echarts使用
    小程序搜索定位导航
    去除数组对象中的某属性相同时删除整个对象
    小程序rtmp监控视频播放
    小程序定义优惠券样式
    小程序购物车实现
    JavaScript Cookie
    JqueryValidate使用
    oracel 创建表空间、用户、导入数据库
    跨域访问Jquery实现[转]
  • 原文地址:https://www.cnblogs.com/hythink/p/5225025.html
Copyright © 2020-2023  润新知