OpenCVMatlab生成视频倒放功能
引言
相信不少朋友在各大短视频平台看到很多运动健身达人的训练视频,本人比较喜欢的运动达人有搬砖小伟
、大师兄欧克
等,街头徒手健身实则美妙,既能考验人的意志 ,又能强健体魄。不得不说,运动
(UFC竞技、武术、拳击)和艺术
(书法
、绘画、歌曲、舞蹈)着实能给人带来直观的真实体验,也能激发自身的运动潜力,对于经常久坐从事脑力运动的人,他们的闲暇时间除了关注科技、军事、生活娱乐,还应该接受艺术和体育的熏陶
,适当地进行体力劳动也是长寿的秘诀,有利于个人和社会的可持续发展。每天锻炼一小时,健康工作五十年,幸福生活一辈子!!!
1、需求分析
互联网上海量的文本(plain text)
、图片(picture or image)
、声音(audio)
、视频(video)
等文件大量涌入,层出不穷,这些数据在网络上存储、传输和下载,各种硬件设备、传感器技术的发展使得数据获取方式变得越来越多样化。这里关注视频文件,视频是由一系列连续的帧按照时间顺序组合排列而形成的,因此它的本质还是一个又一个帧,一个帧就是一个画面,一个画面就是一张图片,因此连续流畅的视频需要保证每秒的帧数大于等于24,而对于经常玩大型网络三维游戏(如吃鸡PLAYERUNKNOWN'S BATTLEGROUNDS
、CSGO
、CF
)的玩家而言,他们可能对这个更有了解,就是游戏实时画面都会显示当前帧率FPS(Frame Per Second,每秒的帧数),更高的帧率(普通电脑60以上,游戏本150~220,发烧本可能达到300)能给高端玩家带来精致的游戏体验。因此视频处理的本质源于对各张图片(每帧画面)的处理。
与此对应,视频倒放的核心思想就是将原始视频中的图片倒序,主要分为两个步骤:
(1)获取原始视频的每一帧图片以从小到大的序号命名后保存到本地
;
(2)将所有图片按照从大到小的顺序,设置与原始视频同样或自定义的帧率FPS,写入视频
。
2、环境配置(Win11+ VS 2015 + OpenCV 2.4.9 / Matlab R2021a)
Win 11 64位
Visual Studio 2015
OpenCV 2.4.9
Matlab R2021a
3、OpenCV实现视频倒放(C++)
3.1 输入原始视频(带声音)
原始视频文件VID_20210801_205259.mp4
展示了我国短跑飞人苏炳添在2020东京奥运会男子100米半决赛中以9.83秒刷新亚洲纪录,一站封神,他创造了亚洲人百米赛跑的记录,成为了首位跑进10秒大关的亚洲本土选手、首位踏上世界大赛百米飞人大战决赛的亚洲选手、亚洲纪录保持者。身高1米72的苏神在百米赛道上要比博尔特多跑7步,因此他只有付出比别人更多的努力,才能和其他选手站到同一起跑线上。让我们向苏神致敬,向苏神学习,功夫不负有心人,勇敢拼搏无极限,不设限的人生更精彩!!!
3.2 原始视频转声音(mp4转mp3)
不少带声音视频的后缀名往往都是.mp4
,那么如何获取里面的音频呢?其实有一种简单取巧的方法,只需将mp4
视频文件的后缀名.mp4
改为mp3
音频文件的后缀名.mp3
就可以了,实测证明该办法具有一定的有效性。
3.3 OpenCV代码
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
string GetFileNameString(string inputfilename)
{
string s = "";
int length = 0;
while (inputfilename[length] != '\0')
{
length++;
}
for (length = length - 1; length >= 0; length--)
{
if (inputfilename[length] == '\\')
break;
}
while (inputfilename[++length] != '\0')
{
if (inputfilename[length] != '.')
s += inputfilename[length];
else
break;
}
return s;
}
string GetFolderString(string inputfilename)//Obtain Path in FileNameWithPathString
{
string s = "";
int length = 0;
while (inputfilename[length] != '\0')
{
length++;
}
for (length = length-1; length >= 0; length--)
{
if (inputfilename[length] == '\\')
break;
}
for (int i = 0; i <= length; i++)
s += inputfilename[i];
return s;
}
string Replace_folder(string inputfilename) // replace \\ to /
{
string s = "";
int length = 0;
bool flag = true;
while (inputfilename[length] != '\0')
{
if (inputfilename[length] != '\\')
{
s += inputfilename[length];
}
else
{
s += '/';
}
length++;
}
return s;
}
int main()
{
string inputVideofilename = "F:\\Users\\VID_20210801_205259.mp4";
string videopath = GetFolderString(inputVideofilename);
string picspath = videopath + ("pics_" + GetFileNameString(inputVideofilename));
string command = "mkdir " + picspath;
system(command.c_str());//Create the folder which is named pics in current folder
string picfolder = Replace_folder(picspath) + "/", suffixname = ".jpg";
cout << "图片和视频保存位置为:"+picfolder << endl;
VideoCapture inputVideo(inputVideofilename);//Obtain input video
if (!inputVideo.isOpened())
{
cout << "Could not open the input video." << inputVideofilename << endl;
return -1;
}
else
{
double width = inputVideo.get(CV_CAP_PROP_FRAME_WIDTH); // width of frame
double height = inputVideo.get(CV_CAP_PROP_FRAME_HEIGHT); //height of frame
double frameRate = inputVideo.get(CV_CAP_PROP_FPS); //frame per second
double totalFrames = inputVideo.get(CV_CAP_PROP_FRAME_COUNT); //total number of frames
cout << "视频宽度=" << width << endl;
cout << "视频高度=" << height << endl;
cout << "视频总帧数=" << totalFrames << endl;
cout << "帧率=" << frameRate << endl;
namedWindow("RGB视频", CV_WINDOW_NORMAL);
namedWindow("B通道", CV_WINDOW_NORMAL);
namedWindow("G通道", CV_WINDOW_NORMAL);
namedWindow("R通道", CV_WINDOW_NORMAL);
namedWindow("被Canny后的视频", CV_WINDOW_NORMAL);
Mat lastframe;
int i = 0;
while (1)
{
Mat frame;// 定义一个Mat变量,用于存储每一帧的图像
inputVideo >> frame;//读取当前帧
if (frame.data)
{
i++;
int num_channels = frame.channels();//通道数
Mat channels[3];
split(frame, channels);
Mat zeroRChannel = channels[2].clone();//将R通道全部置0
zeroRChannel.setTo(0);
Mat zeroGChannel = channels[1].clone();//将G通道全部置0
zeroGChannel.setTo(0);
Mat zeroBChannel = channels[0].clone();//将B通道全部置0
zeroBChannel.setTo(0);
Mat BChannels[3] = { channels[0] , zeroGChannel , zeroRChannel };
Mat mergedBImage;
merge(BChannels, 3, mergedBImage);
Mat GChannels[3] = { zeroBChannel , channels[1] , zeroRChannel };
Mat mergedGImage;
merge(GChannels, 3, mergedGImage);
Mat RChannels[3] = { zeroBChannel , zeroGChannel , channels[2] };
Mat mergedRImage;
merge(RChannels, 3, mergedRImage);
Mat edges;
cvtColor(frame, edges, COLOR_BGR2GRAY);
blur(edges, edges, Size(5, 5));
Canny(edges, edges, 0, 30, 3);
imshow("RGB视频", frame);//显示当前帧
imshow("B通道", mergedBImage);
imshow("G通道", mergedGImage);
imshow("R通道", mergedRImage);
imshow("被Canny后的视频", edges);//显示经过处理后的当前帧
imwrite(picfolder + to_string(i) + suffixname, frame);
}
else
break;
waitKey(2);
}
cout << i << "张图片生成成功,开始逆序合成视频!" << endl;
Mat frame;
Mat class="lazy" data-src0 = imread(picfolder + to_string(i) + suffixname);
Size size = class="lazy" data-src0.size();
VideoWriter writer;
writer.open(Replace_folder(videopath) + GetFileNameString(inputVideofilename)+"_NiZhuan.avi", CV_FOURCC('M', 'J', 'P', 'G'), frameRate, size, true);
int j = i;
for (; j >0; j--)
{
string path = picfolder + to_string(j) + suffixname;
Mat class="lazy" data-src = imread(path);
if (!class="lazy" data-src.empty())
{
writer.write(class="lazy" data-src);
cout << "正在合成第" << j << "张照片" << endl;
}
else
break;
}
if (j == 0)
std::cout << "合成逆序视频 Successed!" << std::endl;
else
std::cout << "合成逆序视频 Failed!" << std::endl;
return 0;
}
}
3.4 OpenCV运行结果
(a)前20米
(b)后80米
(c)开始读取视频
(d)读取视频结束
(e)结果文件
(f)图片文件夹
代码支持mp4、wmv格式的输入视频,在原始视频文件夹中会看到生成的视频文件结果VID_20210801_205259_NiZhuan.avi,将avi
后缀名改为mp4
后缀名也可播放。
4、Matlab实现视频倒放
首先介绍一个Matlab生成动态视频示例:
Z = peaks;
surf(Z);
axis tight manual
set(gca,'nextplot','replacechildren');
v = VideoWriter('peaks.avi');
v.Quality = 95;
v.FrameRate = 40;
open(v);
for k = 1:200
surf(sin(2*pi*k/20)*Z,Z)
frame = getframe(gcf);
writeVideo(v,frame);
end
close(v);
4.1 Matlab代码
4.1.1 Matlab读取视频并播放(三选一)
vidObj = VideoReader('1234.wmv');
vidWidth = vidObj.Width;
vidHeight = vidObj.Height;
vidFps = vidObj.FrameRate;
% 第一种播放方式
while hasFrame(vidObj)
vidFrame = readFrame(vidObj);
imshow(vidFrame)
pause(1/vidObj.FrameRate);
end
% 第二种播放方式
currAxes = axes;
while hasFrame(vidObj)
vidFrame = readFrame(vidObj);
image(vidFrame, 'Parent', currAxes);
currAxes.Visible = 'off';
pause(1/vidFps);
end
% 第三种播放方式(推荐使用)
mov = struct('cdata',zeros(vidHeight,vidWidth,3,'uint8'),'colormap',[]);
vidObj.CurrentTime = 2.5; % 可设置开始时间
k = 1;
while hasFrame(vidObj)
mov(k).cdata = readFrame(vidObj);
imwrite(mov(k).cdata,['pics/', num2str(k),'.jpg']);
k = k+1;
end
hf = figure;
set(hf,'position',[90 60 vidWidth vidHeight]);
movie(hf,mov,1,vidFps);
4.1.2 Matlab读取视频并逆转
需要在原视频文件夹新建一个pics文件夹,然后运行以下代码(实测适用于.mp4和.wmv格式的输入视频文件
):VideoProcessTest.m
filepath = 'D:/Program Files (x86)/MATLAB/myworkspace/';
filename = 'VID_20210801_205259';
suffixname = '.mp4';
vidObj = VideoReader([filepath,filename,suffixname]);
vidWidth = vidObj.Width;
vidHeight = vidObj.Height;
vidFps = vidObj.FrameRate;
% vidObj.CurrentTime = 2.5; % 可设置开始时间
k = 1;
while hasFrame(vidObj)
frame = readFrame(vidObj);
imwrite(frame,['pics/', num2str(k),'.jpg']);
k = k+1;
end
v_all = VideoWriter([filepath,filename,'_NiZhuanMovie_ALL.avi']);
v_all.Quality = 95;
v_all.FrameRate = vidFps;
open(v_all);
v_rgb = VideoWriter([filepath,filename,'_NiZhuanMovie_RGB.avi']);
v_rgb.Quality = 95;
v_rgb.FrameRate = vidFps;
open(v_rgb);
v_r = VideoWriter([filepath,filename,'_NiZhuanMovie_R.avi']);
v_r.Quality = 95;
v_r.FrameRate = vidFps;
open(v_r);
v_g = VideoWriter([filepath,filename,'_NiZhuanMovie_G.avi']);
v_g.Quality = 95;
v_g.FrameRate = vidFps;
open(v_g);
v_b = VideoWriter([filepath,filename,'_NiZhuanMovie_B.avi']);
v_b.Quality = 95;
v_b.FrameRate = vidFps;
open(v_b);
set(gca,'nextplot','replacechildren');
for i = k-1:-1:1
filename = ['D:/Program Files (x86)/MATLAB/myworkspace/pics/', num2str(i),'.jpg'];
img = imread(filename);
[m,n]=size(img(:,:,1));
zero=zeros(m,n);
rgb_r=img(:,:,1);
rgb_g=img(:,:,2);
rgb_b=img(:,:,3);
R_img=cat(3,rgb_r,zero,zero);
G_img=cat(3,zero,rgb_g,zero);
B_img=cat(3,zero,zero,rgb_b);
RGB_img=cat(3,rgb_r,rgb_g,rgb_b);
subplot(2,2,1),imshow(R_img),title('红色分量');
subplot(2,2,2),imshow(G_img),title('绿色分量');
subplot(2,2,3),imshow(B_img),title('蓝色分量');
subplot(2,2,4),imshow(RGB_img);
frame = getframe(gcf);
imwrite(frame.cdata,['./pics/ALL',num2str(i),'.jpg']);
imwrite(RGB_img,['./pics/RGB',num2str(i),'.jpg']);
imwrite(R_img,['./pics/R',num2str(i),'.jpg']);
imwrite(G_img,['./pics/G',num2str(i),'.jpg']);
imwrite(B_img,['./pics/B',num2str(i),'.jpg']);
writeVideo(v_all,frame.cdata);
writeVideo(v_rgb,RGB_img);
writeVideo(v_r,R_img);
writeVideo(v_g,G_img);
writeVideo(v_b,B_img);
end
close(v_all);
close(v_rgb);
close(v_r);
close(v_g);
close(v_b);
4.2 Matlab运行结果
R分量
G分量
B分量
RGB视频
5、总结及应用
本文主要通过利用OpenCV和Matlab两种工具来实现视频中图片R、G、B三分量的提取、保存和逆转,同时视频加工本质是对图片帧的处理,利用这两种图像处理API还可实现视频截取
(通过帧率fps
和时间计算所需的帧并拼接成视频)、多张图片合成自定义视频
、多个视频拼接
、分类
、目标提取追踪
、特征检测
、视频边缘检测
、添加字幕
等功能,可应用于短视频剪辑、创作、应用系统演示、录课、科研、公共安全等多个领域。
到此这篇关于OpenCV Matlab生成倒放视频的文章就介绍到这了,更多相关OpenCV Matlab视频倒放内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341