Объедините OpenCV и FFMEG для более быстрой обработки видео - PullRequest
0 голосов
/ 20 октября 2019

Я пытаюсь обработать видео. Чтобы сделать это быстрее, я хотел бы прочитать его с помощью ffmpeg, а затем отправить кадр на cv2 для обработки.

Это то, что я сделал:

import cv2
import subprocess as sp
import numpy as np

input_file = 'testvideo.mp4'


cap = cv2.VideoCapture(input_file)
ret, frame = cap.read()
height, width, ch = frame.shape

ffmpeg = "C:\\Users\\totyped\\Downloads\\ffmpeg\\bin\\ffmpeg.exe"
dimension = '{}x{}'.format(width, height)
f_format = 'bgr24' # remember OpenCV uses bgr format
fps = str(cap.get(cv2.CAP_PROP_FPS))

command = [ffmpeg,
        '-i', input_file,
            '-r', fps,                  # FPS
            '-pix_fmt', 'bgr24',        # opencv requires bgr24 pixel format.
            '-vcodec', 'mp4',
            '-an','-sn',                # disable audio processing
            '-f', 'image2pipe', '-']    

pipe = sp.Popen(command, stdout = sp.PIPE, bufsize=10)

while True:
    frame =  pipe.stdout.read()
    image =  np.frombuffer(frame, dtype='uint8')        # convert read bytes to np


    cv2.imshow('Video', image)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
proc.stdin.close()
proc.stderr.close()
proc.wait()

Я продолжаю получать ту же ошибку:

ошибка: OpenCV (4.0.0) C: \ projects \ opencv-python \ opencv \ modules \ highgui \ src \ window.cpp: 350: ошибка: (-215: утверждение не выполнено)size.width> 0 && size.height> 0 в функции 'cv :: imshow'

Это потому, что что-то не так с тем, как я получаю видео.

Кодбыл частично вдохновлен: https://www.reddit.com/r/linuxquestions/comments/b4jxdb/how_could_i_interface_ffmpeg_with_opencv_in/

РЕДАКТИРОВАТЬ:

import cv2
import subprocess as sp
import numpy as np

input_file = 'testvideo.mp4'


cap = cv2.VideoCapture(input_file)
ret, frame = cap.read()
height, width, ch = frame.shape

ffmpeg = "C:\\Users\\totyped\\Downloads\\ffmpeg\\bin\\ffmpeg.exe"
dimension = '{}x{}'.format(width, height)
f_format = 'bgr24' # remember OpenCV uses bgr format
fps = str(cap.get(cv2.CAP_PROP_FPS))

command = [ffmpeg,
        '-i', input_file,
            '-r', fps,                  # FPS
            '-pix_fmt', 'bgr24',        # opencv requires bgr24 pixel format.
            '-vcodec', 'mp4',
            '-an','-sn',                # disable audio processing
            '-f', 'image2pipe', '-']    

pipe = sp.Popen(command, stdout = sp.PIPE, bufsize=64000000)

while True:
    frame =  pipe.stdout.read(height*width*3)
    print(frame)
    image =  np.frombuffer(frame, dtype='uint8')        # convert read bytes to np


    cv2.imshow('Video', image)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

Ответы [ 2 ]

1 голос
/ 20 октября 2019

Попробуйте что-то вроде этого - хотя я думаю, что вы, возможно, лаете не то дерево, используя ffmpeg, потому что это все, что OpenCV использует под прикрытием. Если вам нужна более высокая производительность, возможно, стоит больше взглянуть на многопроцессорность - но это зависит от типа обработки, которую вы выполняете, которую вы не обсуждали или не показывали:

#!/usr/bin/env python3
import numpy as np
import cv2
import subprocess as sp
import numpy as np

ffmpeg = "ffmpeg"
input_file='test.mp4'
height, width = 480, 640
command = [ffmpeg,
            '-i', input_file,
            '-pix_fmt', 'bgr24',
            '-codec', 'rawvideo',
            '-an',
            '-sn',
            '-f', 'image2pipe', '-']   

pipe = sp.Popen(command, stdout = sp.PIPE, bufsize=65536)

frameCount=0
while True:
    nbytes = height*width*3
    print(f"Frame: {frameCount} - Trying to read {nbytes} bytes")
    frame =  pipe.stdout.read(nbytes)
    bytesRead = len(frame)
    print(f"Read {bytesRead} bytes")
    if bytesRead==0:
        break
    image =  np.frombuffer(frame, dtype='uint8')        # convert read bytes to np
    image = image.reshape((480,640,3))

    cv2.imshow('Video', image)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
    frameCount += 1
0 голосов
/ 20 октября 2019

Я использовал это некоторое время назад. Это также включает запуск нескольких потоков с ним. Я не проверял этот метод для всех типов потоков или типов файлов. Но я сделал это для потоков RTSP-UDP.

import numpy
from subprocess import Popen, PIPE
import cv2

class ffmpeg_videocapture:
    def __init__(self, stream, width=640, height=360, scale=1, fps=15):
        self.command = 'ffmpeg -rtsp_transport udp -i {i} -pix_fmt bgr24 -s {w}x{h} -vcodec rawvideo ' \
                       '-an -sn -r {fps} -f image2pipe pipe:1'

        self.stream = stream
        self.width = width
        self.height = height
        self.scale = scale
        self.fps = fps

        self.errors = []
        self.start()

    def start(self):
        width = int(self.width * self.scale)
        height = int(self.height * self.scale)
        command = self.command.format(i=self.stream, w=width, h=height, fps=self.fps)
        self.capture = Popen(command.split(' '), stdout=PIPE, stderr=PIPE, bufsize=10 ** 8)

    def read(self):
        width = int(self.width * self.scale)
        height = int(self.height * self.scale)
        raw_image = self.capture.stdout.read(width * height * 3)

        frame = numpy.fromstring(raw_image, dtype='uint8')
        frame = frame.reshape((height, width, 3))

        self.capture.stdout.flush()

        return frame is not None, frame

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.capture.terminate()


def single_camera(rtsp_stream):
    cap = ffmpeg_videocapture(rtsp_stream)
    while True:
        ret, frame = cap.read()
        cv2.imshow("frame", frame)

if __name__ == "__main__":
    rtsp_stream_list = [
        "rtsp_stream_1",
        "rtsp_stream_2",
        "etc...",
    ]

    for rtsp_stream in rtsp_stream_list:
        t = Process(target=single_camera, args=rtsp_stream)
        t.start()

Надеюсь, это поможет вам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...