2016-02-02 3 views
3

Я пытаюсь добиться результатов, как показано на видео (Способ 3 с помощью NetCat) https://www.youtube.com/watch?v=sYGdge3T30oOpenCV Python, чтение видео с именем трубы

Дело в том, чтобы поток видео с малиновым пи Ubuntu ПК и обработать его с помощью openCV и python.

Я использую команду

raspivid -vf -n -w 640 -h 480 -o - -t 0 -b 2000000 | nc 192.168.0.20 5777

для потоковой передачи видео на ПК, а затем на ПК я создал имя трубы «ФИФО» и перенаправил выход

nc -l -p 5777 -v > fifo 

тогда я пытаюсь читать трубу и отображать результат в сценарии python

import cv2 
import sys 

video_capture = cv2.VideoCapture(r'fifo') 
video_capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640); 
video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480); 

while True: 
    # Capture frame-by-frame 
    ret, frame = video_capture.read() 
    if ret == False: 
     pass 

    cv2.imshow('Video', frame) 

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

# When everything is done, release the capture 
video_capture.release() 
cv2.destroyAllWindows() 

Однако я просто в конечном итоге с ошибкой

[mp3 @ 0x18b2940] Заголовок отсутствует эта ошибка генерируемый командой video_capture = cv2.VideoCapture(r'fifo')

Когда я перенаправить вывод Netcat на компьютере файл, а затем читает его в python видео работает, однако оно ускоряется примерно в 10 раз.

Я знаю, что проблема связана с скриптом python, потому что передача nc работает (в файл), но я не могу найти никаких подсказок.

Как достичь результатов, как показано на прилагаемом видео (метод 3)?

ответ

2

Я тоже хотел добиться того же результата в этом видео. Первоначально я пробовал аналогичный подход, как ваш, но, похоже, cv2.VideoCapture() не читается из именованных каналов, требуется некоторая предварительная обработка.

ffmpeg - это путь! Вы можете установить и собрать FFmpeg, следуя инструкциям, приведенным в этой ссылке: https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu

После установки, вы можете изменить свой код, например, так:

import cv2 
import subprocess as sp 
import numpy 

FFMPEG_BIN = "ffmpeg" 
command = [ FFMPEG_BIN, 
     '-i', 'fifo',    # fifo is the named pipe 
     '-pix_fmt', 'bgr24',  # opencv requires bgr24 pixel format. 
     '-vcodec', 'rawvideo', 
     '-an','-sn',    # we want to disable audio processing (there is no audio) 
     '-f', 'image2pipe', '-']  
pipe = sp.Popen(command, stdout = sp.PIPE, bufsize=10**8) 

while True: 
    # Capture frame-by-frame 
    raw_image = pipe.stdout.read(640*480*3) 
    # transform the byte read into a numpy array 
    image = numpy.fromstring(raw_image, dtype='uint8') 
    image = image.reshape((480,640,3))   # Notice how height is specified first and then width 
    if image is not None: 
     cv2.imshow('Video', image) 

    if cv2.waitKey(1) & 0xFF == ord('q'): 
     break 
    pipe.stdout.flush() 

cv2.destroyAllWindows() 

Нет необходимости изменять какие-либо другие вещи на малиновый pi скрипт.

Это работало как очарование для меня. Задержка видео была незначительной. Надеюсь, это поможет.

+0

Я предполагаю это та часть, которая работает на рабочем столе Linux, но не появляются, чтобы показать, что нужно запустить на малине Pi или как запустить оба конца двух машин? –

+0

Ну, мы пытались достичь результатов, как показано на видео (метод 3) https://www.youtube.com/watch?v=sYGdge3T30o, как упоминалось в @Richard. Все остается таким же, как описано в видео. Я просто хотел помочь с скриптом python для чтения из именованного канала, который не был показан в видео. –

+0

