В рамках системы распознавания жестов рук на основе OpenCV и MediaPipe (от Google) я исследовал возможную частоту кадров. Первым был использован код в подходе 1 (частично из видео на YouTube и частично из примера кода Mediapipe) — он использует счетчик кадров и общее время, затраченное на вычисление частоты кадров. Код для подхода 2 использует несколько иной метод — время начала и окончания используются для определения времени обработки кадра для получения частоты кадров. Мгновенная частота кадров затем добавляется в список, который усредняется, чтобы получить среднюю частоту кадров (более 10 кадров).
Подход 1 в моей системе обеспечивает частоту кадров 30 кадров в секунду (необходимо некоторое время для установления этого значения, скажем, 5-10 секунд). Подход 2, когда строка if results.multi_hand_landmarks
ложная, достигает 100-110 кадров в секунду. Когда if results.multi_hand_landmarks
истинно, частота кадров падает примерно до 60 кадров в секунду (двойной подход 1).
Частота кадров для Подхода 1 не зависит от if results.multi_hand_landmarks
, но уменьшается при увеличении значения cv2.waitKey(5)
. Подход 2 показывает другое поведение при увеличении одного и того же значения — по мере увеличения значения частота кадров будет увеличиваться до точки, в которой достигается максимальная частота кадров, но она падает при дальнейшем увеличении времени ожидания.
Я подозреваю, что правильная частота кадров составляет 30 кадров в секунду, исходя из характеристик камеры (см. Ниже), но это не объясняет значения из Подхода 2.
Я работал с обоими подходами, чтобы исключить другие источники, которые могут повлиять на частоту кадров, но вскоре стало очевидно (по крайней мере, для меня), что это был метод, используемый для расчета частоты кадров. Поэтому я спрашиваю, может ли кто-нибудь пролить свет на то, почему эти два подхода дают разные результаты. Мне логика каждого метода кажется правильной, но я должен что-то упустить.
Windows 10; Питон — 3.7.9; OpenCV — 4.5.4; МедиаПайп — 0.8.9; Управляемый процессором (без графического процессора); Веб-камера — Logitech C920 (30 кадров в секунду при 720p/1080p)
Подход 1
import cv2
import mediapipe as mp
import numpy as np
import sys
import time
def main():
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
# start processing the video feed
capture(cap)
def capture(cap):
mpHands = mp.solutions.hands
hands = mpHands.Hands(min_detection_confidence=0.91, min_tracking_confidence=0.91)
# used for displaying hand and other information in separate window
mpDraw = mp.solutions.drawing_utils
# used for displaying hand and other information in separate window
# initialize time and frame count variables
last_time = time.time()
frames = 0
while True:
# blocks until the entire frame is read
success, img = cap.read()
# used for displaying hand and other information in separate window
img = cv2.cvtColor(cv2.flip(img,1), cv2.COLOR_BGR2RGB)
# process the image
results = hands.process(img)
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
# if results and landmarks exist process as needed
if results.multi_hand_landmarks:
for handLms in results.multi_hand_landmarks:
# used for displaying hand and landmarks in separate window
mpDraw.draw_landmarks(img, handLms, mpHands.HAND_CONNECTIONS)
# Other code goes here to process landmarks
# used for displaying hand and other information in separate window
# compute fps: current_time - last_time
frames += 1
delta_time = time.time() - last_time
cur_fps = np.around(frames / delta_time, 1)
# used for displaying hand and other information in separate window
cv2.putText(img, 'FPS: ' + str(cur_fps), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA)
cv2.imshow("Image", img)
if cv2.waitKey(5) & 0xFF == 27:
break
if __name__ == "__main__":
main()
Подход 2
import cv2
import mediapipe as mp
import numpy as np
import sys
import time
def main():
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
# start processing the video feed
capture(cap)
def capture(cap):
mpHands = mp.solutions.hands
hands = mpHands.Hands(min_detection_confidence=0.91, min_tracking_confidence=0.91)
# used for displaying hand and other information in separate window
mpDraw = mp.solutions.drawing_utils
# Initialise list to hold instantaneous frame rates
fps = [0]
while True:
# start time
start = time.time()
# blocks until the entire frame is read
success, image = cap.read()
# used for displaying hand and other information in separate window
imageRGB = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
results = hands.process(imageRGB)
# if results and landmarks exist process as needed
if results.multi_hand_landmarks:
for handLms in results.multi_hand_landmarks:
# used for displaying hand and landmarks in separate window
mpDraw.draw_landmarks(image, handLms, mpHands.HAND_CONNECTIONS)
# Other code goes here to process landmarks
# Define end time
end = time.time()
# Elapsed time between frames
elapsed_time = (end - start)
if elapsed_time != 0:
# Calculate the current instantaneous frame rate
cur_fps = 1/elapsed_time
# Append to end of list
fps.append(cur_fps)
# Maintain length of list
if len(fps) == 10:
del fps[0]
# Calculate the average frame rate
ave_fps = np.around(sum(fps)/len(fps))
# used for displaying hand and other information in separate window
cv2.putText(image, 'FPS: ' + str(ave_fps), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA)
cv2.imshow("Image", image)
if cv2.waitKey(35) & 0xFF == 27:
break
cap.release()
if __name__ == "__main__":
main()
Конечно, между № 1 и № 2 результаты разные.
в № 1 эти строки также засчитываются в delta_time
cur_fps = np.around(frames / delta_time, 1)
# used for displaying hand and other information in separate window
cv2.putText(img, 'FPS: ' + str(cur_fps), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA)
cv2.imshow("Image", img)
if cv2.waitKey(5) & 0xFF == 27:
break
которые делают ваш FPS более достоверным, потому что он охватывает все время цикла
в # 2 вы не полностью считаете FPS, потому что вы не включаете приведенные выше кодовые строки для подсчета.
Спасибо @danangjoyoo за выявление (теперь это очевидно) проблемы с моими методами. Я изменил № 2, включив в него перечисленные строки кода, и вуаля 30 кадров в секунду! Я действительно надеялся, что обещание 60 кадров в секунду было реальным, но это иллюзия - по крайней мере, в моем случае. Это также показывает, что эти строки кода занимают столько же времени, сколько и остальные — конечно
cap.read()
занимают значительное время.