OpenCV Matlab生成視頻倒放功能
引言
相信不少朋友在各大短視頻平臺看到很多運動健身達人的訓練視頻,本人比較喜歡的運動達人有搬磚小偉、大師兄歐克等,街頭徒手健身實則美妙,既能考驗人的意志 ,又能強健體魄。不得不說,運動(UFC競技、武術、拳擊)和藝術(書法、繪畫、歌曲、舞蹈)著實能給人帶來直觀的真實體驗,也能激發(fā)自身的運動潛力,對于經常久坐從事腦力運動的人,他們的閑暇時間除了關注科技、軍事、生活娛樂,還應該接受藝術和體育的熏陶,適當地進行體力勞動也是長壽的秘訣,有利于個人和社會的可持續(xù)發(fā)展。每天鍛煉一小時,健康工作五十年,幸福生活一輩子?。。?/p>
1、需求分析
互聯網上海量的文本(plain text)、圖片(picture or image)、聲音(audio)、視頻(video)等文件大量涌入,層出不窮,這些數據在網絡上存儲、傳輸和下載,各種硬件設備、傳感器技術的發(fā)展使得數據獲取方式變得越來越多樣化。這里關注視頻文件,視頻是由一系列連續(xù)的幀按照時間順序組合排列而形成的,因此它的本質還是一個又一個幀,一個幀就是一個畫面,一個畫面就是一張圖片,因此連續(xù)流暢的視頻需要保證每秒的幀數大于等于24,而對于經常玩大型網絡三維游戲(如吃雞PLAYERUNKNOWN'S BATTLEGROUNDS、CSGO、CF)的玩家而言,他們可能對這個更有了解,就是游戲實時畫面都會顯示當前幀率FPS(Frame Per Second,每秒的幀數),更高的幀率(普通電腦60以上,游戲本150~220,發(fā)燒本可能達到300)能給高端玩家?guī)砭碌挠螒蝮w驗。因此視頻處理的本質源于對各張圖片(每幀畫面)的處理。
與此對應,視頻倒放的核心思想就是將原始視頻中的圖片倒序,主要分為兩個步驟:
(1)獲取原始視頻的每一幀圖片以從小到大的序號命名后保存到本地;
(2)將所有圖片按照從大到小的順序,設置與原始視頻同樣或自定義的幀率FPS,寫入視頻。
2、環(huán)境配置(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秒刷新亞洲紀錄,一站封神,他創(chuàng)造了亞洲人百米賽跑的記錄,成為了首位跑進10秒大關的亞洲本土選手、首位踏上世界大賽百米飛人大戰(zhàn)決賽的亞洲選手、亞洲紀錄保持者。身高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 src0 = imread(picfolder + to_string(i) + suffixname);
Size size = 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 src = imread(path);
if (!src.empty())
{
writer.write(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生成動態(tài)視頻示例:

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和時間計算所需的幀并拼接成視頻)、多張圖片合成自定義視頻、多個視頻拼接、分類、目標提取追蹤、特征檢測、視頻邊緣檢測、添加字幕等功能,可應用于短視頻剪輯、創(chuàng)作、應用系統(tǒng)演示、錄課、科研、公共安全等多個領域。
到此這篇關于OpenCV Matlab生成倒放視頻的文章就介紹到這了,更多相關OpenCV Matlab視頻倒放內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
json格式解析和libjson的用法介紹(關于cjson的使用方法)
下面小編就為大家?guī)硪黄猨son格式解析和libjson的用法介紹(關于cjson的使用方法)。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-12-12