Я надеялся, что это позволит мне использовать аргументы командной строки для ffmpeg для принудительного аппаратного декодирования через qsv и h264_qsv вместо скрытых значений по умолчанию OpenCV. И хотя технически этот ответ действительно делает это, я на самом деле вижу снижение скорости по сравнению с использованием cv2.VideoCapture ('filename.mp4'). Я получаю около 111 кадров в секунду вместо 259 кадров в секунду. (в той же системе ffmpeg-декодирование до нуля превышает 1100 кадров в секунду). Я думаю, что это, вероятно, из-за того, что все данные попадают по всему миру. Хорошее доказательство концепции, по крайней мере. – TheAtomicOption

0

У меня была аналогичная проблема, что я работаю, с немного больше исследований, я в конце концов наткнулся на следующее:

Перейти к решению: https://stackoverflow.com/a/48675107/2355051

я оказался адаптации этого picamera python recipe

на Raspberry Pi: (createStream.py)

import io 
import socket 
import struct 
import time 
import picamera 

# Connect a client socket to my_server:8000 (change my_server to the 
# hostname of your server) 
client_socket = socket.socket() 
client_socket.connect(('10.0.0.3', 777)) 

# Make a file-like object out of the connection 
connection = client_socket.makefile('wb') 
try: 
    with picamera.PiCamera() as camera: 
     camera.resolution = (1024, 768) 
     # Start a preview and let the camera warm up for 2 seconds 
     camera.start_preview() 
     time.sleep(2) 

     # Note the start time and construct a stream to hold image data 
     # temporarily (we could write it directly to connection but in this 
     # case we want to find out the size of each capture first to keep 
     # our protocol simple) 
     start = time.time() 
     stream = io.BytesIO() 
     for foo in camera.capture_continuous(stream, 'jpeg', use_video_port=True): 
      # Write the length of the capture to the stream and flush to 
      # ensure it actually gets sent 
      connection.write(struct.pack('<L', stream.tell())) 
      connection.flush() 

      # Rewind the stream and send the image data over the wire 
      stream.seek(0) 
      connection.write(stream.read()) 

      # Reset the stream for the next capture 
      stream.seek(0) 
      stream.truncate() 
    # Write a length of zero to the stream to signal we're done 
    connection.write(struct.pack('<L', 0)) 
finally: 
    connection.close() 
    client_socket.close() 

на машине, обрабатывающего поток: (processStream.py)

import io 
import socket 
import struct 
import cv2 
import numpy as np 

# Start a socket listening for connections on 0.0.0.0:8000 (0.0.0.0 means 
# all interfaces) 
server_socket = socket.socket() 
server_socket.bind(('0.0.0.0', 777)) 
server_socket.listen(0) 

# Accept a single connection and make a file-like object out of it 
connection = server_socket.accept()[0].makefile('rb') 
try: 
    while True: 
     # Read the length of the image as a 32-bit unsigned int. If the 
     # length is zero, quit the loop 
     image_len = struct.unpack('<L', connection.read(struct.calcsize('<L')))[0] 
     if not image_len: 
      break 
     # Construct a stream to hold the image data and read the image 
     # data from the connection 
     image_stream = io.BytesIO() 
     image_stream.write(connection.read(image_len)) 
     # Rewind the stream, open it as an image with opencv and do some 
     # processing on it 
     image_stream.seek(0) 
     image = Image.open(image_stream) 

     data = np.fromstring(image_stream.getvalue(), dtype=np.uint8) 
     imagedisp = cv2.imdecode(data, 1) 

     cv2.imshow("Frame",imagedisp) 
     cv2.waitKey(1) #imshow will not output an image if you do not use waitKey 
     cv2.destroyAllWindows() #cleanup windows 
finally: 
    connection.close() 
    server_socket.close() 

Это решение имеет похожие результаты с видео, на которое я ссылался в своем первоначальном вопросе. Рамки большего разрешения увеличивают латентность фида, но это приемлемо для целей моего приложения.

Сначала вам нужно запустить processStream.py, а затем выполнить createStream.py на Raspberry Pi

Смежные вопросы