Различные методы расчета частоты кадров дают очень разные результаты

В рамках системы распознавания жестов рук на основе 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()
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
34
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Конечно, между № 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() занимают значительное время.

Luke Hollingshead 07.04.2022 13:25

Другие вопросы по теме