是否可以逐步從視頻讀取幀(例如,我想讀取視頻流的每第五幀)。目前我正在做這個解決方法,但效率不高。從OpenCV中的VideoCapture讀取每第n幀
bool bSuccess
int FramesSkipped = 5;
for (int a = 0; < FramesSkipped; a++)
bSuccess = cap.read(NextFrameBGR);
任何建議,所以我不必循環五幀得到所需的幀?
是否可以逐步從視頻讀取幀(例如,我想讀取視頻流的每第五幀)。目前我正在做這個解決方法,但效率不高。從OpenCV中的VideoCapture讀取每第n幀
bool bSuccess
int FramesSkipped = 5;
for (int a = 0; < FramesSkipped; a++)
bSuccess = cap.read(NextFrameBGR);
任何建議,所以我不必循環五幀得到所需的幀?
恐怕沒有什麼可以做的,這不僅僅是OpenCV的一個缺點。你看,現代視頻編解碼器通常是複雜的動物。爲了獲得更高的壓縮率,幀的編碼通常取決於之前的幀,有時甚至是連續的幀。
因此,大多數情況下,即使您不需要它們,也必須在所需幀之前解碼幀。
對於特定的視頻文件進行編碼有相當不平凡的技巧,因此獲得每一個N幀都很便宜,但在一般情況下不可行。
也就是說,您可以嘗試OpenCV提供的查找功能(請參閱OpenCV Seek Function/Rewind)。它可能(也可能不會)根據具體情況加快工作速度。但是,我個人並不打賭。
這裏是我的建議:
CvCapture* capture = cvCaptureFromFile("input_video_path");
int loop = 0;
IplImage* frame = NULL;
Mat matframe;
char fname[20];
do {
frame = cvQueryFrame(capture);
matframe = cv::cvarrToMat(frame);
cvNamedWindow("video_frame", CV_WINDOW_AUTOSIZE);
cvShowImage("video_frame", frame);
sprintf(fname, "frame%d.jpg", loop);
cv::imwrite(fname, matframe);//save each frame locally
loop++;
cvWaitKey(100);
} while(frame != NULL);
現在你已經保存的所有幀局部可以快速讀取所需的第n個幀。
CATUION:我拍攝的12秒樣本視頻由200多幅圖像組成。這會吃掉很多空間。
簡單而有效的優化將使用您正在使用的方法或@sergie建議的方法來讀取第n幀。之後,您可以使用索引保存圖像,以便稍後在相同索引處查詢將返回保存的圖像,而不必像您一樣跳過幀。通過這種方式,您可以節省您在保存不需要查詢的幀以及浪費時間讀取&以及保存這些不需要的幀的空間。
我正在運行130個1分鐘的4K視頻樣本,我向你保證這是一個非常糟糕的主意! –
我得到它在Python中工作...請參閱下面的兩個示例用例和一些注意事項。
import cv2
import math
import numpy as np
#################### Setting up the file ################
videoFile = "Jumanji.mp4"
vidcap = cv2.VideoCapture(videoFile)
success,image = vidcap.read()
#################### Setting up parameters ################
seconds = 5
fps = vidcap.get(cv2.CAP_PROP_FPS) # Gets the frames per second
multiplier = fps * seconds
#################### Initiate Process ################
while success:
frameId = int(round(vidcap.get(1))) #current frame number, rounded b/c sometimes you get frame intervals which aren't integers...this adds a little imprecision but is likely good enough
success, image = vidcap.read()
if frameId % multiplier == 0:
cv2.imwrite("FolderSeconds/frame%d.jpg" % frameId, image)
vidcap.release()
print "Complete"
#################### Setting up the file ################
videoFile = "Jumanji.mp4"
vidcap = cv2.VideoCapture(videoFile)
success,image = vidcap.read()
#################### Setting up parameters ################
#OpenCV is notorious for not being able to good to
# predict how many frames are in a video. The point here is just to
# populate the "desired_frames" list for all the individual frames
# you'd like to capture.
fps = vidcap.get(cv2.CAP_PROP_FPS)
est_video_length_minutes = 3 # Round up if not sure.
est_tot_frames = est_video_length_minutes * 60 * fps # Sets an upper bound # of frames in video clip
n = 5 # Desired interval of frames to include
desired_frames = n * np.arange(est_tot_frames)
#################### Initiate Process ################
for i in desired_frames:
vidcap.set(1,i-1)
success,image = vidcap.read(1) # image is an array of array of [R,G,B] values
frameId = vidcap.get(1) # The 0th frame is often a throw-away
cv2.imwrite("FolderFrames/frame%d.jpg" % frameId, image)
vidcap.release()
print "Complete"
這就是它。
(major_ver, minor_ver, subminor_ver) = (cv2.__version__).split('.')
major_ver
在你的第二個例子中,你可以使用'cv2.CAP_PROP_FRAME_COUNT'來獲得確切的幀數並且避免對其進行計算。 另外,你能解釋'n * np.arange(est_tot_frames)'的用途嗎?它似乎沒有做它應該做的。 – StephaneMombuleau
我不是專家,所以可能是非常錯誤的,但有可能跳過中間P和B幀高達的最後一個I幀的幀需要之前? – saurabheights
也許,它提供的搜索功能就是這樣做的。但我不認爲OpenCV中有一個用於編解碼器級別的細粒度操作的API。 –
謝謝。我最終選擇使用ffmpeg來提取關鍵幀。發現從opencv提取的幀沒有與ffmpeg一樣好的質量。 – saurabheights