Как я могу улучшить свой Python OpenCV видео-поток?

Я работал над проектом, в котором я использую Raspberry Pi для отправки живого видео на мой сервер. Это работает, но не так, как мне бы хотелось. Проблема в основном в скорости. Прямо сейчас я могу отправить видео поток 640x480 со скоростью около 3,5 кадров в секунду и 1920x1080 со скоростью около 0,5 кадров в секунду, что ужасно. Поскольку я не профессионал, я подумал, что должен быть способ улучшить мой код.

Отправитель (Raspberry pi):

def send_stream():
    connection = True
    while connection:
        ret,frame = cap.read()
        if ret:
            # You might want to enable this while testing.
            # cv2.imshow('camera', frame)
            b_frame = pickle.dumps(frame)
            b_size = len(b_frame)
            try:
                s.sendall(struct.pack("<L", b_size) + b_frame)
            except socket.error:
                print("Socket Error!")
                connection = False

        else:
            print("Received no frame from camera, exiting.")
            exit()

Получатель (Сервер):

    def recv_stream(self):
        payload_size = struct.calcsize("<L")
        data = b''
        while True:
            try:
                start_time = datetime.datetime.now()
                # keep receiving data until it gets the size of the msg.
                while len(data) < payload_size:
                    data += self.connection.recv(4096)
                # Get the frame size and remove it from the data.
                frame_size = struct.unpack("<L", data[:payload_size])[0]
                data = data[payload_size:]
                # Keep receiving data until the frame size is reached.
                while len(data) < frame_size:
                    data += self.connection.recv(32768)
                # Cut the frame to the beginning of the next frame.
                frame_data = data[:frame_size]
                data = data[frame_size:]

                frame = pickle.loads(frame_data)
                frame = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)

                end_time = datetime.datetime.now()
                fps = 1/(end_time-start_time).total_seconds()
                print("Fps: ",round(fps,2))

                self.detect_motion(frame,fps)

                self.current_frame = frame

            except (socket.error,socket.timeout) as e:
                # The timeout got reached or the client disconnected. Clean up the mess.
                print("Cleaning up: ",e)
                try:
                    self.connection.close()
                except socket.error:
                    pass
                self.is_connected = False
                break

Всего 1 ответ


Одна потенциальная причина может из-за задержки ввода / вывода при чтении кадров. Поскольку cv2.VideoCapture().read() является операцией блокировки, основная программа останавливается до тех пор, пока кадр не будет считан с устройства камеры и не возвращен. Метод повышения производительности - создание другого потока для параллельной обработки захвата кадров, вместо того чтобы полагаться на один поток для захвата кадров в последовательном порядке. Мы можем повысить производительность, создав новый поток, который опрашивает только новые кадры, в то время как основной поток обрабатывает / отображает самый последний кадр.

Ваш текущий подход (последовательный):

Тема 1: Схватить кадр -> Обрабатывать кадр -> Сюжет

Предлагаемый подход (параллельный):

Тема 1: Схватить кадр

from threading import Thread
import time

def get_frames():
    while True:
        ret, frame = cap.read()
        time.sleep(.01)

thread_frames = Thread(target=self.get_frames, args=())
thread_frames.daemon = True
thread_frames.start()

Поток 2: Обработка кадра -> Сюжет

def process_frames():
    while True:
        # Grab most recent frame
        # Process/plot frame
        ...

Имея отдельные потоки, ваша программа будет параллельной, поскольку всегда будет кадр, готовый для обработки, вместо того, чтобы ждать, пока кадр будет прочитан, прежде чем можно будет выполнить обработку.

Примечание. Этот метод даст вам повышение производительности на основе уменьшения задержки ввода / вывода. Это не является истинным увеличением FPS, поскольку это значительное сокращение задержки (кадр всегда доступен для обработки; нам не нужно опрашивать устройство камеры и ждать завершения ввода-вывода).