1. 程式人生 > >關於YUV視訊的讀取、播放,儲存幀圖片、以及處理的影象儲存為YUV視訊。

關於YUV視訊的讀取、播放,儲存幀圖片、以及處理的影象儲存為YUV視訊。

下面結合程式碼,總結一下這兩天掌握的內容。下面程式碼的功能,就是讀取YUV視訊指定幀的Y、U、V分量的值。通過這篇文章,會加深大家對YUV視訊如何儲存,以及MATLAB中檔案讀取功能的理解。

首先,讀入YUV視訊

function [Y,U,V]=yuv_import(filename,dims,numfrm,startfrm)
% filename 為待處理YUV視訊的名字。dims為視訊大小,numfrm,我們要儲存的幀數,startfrm,儲存視訊片段的起始幀。
fid=fopen(filename,'r');
if (fid < 0) 
    error('File does not exist!');
end;

filename是我們需要處理的yuv視訊,例如'foreman.cif',通過fid,獲得這個視訊的控制代碼,或者說是索引。我認為他的作用有定類似指標,通過fid,我們能定位到YUV視訊指定的地方。可以認為fid現在指向YUV視訊的最開始,也就是第一幀。如果不存在以filename命名的檔案,那麼fid為-1,如果存在,fid將是一個正數。

通過if語句,我們可以判斷是否存在指定的視訊,如果不存在,就提示'File does not exist!'的錯誤。

下面我們為儲存影象作準備

Yd = zeros(dims(1),dims(2));
UVd = zeros(dims(1)/2,dims(2)/2);

dims是影象的尺寸,格式為[M H],但是要注意的是,這裡的M,H分別表示影象的寬和高。對於cif格式,即為[352 288]。

通過下面的語句,我們定位到開始讀取影象的位置。

frelem = numel(Yd) + 2*numel(UVd);

if (nargin == 4) %go to the starting frame
    fseek(fid, startfrm * frelem , 0);
end;

frelem為YUV視訊中一幀影象總的畫素個數,至於為什麼這樣計算,大家需要首先了解下YUV格式,網上這方面的內容和諾,本篇文章先不作講解。

通過fseek,我們就實現了定位的目的。講一下fseek這個函式。 

    STATUS = fseek(FID, OFFSET, ORIGIN) repositions the file position
    indicator in the file associated with the given FID.  fseek sets the 
    position indicator to the byte with the specified OFFSET relative to 
    ORIGIN.
 
    FID is an integer file identifier obtained from FOPEN.
 
    OFFSET values are interpreted as follows:
        >= 0    Move position indicator OFFSET bytes after ORIGIN.
        < 0    Move position indicator OFFSET bytes before ORIGIN.
 
    ORIGIN values are interpreted as follows:
        'bof' or -1   Beginning of file
        'cof' or  0   Current position in file
        'eof' or  1   End of file

上面講的很清楚,這個函式通過OFFSET和ORIGIN定位FID所指向的位置。其中OFFSET代表移動的位置,>= 0,就從ORIGIN往後移動,相應的<0就往前移動。

ORGIN代表FID的起始位置。FID=-1,則指向檔案的開頭,FID = 0,指向當前位置,FID= 1,指向檔案的結尾。

通過上面的講解,fseek(fid, startfrm * frelem , 0);的作用就不難理解了,從當前位置,偏移startfrm幀影象,從而到達我們指定的起始幀。

準備工作完成,下面我們就可以讀取YUV視訊了。

Y = cell(1,numfrm);
U = cell(1,numfrm);
V = cell(1,numfrm);
for i=1:numfrm
    Yd = fread(fid,[dims(1) dims(2)],'uint8');
    Y{i} = Yd';   
    UVd = fread(fid,[dims(1)/2 dims(2)/2],'uint8');
    U{i} = UVd';
    UVd = fread(fid,[dims(1)/2 dims(2)/2],'uint8');
    V{i} = UVd';    
end;

這段程式碼比較好理解,就是讀取YUV視訊裡每一幀的Y、U、V分量並儲存。只有一點需要說明,就是轉置的問題。YUV視訊是這樣儲存的,他把所有的畫素值組成一個列向量。畫素值是這樣排序的,首先是Y分量的第一行畫素值,之後是第二行,一直存完第一幀影象Y分量所遇行的畫素值,然後再存U、V。所以這裡先取W*H個數據組成一個[w H]矩陣,之後再轉置。大家可以回去隨便找幾幅影象實驗一下,通過實驗就很好理解了。

這樣我們就讀出了指定幀的Y、U、V分量的值。我們可以分別imshow Y,U,C,分量,看看結果。

至於讀出的YUV資料怎麼轉化成RGB影象,以及處理後如何再儲存成YUV視訊,我們之後再進行講解。

PS:本文所指的視訊是常用的4:2:0格式的YUV視訊,如果格式不一樣,可能需要一點改動。