原本想做视频动漫风格化的,动漫风格化要求图片色块分明,所以用到的是保边缘性极强的双边滤波,但由于双边滤波需要每张图片多次滤波才能出效果,等待时机较长,MATLAB处理循环的能力并不太适合。
事实上本篇文章主要就是教大家如何用matlab简单处理视频,因此我们选择较快的水彩风格化(简易版),但即使是这样长达一分钟的视频处理也足足耗了15分钟
使用VideoReader函数可以导入视频,用法如下(2012版以后的matlab支持VideoReader):
movObj=VideoReader(‘test.mp4’);
这样导入的便是一个结构体
我们可以使用
disp(movObj)
或者
get(movObj)
来查看结构体的属性:
VideoReader - 属性:
常规属性:
Name: ‘test.mp4’
Path: ‘E:\bin\matlabPS\edgeMovie’
Duration: 87.7480
CurrentTime: 0.0800
NumFrames: <正在计算…> 了解更多视频属性:
Width: 1920
Height: 1080
FrameRate: 25
BitsPerPixel: 24
VideoFormat: ‘RGB24’
其中比较重要的属性有:
for k=1:movObj.NumFrames
frame=read(movObj,k);
end
read(movObj,k)就是提取视频对象第k帧,而视频一共有movObj.NumFrames帧,这些都非常好理解。
水彩有一种晕开的感觉,所以我们选择不注重边缘的均值或高斯滤波,再将其与边缘结合
原图:
sobel卷积:
乘不乘以1.2其实差不多,当然也可以选择matlab自带的sobel边缘检测,不过那样的话边缘没有灰度的差异
ed_img=(255-sobelConv2_gray(rgb2gray(frame))).*1.2;
function sobelPic=sobelConv2_gray(oriPic)
Hx=[-1 0 1;-2 0 2;-1 0 1];
Hy=[1 2 1;0 0 0;-1 -2 -1];
[rows,cols]=size(oriPic);
exPic=uint8(zeros([rows+2,cols+2]));
exPic(2:rows+1,2:cols+1)=oriPic;
exPic(2:rows+1,1)=oriPic(:,1);
exPic(2:rows+1,cols+2)=oriPic(:,cols);
exPic(1,2:cols+1)=oriPic(1,:);
exPic(rows+2,2:cols+1)=oriPic(rows,:);
exPic(1,1)=oriPic(1,1);
exPic(rows+2,1)=oriPic(rows,1);
exPic(1,cols+2)=oriPic(1,cols);
exPic(rows+2,cols+2)=oriPic(rows,cols);
Gx=zeros([rows,cols]);Gy=Gx;
for ii=1:3
for jj=1:3
tempPic=double(exPic(ii:rows+ii-1,jj:cols+jj-1));
Gx=Gx+tempPic.*Hx(ii,jj);
Gy=Gy+tempPic.*Hy(ii,jj);
end
end
sobelPic=uint8(sqrt(Gx.^2+Gy.^2));
end
ga_img=imgaussfilt(frame,5);
newFrame=uint8(double(ga_img).*double(ed_img)./255);
制作新视频首先要用VideoWriter函数创建视频对象
newObj=VideoWriter(‘waterColorResult’);
视频名称为waterColorResult,这里视频格式默认为avi,如果想要mp4格式之类的其他格式,要设置profile属性,例如(mp4格式):
newObj=VideoWriter(‘waterColorResult’,‘MPEG-4’);
设置新视频帧率:
和原视频帧率相同
newObj.FrameRate=movObj.FrameRate;
打开视频对象,并将每一帧写入新视频对象
open(newObj)
for k=1:movObj.NumFrames
frame=read(movObj,k);
ga_img=imgaussfilt(frame,5);
ed_img=(255-sobelConv2_gray(rgb2gray(frame))).*1.2;
newFrame=uint8(double(ga_img).*double(ed_img)./255);
%下面这一行就是帧的写入
writeVideo(newObj,newFrame);
end
close(newObj)
理论上靠前四部已经能够制作出视频了,但是一个视频处理时间不短,我们需要一个进度显示的功能,类似下面这样:
close all;
fig=figure(1);
fig.NumberTitle='off';
for k=1:movObj.NumFrames
%一大堆操作
%。。。。。。
%。。。。。。
imshow(newFrame)
fig.Name=['Frame:[',num2str(k),'/',num2str(movObj.NumFrames),']'];
end
function waterColorMov
movObj=VideoReader('test.mp4');
newObj=VideoWriter('waterColorResult','MPEG-4');
newObj.FrameRate=movObj.FrameRate;
open(newObj)
close all;
fig=figure(1);
fig.NumberTitle='off';
tic
for k=1:movObj.NumFrames
frame=read(movObj,k);
ga_img=imgaussfilt(frame,5);
ed_img=(255-sobelConv2_gray(rgb2gray(frame))).*1.2;
newFrame=uint8(double(ga_img).*double(ed_img)./255);
writeVideo(newObj,newFrame);
imshow(newFrame)
fig.Name=['Frame:[',num2str(k),'/',num2str(movObj.NumFrames),']'];
end
toc
close(newObj)
function sobelPic=sobelConv2_gray(oriPic)
Hx=[-1 0 1;-2 0 2;-1 0 1];
Hy=[1 2 1;0 0 0;-1 -2 -1];
[rows,cols]=size(oriPic);
exPic=uint8(zeros([rows+2,cols+2]));
exPic(2:rows+1,2:cols+1)=oriPic;
exPic(2:rows+1,1)=oriPic(:,1);
exPic(2:rows+1,cols+2)=oriPic(:,cols);
exPic(1,2:cols+1)=oriPic(1,:);
exPic(rows+2,2:cols+1)=oriPic(rows,:);
exPic(1,1)=oriPic(1,1);
exPic(rows+2,1)=oriPic(rows,1);
exPic(1,cols+2)=oriPic(1,cols);
exPic(rows+2,cols+2)=oriPic(rows,cols);
Gx=zeros([rows,cols]);Gy=Gx;
for ii=1:3
for jj=1:3
tempPic=double(exPic(ii:rows+ii-1,jj:cols+jj-1));
Gx=Gx+tempPic.*Hx(ii,jj);
Gy=Gy+tempPic.*Hy(ii,jj);
end
end
sobelPic=uint8(sqrt(Gx.^2+Gy.^2));
end
end
当然如果不怕处理时间久的话可以尝试别的类型的风格化,and matlab 循环着实有点慢,其实可以考虑一下C++的。。。
原始视频:
链接:https://pan.baidu.com/s/1OMwX1MuDPr_558EBJZ3-FQ
提取码:jkt1