Matlab:为什么我不能使用 VideoWriter 创建 mp4 文件?

Matlab: Why can't I create an mp4 file using VideoWriter?

我想删除视频的背景。之后我想把它放到另一个视频中,然后将它另存为一个新的 mp4 文件。我正在使用 Windows 10 并且遇到以下问题,我无法在 运行 我的代码后创建新的 mp4 文件。

想法: 我有一辆后面有绿屏的车。我想把这辆车剪下来放在街拍前。 结果应该是一辆汽车在街上行驶(视频)。

来自 myScript 的代码:

clear
close all
v = VideoReader(fullfile('videos', 'carWithGreenscreen.mp4'));
s = VideoReader(fullfile('videos','street.mp4'));

video=zeros(v.Height,v.Width,3,floor(v.Duration/(1/v.FrameRate))-2,'uint8');
t=1;
car = 0.6 ;
values=[0;1;0];
while hasFrame(v)
    Img = im2double(readFrame(v));
    mask = sqrt((values(1)-Img(:, :, 1)).^2+(values(2)-Img(:, :, 2)).^2+(values(3)-Img(:, :, 3)).^2)<car;
    video(:,:,:,t) = imoverlay(im2uint8(Img),mask,[0 0 0]);
    imshow(video(:,:,:,t));
    t=t+1;
end

videoOut = VideoWriter('result.mp4','MPEG-4'); %here I want to create a video%
videoOut.FrameRate=v.FrameRate;
open(videoOut);
moveX=0;
for t=1:1:size(video,4)
    im = video(:,:,:,t);
    mask = im(:,:,1)+im(:,:,2)+im(:,:,3)==0;
    frame=imoverlay(readFrame(s),~mask,[0 0 0]);
    frame=frame+im;
    writeVideo(videoOut,frame);
    imshow(frame);
end
close(videoOut);

在我 运行 之后出现以下代码错误:

Error using myScript (line 27)
No more frames available to read from file.
line 27: frame=imoverlay(readFrame(s),~mask,[0 0 0]);

但最后它没有创建 mp4 文件...我用 avi 尝试过但我只创建了一个 0KB 的空 .avi 文件...

我设法重现了这个问题,它看起来像是一个 codec 问题。

我下载了 FFmpeg 命令行工具,并生成了示例(合成)视频:

对于 carWithGreenscreen.mp4,我 selected libxvid 编解码器:

ffmpeg -r 2.5 -f lavfi -i testsrc=rate=1:size=320x256 -t 10 -c:v libxvid videos/carWithGreenscreen.mp4

对于 street.mp4,我 selected libx264 编解码器:

ffmpeg -r 2.5 -f lavfi -i mandelbrot=rate=1:size=320x256 -t 10 -c:v libx264 videos/street.mp4

在 Windows 10 中的 MATLAB R2019a 中执行脚本时,我收到相同的错误消息:

Error using myScript (line 27)
No more frames available to read from file.

当我 select libxvid for street.mp4 时,脚本正在运行。

显然,MATLAB 对 h264 编解码器的支持是有限的。
根据文档,支持 h264 编解码器,但由于某种原因它无法正常工作,我找不到解决方案。


这是一个解决方法:

  • 使用 FFmpegstreet.mp4 转换为未压缩的 AVI。
    首选未压缩的 AVI 格式,因为没有转码(没有数据丢失)。
    (下载静态链接的最后一个稳定版本的 FFmpeg)。

您可以在 MATLAB 中执行 FFmpeg 以执行转换(将 ffmpeg 可执行文件与您的脚本放在同一文件夹后):

% Convert street.mp4 to street.avi (create uncompressed AVI video file)
[status, cmdout] = system(['ffmpeg -y -i ', fullfile('videos','street.mp4'), ' -c:v rawvideo -pix_fmt bgr24 ', fullfile('videos','street.avi')]);

if (status ~= 0)
    display(cmdout); % Displat cmdout in case of an error.
end

%Open street.avi instead of street.mp4
s = VideoReader(fullfile('videos','street.avi'));

这里是完整的修改代码:

clear
close all
v = VideoReader(fullfile('videos', 'carWithGreenscreen.mp4'));

%s = VideoReader(fullfile('videos','street.mp4'));

% Convert street.mp4 to street.avi (create uncompressed AVI video file)
[status, cmdout] = system(['ffmpeg -y -i ', fullfile('videos','street.mp4'), ' -c:v rawvideo -pix_fmt bgr24 ', fullfile('videos','street.avi')]);

if (status ~= 0)
    display(cmdout); % Displat cmdout in case of an error.
end

%Open street.avi instead of street.mp4
s = VideoReader(fullfile('videos','street.avi'));

video=zeros(v.Height,v.Width,3,floor(v.Duration/(1/v.FrameRate))-2,'uint8');
t=1;
car = 0.6 ;
values=[0;1;0];
while hasFrame(v)
    Img = im2double(readFrame(v));
    mask = sqrt((values(1)-Img(:, :, 1)).^2+(values(2)-Img(:, :, 2)).^2+(values(3)-Img(:, :, 3)).^2)<car;
    video(:,:,:,t) = imoverlay(im2uint8(Img),mask,[0 0 0]);
    imshow(video(:,:,:,t));
    t=t+1;
end

videoOut = VideoWriter('result.mp4','MPEG-4'); %here I want to create a video%
videoOut.FrameRate=v.FrameRate;
open(videoOut);
moveX=0;
for t=1:1:size(video,4)
    im = video(:,:,:,t);
    mask = im(:,:,1)+im(:,:,2)+im(:,:,3)==0;
    frame=imoverlay(readFrame(s),~mask,[0 0 0]);
    frame=frame+im;
    writeVideo(videoOut,frame);
    imshow(frame);
end
close(videoOut);

%Delete VideoReader objects (force closing the files).
v.delete();
s.delete();

最后一帧样本(两个合成模式的叠加):