Hi all,
I’ve been playing around with python, opencv, a raspberry 4 and a “pi hq cam”. The thing is, the time it takes to capture is really long. The pi cam could, in theory, do 1920x1080@30fps. I’m not aiming for that but what I’m getting is more like 2-3 fps when using videocapture. I’d be happy if I could get up to 10fps. Also I would like to get a minimal read time at full resolution.
My main questions are:
– How can I get the read times down as far as possible?
– What is going on in the background, are there maybe some “magic resolutions” that bring read time down considerably? (see drop of read time at specific resolutions below)
Below you’ll find some system info and my test code
The test code does the following at different resolutions:
– read a frame from videocapture
– crop the frame to an area of interest
– show the frame with imshow
These are the timing results. The read times are long but go down with the resolution. However at 1280x704 and 640x480 the read time drops considerably. Why is that?
4032 x 3040: 0.553347
3840 x 2144: 0.425402
1920 x 1088: 0.328975
1280 x 704: 0.026025
1024 x 768: 0.356915
640 x 480: 0.031017
Some system info:
Raspberry Pi 4 Model B Rev 1.4 4GB
Raspbian GNU/Linux 10 (buster)
ARMv7 Processor rev 3 (v7l)
IDE: Pycharm, Python 3.7, opencv-python 4.5.3.56
And finally my code:
import cv2
import time
# Read frame from videocapture
def read_frame():
_, frame = feed.read()
return frame
# Crop to region of interest
# x1 x2
# y1 .___________________.
# | |
# | |
# | |
# | |
# y2.|___________________|.
#
# frame[y1:y2, x1:x2]
def crop(frame, x, y, width, height):
return frame[y:y+height, x:x+width]
# Show frame
def show(frame):
cv2.imshow('Preview', frame)
if __name__ == '__main__':
cv2.namedWindow('Preview')
feed = cv2.VideoCapture(0)
# Resolutions, the width and height values must be multiples of 32
# Index: 0 1 2 3 4 5
resolutions = [[640, 480], [1024, 768], [1280, 704], [1920, 1088], [3840, 2144], [4032, 3040]]
res_index = 5
feed.set(cv2.CAP_PROP_FRAME_WIDTH, resolutions[res_index][0])
feed.set(cv2.CAP_PROP_FRAME_HEIGHT, resolutions[res_index][1])
# Region of interest will be 1/3 of the width and 1/3 of the height of chosen resolution,
full_width = resolutions[res_index][0]
full_height = resolutions[res_index][1]
roi_w = int(full_width/3)
roi_h = int(full_height/3)
roi_x = int(full_width/2 - roi_w/2)
roi_y = int(full_height/2 - roi_h/2)
while True:
start = time.time()
frame = read_frame()
print(f'read: {(time.time() - start):.6f}') # print with 6 decimals
start = time.time()
frame = crop(frame, roi_x, roi_y, roi_w, roi_h)
print(f'crop: {(time.time() - start):.6f}')
start = time.time()
show(frame)
print(f'show: {(time.time() - start):.6f}')
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()