使用Matlab讀取視訊流檔案
阿新 • • 發佈:2018-11-01
Matlab中對影象和視訊流的讀取還是很方便的,但是由於不常用Matlab讀取視訊流(這傢伙處理能力較OpenCV還是慢些)偶有小忘,這次有在工作中遇到特此記錄一下,Matlab的help文件關於視訊流的讀取講解的比較少,但還好經過網上查閱和實踐做了一些整理,算是熟悉了,在讀取視訊這個過程主要用到了三個函式:1、VideoReader,這個也可以認為是個視訊讀取類,用於構造要讀取的視訊檔案;2、hasFrame函式用於判斷視訊中還有沒有幀,有就接著讀,沒有就退出;3、 readFrame用於讀取影象幀檔案;其他的函式不做解釋。直接上程式碼:
function Video2Image(VideoPath,ImageSaveFolder,ImNamePre,ImSpanNum) ImageSaveForm='.jpg'; ImStartId=20; ObjImSize=[480,640]; %獲取視訊資訊 vidObj= VideoReader(VideoPath); vidHeight = vidObj.Height; vidWidth = vidObj.Width; %創造一個儲存視訊的結構體 s = struct('cdata',zeros(vidHeight,vidWidth,3,'uint8'),... 'colormap',[]); %先把視訊每一幀資訊記錄下來 k = 1; while hasFrame(vidObj) s(k).cdata = readFrame(vidObj); k = k+1; end %把上面儲存的資訊寫入圖片中去 if ~exist(ImageSaveFolder,'dir') mkdir(ImageSaveFolder); end for i=ImStartId:ImSpanNum:k-1 %取出結構體中一張圖片資訊 Image=s(i).cdata; Image=imresize(Image,ObjImSize); %按指定格式儲存到指定的資料夾 ImageName=sprintf('%s-%d.%s',ImNamePre,i,ImageSaveForm); ImagePath=fullfile(ImageSaveFolder,ImageName); imwrite(Image,ImagePath); end end
下面舉一個我在讀取多個視訊的程式:
首先看一下我的檔案結構:每一個主資料夾下有三個子資料夾,每個子資料夾下又有四個視訊檔案:
因此要自動把主檔案下的三個子資料夾下的視訊流都自動讀取,程式如下:
%2018/09/18 by DQ function ExtractVideoIm() clc; close all; FanFolder='H:\BaiduNetdiskDownload\1-011'; ImSpanNum=30;%抽取視訊幀的間隔數 WindSiteName='YYMS'; SaveWindSiteFolder=fullfile('C:\Users\Administrator\Desktop\ImBigSet',WindSiteName);%%圖片儲存的主資料夾 if ~exist(SaveWindSiteFolder,'dir') mkdir(SaveWindSiteFolder); end [~,PreFanName,~] = fileparts(FanFolder); SaveFanFolder=fullfile(SaveWindSiteFolder,PreFanName); if ~exist(SaveFanFolder,'dir') mkdir(SaveFanFolder); end SplitStr=strsplit(PreFanName(2:end),'-'); FirstNum=SplitStr{1}; SecondNum=num2str(str2num(SplitStr{2})); FanName=strcat(FirstNum,'0',SecondNum); BladeFolderSet=dir(FanFolder); BladeFolderNum=length(BladeFolderSet); for i=3:BladeFolderNum BladeName=BladeFolderSet(i).name; SaveBladeFolder=fullfile(SaveFanFolder,BladeName); if ~exist(SaveBladeFolder,'dir') mkdir(SaveBladeFolder); end BladeFolder=fullfile(FanFolder,BladeName); VideoSet=dir(BladeFolder); VideoNum=length(VideoSet); for j=3:VideoNum VideoName=VideoSet(j).name; VideoNameNum=strsplit(VideoName(1:end-4),'_'); VideoId=VideoNameNum{2}; SaveVideoFolder=fullfile(SaveBladeFolder,VideoName); if exist(SaveVideoFolder,'dir') fprintf('%s existed,please check\n',SaveVideoFolder); return; else mkdir(SaveVideoFolder); end VideoPath=fullfile(BladeFolder,VideoName); ImNamePre=sprintf('%s%s-%s-%s',WindSiteName,FanName,BladeName,VideoId); Video2Image(VideoPath,SaveVideoFolder,ImNamePre,ImSpanNum); fprintf('Completely %s %s %s\n',PreFanName,BladeName,VideoName); end end end
好了至此就算完成了這些視訊流讀取儲存成圖片,但是啦在這中間又遇到了一些問題,程式能正確完成任務,主要是視訊流的讀取太他媽費時了,以至於有時cpu滿負荷,這應該不是matlab做的不好,估計是哪裡寫的不對。經過查閱終於找到了這個問題的根源,原始是提取視訊流中的這幾條句:
while hasFrame(vidObj)
s(k).cdata = readFrame(vidObj);
k = k+1;
end
這幾條語句因為記錄下所有視訊幀檔案,所以自然很消耗資源,這個我可是照著matlab中的Help文件來的,文件當然沒錯,只是在這裡不太合適,我們只需要提取視訊幀,沒不需要做一些其他處理,沒必要把這些資料儲存為matlab方便的資料格式,我們只需要讀一幀就儲存一下就好了,修改後的程式碼如下:
function Video2Image2(VideoPath,ImageSaveFolder,ImNamePre,ImSpanNum,StartId)
ImageSaveForm='.jpg';
ObjImSize=[480,640];
%獲取視訊資訊
vidObj= VideoReader(VideoPath);
%把上面儲存的資訊寫入圖片中去
if ~exist(ImageSaveFolder,'dir')
mkdir(ImageSaveFolder);
end
IsExtractPointStartId=false;%從指定的幀號開始提取圖片
CurFrameId=0;
PreFrameId=0;
while hasFrame(vidObj)
Image = readFrame(vidObj);
CurFrameId=CurFrameId+1;
if (~IsExtractPointStartId)&&(CurFrameId==StartId)
IsExtractPointStartId=true;
PreFrameId=CurFrameId;
Image=imresize(Image,ObjImSize);
%按指定格式儲存到指定的資料夾
ImageName=sprintf('%s-%d%s',ImNamePre,CurFrameId,ImageSaveForm);
ImagePath=fullfile(ImageSaveFolder,ImageName);
imwrite(Image,ImagePath);
continue;
end
if ((CurFrameId-PreFrameId)==ImSpanNum)
PreFrameId=CurFrameId;
Image=imresize(Image,ObjImSize);
%按指定格式儲存到指定的資料夾
ImageName=sprintf('%s-%d%s',ImNamePre,CurFrameId,ImageSaveForm);
ImagePath=fullfile(ImageSaveFolder,ImageName);
imwrite(Image,ImagePath);
end
end
end
好了,修改後的程式讀取視訊流還是比較快的,下面再附帶了一個讀取單個視訊流檔案的原始碼:
%2018/09/18 by DQ
%%從指定的幀號按指定間隔數抽取某單個視訊幀
function ExtractPointSingleVideoImForAnot22()
tic;
clc;
close all;
VideoFolder='H:\BaiduNetdiskDownload\YYMS\33\3';
VideoName='DJI_0057.mp4';
WindSiteName='SDB';
ImSpanNum=30;
StartId=10;
VideoNameNum=strsplit(VideoName(1:end-4),'_');
VideoId=VideoNameNum{2};
SplitCell=strsplit(VideoFolder,'\');
FanName=SplitCell{end-1};
BladeName=SplitCell{end};
SaveWindSiteFolder=fullfile('C:\Users\Administrator\Desktop\ImBigSet',WindSiteName);
if ~exist(SaveWindSiteFolder,'dir')
mkdir(SaveWindSiteFolder);
end
SaveFanFolder=fullfile(SaveWindSiteFolder,FanName);
if ~exist(SaveFanFolder,'dir')
mkdir(SaveFanFolder);
end
SaveBladeFolder=fullfile(SaveFanFolder,BladeName);
if ~exist(SaveBladeFolder,'dir')
mkdir(SaveBladeFolder);
end
SaveVideoFolder=fullfile(SaveBladeFolder,VideoName);
if exist(SaveVideoFolder,'dir')
fprintf('%s existed,please check\n',SaveVideoFolder);
return;
else
mkdir(SaveVideoFolder);
end
VideoPath=fullfile(VideoFolder,VideoName);
ImNamePre=sprintf('%s%s-%s-%s',WindSiteName,FanName,BladeName,VideoId);
Video2Image2(VideoPath,SaveVideoFolder,ImNamePre,ImSpanNum,StartId)
fprintf('Completely %s %s %s\n',FanName,BladeName,VideoName);
toc;
end
好了matlab讀取視訊流檔案的過程就是這樣