OpenCV Matlab生成視頻倒放功能
引言
相信不少朋友在各大短視頻平臺看到很多運動健身達人的訓練視頻,本人比較喜歡的運動達人有搬磚小偉
、大師兄歐克
等,街頭徒手健身實則美妙,既能考驗人的意志 ,又能強健體魄。不得不說,運動
(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 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生成動態視頻示例:
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視頻倒放內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Matlab實現將圖像序列合並為視頻的方法詳解
- 如何使用Python的OpenCV庫處理圖像和視頻
- python 基於opencv操作攝像頭
- OpenCV實現更改圖片顏色功能
- C++ OpenCV實現抖音"藍線挑戰"特效