Основываясь на комментариях к исходному вопросу, я провел некоторое тестирование и подумал, что стоит поделиться (интересными) результатами.Большой потенциал экономии для тех, кто использует OpenCV VideoCapture.set(CAP_PROP_POS_MSEC)
или VideoCapture.set(CAP_PROP_POS_FRAMES)
.
. Я провел профилирование, сравнив три варианта:
1.ПОЛУЧИТЕ КАДРЫ, ПОИСКА ВРЕМЕНИ:
frames = {}
def get_all_frames_by_ms(time):
while True:
video_capture.set(cv2.CAP_PROP_POS_MSEC, time)
capture_success, frames[time] = video_capture.read()
if not capture_success:
break
time += 1000
2.ПОЛУЧИТЕ КАДРЫ, ПОИСКА НОМЕР КАДРА:
frames = {}
def get_all_frames_by_frame(time):
while True:
# Note my test video is 12.333 FPS, and time is in milliseconds
video_capture.set(cv2.CAP_PROP_POS_FRAMES, int(time/1000*12.333))
capture_success, frames[time] = video_capture.read()
if not capture_success:
break
time += 1000
3.ПОЛУЧИТЕ РАМКИ, ПОЛУЧИВАЯ ВСЕ, НО ПОЛУЧИТЬ ТОЛЬКО ОДНОГО, КОТОРОГО Я ХОЧУ:
def get_all_frames_in_order():
prev_time = -1
while True:
grabbed = video_capture.grab()
if grabbed:
time_s = video_capture.get(cv2.CAP_PROP_POS_MSEC) / 1000
if int(time_s) > int(prev_time):
# Only retrieve and save the first frame in each new second
self.frames[int(time_s)] = video_capture.retrieve()
prev_time = time_s
else:
break
При выполнении этих трех подходов время (из трех прогонов каждого) следующее:
- 33,78 с 29,65 с 29,24 с
- 31,95 с 29,16 с 28,35 с
- 11,81 с 10,76 с 11,73 с
В каждом случае сохраняется 100 кадров приИнтервалы 1 с в словарь, где каждый кадр представляет собой изображение 3072x1728 из видеофайла .mp4.Все на MacBookPro 2015 года с 2,9 ГГц процессором Intel Core i5 и 8 ГБ ОЗУ.
Выводы ... если вы заинтересованы в извлечении только нескольких кадров из видео, тогда стоит посмотреть на просмотр всех кадров.по порядку и захватывая их все, но извлекая только те, которые вас интересуют - как альтернативу чтению (которое захватывает и извлекает за один раз).У меня было почти 3-кратное ускорение.
Я также пересмотрел многопоточность на этой основе.У меня есть два процесса тестирования - один, который получает кадры, и другой, который обрабатывает их, как только они становятся доступными:
frames = {}
def get_all_frames_in_order():
prev_time = -1
while True:
grabbed = video_capture.grab()
if grabbed:
time_s = video_capture.get(cv2.CAP_PROP_POS_MSEC) / 1000
if int(time_s) > int(prev_time):
# Only retrieve and save the first frame in each new second
frames[int(time_s)] = video_capture.retrieve()
prev_time = time_s
else:
break
def process_all_frames_as_available(processing_time):
prev_time = 0
while True:
this_time = prev_time + 1000
if this_time in frames and prev_time in frames:
# Dummy processing loop - just sleeps for specified time
sleep(processing_time)
prev_time += self.time_increment
if prev_time + self.time_increment > video_duration:
break
else:
# If the frames aren't ready yet, wait a short time before trying again
sleep(0.02)
Для этого тестирования я затем вызывал их один за другим (последовательно,однопоточное) или со следующим многопоточным кодом:
get_frames_thread = Thread(target=get_all_frames_in_order)
get_frames_thread.start()
process_frames_thread = Thread(target=process_all_frames_as_available, args=(0.02,))
process_frames_thread.start()
get_frames_thread.join()
process_frames_thread.join()
Исходя из этого, я теперь счастлив, что многопоточность работает эффективно и экономит значительное количество времени.Я сгенерировал временные интервалы для двух указанных выше функций по отдельности, а затем вместе в однопоточном и многопоточном режимах.Результаты приведены ниже (число в скобках - это время в секундах, которое занимает «обработка» для каждого кадра, что в данном случае является просто фиктивной / задержкой):
get_all_frames_in_order - 2.99s
Process time = 0.02s per frame:
process_all_frames_as_available - 0.97s
single-threaded - 3.99s
multi-threaded - 3.28s
Process time = 0.1s per frame:
process_all_frames_as_available - 4.31s
single-threaded - 7.35s
multi-threaded - 4.46s
Process time = 0.2s per frame:
process_all_frames_as_available - 8.52s
single-threaded - 11.58s
multi-threaded - 8.62s
Как вы можете надеяться, вы увидите,результаты многопоточности очень хороши.По сути, для одновременного выполнения обеих функций на ~ 0,2 с требуется больше времени, чем для медленной работы двух функций, выполняемых совершенно по-отдельности.
Надеюсь, это кому-нибудь поможет!