Frame rate measures how many frames an application captures, processes, or checks each second. In interactive loops, it sets how often input events are handled; in live vision, it determines whether processing can keep pace with camera images. section 7.4.1 section 9.4
Choose a rate that matches the job. A Pygame event loop uses 60 frames per second for responsiveness, while raising it further adds computer load without improving the described user experience. A Raspberry Pi camera supplies video at 30 frames per second, so face detection must run at least that fast for live operation. section 7.4.1 section 9.6
Limit an event loop to 60 FPS
Create a Pygame Clock and call tick(FRAME_RATE) once per loop iteration, after reading events. This keeps event polling at the configured rate while allowing a QUIT event to close the application. section 7.4.1
Listing 7.1 pygame_events.py: Using the Pygame library to print joystick events
#!/usr/bin/env python3
import pygame
FRAME_RATE = 60
WINDOW_SIZE = [100, 100]
def main():
pygame.init()
screen = pygame.display.set_mode(WINDOW_SIZE)
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
print('event detected:', event)
if event.type == pygame.QUIT:
pygame.quit()
return
clock.tick(FRAME_RATE)
main()
This runnable event loop defines FRAME_RATE as 60 and applies it with clock.tick at the end of every iteration. section 7.4.1
Measure processing frame rate from elapsed work time. Time repeated face-detection calls, average their durations, then calculate frames per second as 1 divided by that average. A measured 10.1 FPS falls below the required 30 FPS, identifying a performance problem before optimization. section 9.4.1
Listing 9.2 measure_face.py: Measuring face detection performance
#!/usr/bin/env python3
import cv2
from statistics import mean
import time
BLUE = (255, 0, 0)
CV2_DIR = cv2.__path__[0]
CLASSIFIER_PATH = f'{CV2_DIR}/data/haarcascade_frontalface_default.xml'
face_classifier = cv2.CascadeClassifier(CLASSIFIER_PATH)
def get_center(x, y, w, h):
return int(x + (w / 2)), int(y + (h / 2))
def prep_face(frame):
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
return cv2.equalizeHist(gray)
def detect_face(frame):
clean = prep_face(frame)
faces = face_classifier.detectMultiScale(clean)
if len(faces) > 0:
x, y, w, h = faces[0]
center = get_center(x, y, w, h)
cv2.rectangle(frame, (x, y), (x + w, y + h), BLUE, 2)
cv2.drawMarker(frame, center, BLUE)
return center
def get_detect_timing(frame):
start = time.perf_counter()
center = detect_face(frame)
return time.perf_counter() - start
def main():
frame = cv2.imread('photo.jpg')
center = detect_face(frame.copy())
print('face center:', center)
stats = [get_detect_timing(frame.copy()) for i in range(10)]
print('avg fps:', 1 / mean(stats))
main()
The timing script runs face detection ten times, averages elapsed time, and reports average FPS for comparison with the camera rate. section 9.4.1
