我想编写一个程序,将视频作为输入,创建一个输出视频文件,并且(在一定数量的帧之后开始),开始逐帧地将修改后的帧写入输出文件。 修改将需要一次一个地处理单个像素列。
将此视为Matlab中要解决的问题,将每个帧作为矩阵......我想不出一种方法可以使这个计算易于处理。 我希望有人可以就如何开始解决这个问题提出建议。
以下是一些细节,如果它有帮助:
我对以下列方式转换视频感兴趣:
将视频视为一系列(MxN)矩阵,其中每个矩阵称为frame
:
frame(i + V - N)
中的第V列。例如:框架(i)的新的最右列(列N)将包含frame(i + N - N) = frame(i)...
的列N,因此没有替换。框架(i)的新的第2列到最右列(第N-1列)将包含[frame(i+N-1-N) = frame(i-1)]
的第N-1列。
为了使这项工作(即为了不用完前一帧),此列替换将从视频的第N帧开始。
答案 0 :(得分:2)
那么......这基本上是一个从左到右运行的可变延迟?
正如你所说,你有两种解决方法:
a)使用大量内存 b)使用大量文件访问
您的内存需求随着视频大小的立方体功率而增加 - 每帧的大小增加,以及您需要打开或引用的前一帧数量增加。即加倍帧大小将需要每帧4x内存,并打开2x帧数。
我认为Matlab的内存管理可能会让人很难做到这一点。 1080p视频,除非你有一个漂亮的高端工作站。你呢?对720p视频的快速测试读取每帧1.2MB。那么1080p每帧约为5MB,你需要打开1920帧:需要大约10GB。
如果没有足够的内存,单独加载帧会更有效 - 否则你将使用页面文件,这比逐帧加载要慢。
您单独阅读每个框架的基本代码可能是这样的:
VR=VideoReader('My_Input_Video_Filename.avi');
VW=VideoWriter('My_Output_Video_Filename.avi','MPEG-4');
NumInFrames=get(VR,'NumberOfFrames');
InWidth=get(VR,'Width');
InHeight=get(VR,'Height');
OutFrame=zeros(InHeight,InWidth,3,'uint8');
for (frame=InWidth+1:NumInFrames)
for (subindex=1:InWidth)
CData=read(VR,frame-subindex);
OutFrame(:,subindex,:)=CData(:,subindex,:);
end
writeVideo(VW,OutFrame);
end
这可能会很慢,我还没有完全检查它是否有效,但确实使用了最少的内存。
最小文件访问的最佳情况可能是使用环形缓冲区排列和最大内存量,如下所示:
VR=VideoReader('My_Input_Video_Filename.avi');
VW=VideoWriter('My_Output_Video_Filename.avi','MPEG-4');
NumInFrames=get(VR,'NumberOfFrames');
InWidth=get(VR,'Width');
InHeight=get(VR,'Height');
CDatas=read(VR,InWidth);
BufferIndex=1;
OutFrame=zeros(InHeight,InWidth,3,'uint8');
for (frame=InWidth+1:NumInFrames)
CDatas(:,:,:,BufferIndex)=read(VR,frame);
tempindices=circshift(1:InWidth,[1,-1*BufferIndex]);
for (subindex=1:InWidth)
OutFrame(:,subindex,:)=CDatas(:,subindex,:,tempindices(subindex));
end
writeVideo(VW,OutFrame);
BufferIndex=mod(BufferIndex+1,InWidth);
end
缓冲区索引代码可能需要在那里进行一些调整,但沿着这些行的东西将是最小文件访问,最大内存使用解决方案。
对于具有更多或更少内存的给定PC,您可以在这两者之间实现某种解决方案(即在每次迭代中读取1到所有帧之间的某处)作为最佳情况。
对于这类任务来说,Matlab会很慢,但这将是一个很好的方法,可以让你的算法正确并找出索引错误和类似的东西。转换为编译语言可以大大提高速度 - 我在几个小时内将Matlab脚本转换为C#程序,并且比优化脚本的速度提高了10倍,其中所用的时间是文件读取次数希望这有帮助,祝你好运!