Python Opencv 和套接字 - 以 h264 编码的流媒体视频
Python Opencv and Sockets - Streaming video encoded in h264
所以我正在尝试制作一个流媒体,将视频从我的局域网中的一台计算机流式传输到另一台计算机(或目前是同一台计算机)。我需要它使用尽可能少的带宽,所以我试图在 h264 中编码。我在做这件事时遇到了麻烦,我真的不知道从哪里开始。现在它是用jpg编码的,并且是逐帧发送的。但是,我知道这是非常低效的,并且会消耗大量带宽。这是我当前的接收者代码。
import cv2
import socket
import _pickle
import time
host = "192.168.1.196"
port = 25565
boo = True
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # declares s object with two parameters
s.bind((host, port)) # tells my socket object to connect to this host & port "binds it to it"
s.listen(10) # tells the socket how much data it will be receiving.
conn, addr = s.accept()
buf = ''
while boo:
pictures = conn.recv(128000) # creates a pictures variable that receives the pictures with a max amount of 128000 data it can receive
decoded = _pickle.loads(pictures) # decodes the pictures
frame = cv2.imdecode(decoded, cv2.IMREAD_COLOR) # translates decoded into frames that we can see!
cv2.imshow("recv", frame)
if cv2.waitKey(1) & 0xFF == ord("q"): # wait until q key was pressed once and
break
这是我当前的客户端代码(发件人):
import cv2
import numpy as np
import socket
import _pickle
from cv2 import *
host = "192.168.1.196"
port = 25565
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # declares s object with two parameters
s.connect((host, port)) # connects to the host & port
cap = cv2.VideoCapture(1)
cv2.cv.CV_FOURCC('H','2','6','4')
while cap.isOpened(): # while camera is being used
ret, frame = cap.read() # reads each frame from webcam
cv2.imshow("client", frame)
if ret:
encoded = _pickle.dumps(cv2.imencode("fourcc", frame)[1]) # encoding each frame, instead of sending live video it is sending pictures one by one
s.sendall(encoded)
if cv2.waitKey(1) & 0xFF == ord("q"): # wait until key was pressed once and
break
cap.release()
cv2.destroyAllWindows()
我只需要一些关于如何在 h264 中编码和解码视频的帮助。
您可以使用 pyzmq
and the the publish/subscribe 模式和 base64 字符串 encoding/decoding 来完成此操作。服务器端的思路是:
- 从相机流中获取帧
- 使用
cv2.imencode
从内存缓冲区读取图像
- 使用 base64 将
ndarray
转换为 str
并通过套接字发送
在客户端我们简单地反转这个过程:
- 从套接字读取图像字符串
- 用 base64
将 str
转换成 bytes
- 用
np.frombuffer
+ cv2.imdecode
将 bytes
转换成 ndarray
此方法不应使用太多带宽,因为它仅通过套接字发送字符串。
服务器
import base64
import cv2
import zmq
context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.connect('tcp://localhost:7777')
camera = cv2.VideoCapture(0)
while True:
try:
ret, frame = camera.read()
frame = cv2.resize(frame, (640, 480))
encoded, buf = cv2.imencode('.jpg', frame)
image = base64.b64encode(buf)
socket.send(image)
except KeyboardInterrupt:
camera.release()
cv2.destroyAllWindows()
break
客户端
import cv2
import zmq
import base64
import numpy as np
context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.bind('tcp://*:7777')
socket.setsockopt_string(zmq.SUBSCRIBE, np.unicode(''))
while True:
try:
image_string = socket.recv_string()
raw_image = base64.b64decode(image_string)
image = np.frombuffer(raw_image, dtype=np.uint8)
frame = cv2.imdecode(image, 1)
cv2.imshow("frame", frame)
cv2.waitKey(1)
except KeyboardInterrupt:
cv2.destroyAllWindows()
break
所以我正在尝试制作一个流媒体,将视频从我的局域网中的一台计算机流式传输到另一台计算机(或目前是同一台计算机)。我需要它使用尽可能少的带宽,所以我试图在 h264 中编码。我在做这件事时遇到了麻烦,我真的不知道从哪里开始。现在它是用jpg编码的,并且是逐帧发送的。但是,我知道这是非常低效的,并且会消耗大量带宽。这是我当前的接收者代码。
import cv2
import socket
import _pickle
import time
host = "192.168.1.196"
port = 25565
boo = True
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # declares s object with two parameters
s.bind((host, port)) # tells my socket object to connect to this host & port "binds it to it"
s.listen(10) # tells the socket how much data it will be receiving.
conn, addr = s.accept()
buf = ''
while boo:
pictures = conn.recv(128000) # creates a pictures variable that receives the pictures with a max amount of 128000 data it can receive
decoded = _pickle.loads(pictures) # decodes the pictures
frame = cv2.imdecode(decoded, cv2.IMREAD_COLOR) # translates decoded into frames that we can see!
cv2.imshow("recv", frame)
if cv2.waitKey(1) & 0xFF == ord("q"): # wait until q key was pressed once and
break
这是我当前的客户端代码(发件人):
import cv2
import numpy as np
import socket
import _pickle
from cv2 import *
host = "192.168.1.196"
port = 25565
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # declares s object with two parameters
s.connect((host, port)) # connects to the host & port
cap = cv2.VideoCapture(1)
cv2.cv.CV_FOURCC('H','2','6','4')
while cap.isOpened(): # while camera is being used
ret, frame = cap.read() # reads each frame from webcam
cv2.imshow("client", frame)
if ret:
encoded = _pickle.dumps(cv2.imencode("fourcc", frame)[1]) # encoding each frame, instead of sending live video it is sending pictures one by one
s.sendall(encoded)
if cv2.waitKey(1) & 0xFF == ord("q"): # wait until key was pressed once and
break
cap.release()
cv2.destroyAllWindows()
我只需要一些关于如何在 h264 中编码和解码视频的帮助。
您可以使用 pyzmq
and the the publish/subscribe 模式和 base64 字符串 encoding/decoding 来完成此操作。服务器端的思路是:
- 从相机流中获取帧
- 使用
cv2.imencode
从内存缓冲区读取图像
- 使用 base64 将
ndarray
转换为str
并通过套接字发送
在客户端我们简单地反转这个过程:
- 从套接字读取图像字符串
- 用 base64 将
- 用
np.frombuffer
+cv2.imdecode
将
str
转换成 bytes
bytes
转换成 ndarray
此方法不应使用太多带宽,因为它仅通过套接字发送字符串。
服务器
import base64
import cv2
import zmq
context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.connect('tcp://localhost:7777')
camera = cv2.VideoCapture(0)
while True:
try:
ret, frame = camera.read()
frame = cv2.resize(frame, (640, 480))
encoded, buf = cv2.imencode('.jpg', frame)
image = base64.b64encode(buf)
socket.send(image)
except KeyboardInterrupt:
camera.release()
cv2.destroyAllWindows()
break
客户端
import cv2
import zmq
import base64
import numpy as np
context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.bind('tcp://*:7777')
socket.setsockopt_string(zmq.SUBSCRIBE, np.unicode(''))
while True:
try:
image_string = socket.recv_string()
raw_image = base64.b64decode(image_string)
image = np.frombuffer(raw_image, dtype=np.uint8)
frame = cv2.imdecode(image, 1)
cv2.imshow("frame", frame)
cv2.waitKey(1)
except KeyboardInterrupt:
cv2.destroyAllWindows()
break