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读取视频流文件的过程就是这样
---------------------
作者:粼粼小淇
来源:CSDN
原文:https://blog.csdn.net/lingyunxianhe/article/details/83543282
版权声明:本文为博主原创文章,转载请附上博文链接!