Khi play camera bằng OpenCV bạn sẽ thường gặp vấn đề delay của camera. Nếu thời gian xử lý mỗi frame càng nhiều thì delay càng nghiêm trọng.
Lý do là camera stream hình ảnh về có buffer, lấy tuần tự ra để hiển thị. Do đó phương pháp giải quyết là dùng 2 thread, 1 thread đọc frame mới nhất và 1 thread xử lý.
Bài này hướng dẫn play camera IP trong OpenCV không bị delay bằng cách viết 1 class thay thế cho VideoCapture. Sau khi thay thế thì cách dùng cũng gần giống như cũ, không khác biệt nhiều.
Khai báo class VideoCapture
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import threading import queue import cv2 class VideoCapture: def __init__(self, name): self.cap = cv2.VideoCapture(name) self.q = queue.Queue() t = threading.Thread(target=self._reader) t.daemon = True t.start() # read frames as soon as they are available, keeping only most recent one def _reader(self): while True: ret, frame = self.cap.read() if not ret: break if not self.q.empty(): try: self.q.get_nowait() # discard previous (unprocessed) frame except queue.Empty: pass self.q.put(frame) def read(self): return self.q.get() def release(self): self.cap.release() |
Cách sử dụng
1 2 3 4 5 6 7 8 9 10 |
url = "rtsp://admin:hd543211@192.168.1.127:554/0" video_capture = VideoCapture(url) while True: frame = video_capture.read() cv2.imshow('frame', frame) if cv2.waitKey(30) & 0xFF == ord('q'): break video_capture.release() |
Giải thích
Trong class VideoCapture sẽ tạo 1 thread để chạy hàm _reader(). Hàm này có công dụng chạy liên tục để lấy frame mới nhất, độc lập với hàm while hiển thị hình ảnh.
Trong hàm while chính thì mỗi khi gọi hàm read() để lấy frame thì class VideoCapture sẽ trả về frame mới nhất, do đó sẽ giảm đi độ delay rất nhiều.