我试图在同一网络中的两台计算机上制作网络摄像头流, 所以我在互联网上做了一些研究,我发现这个客户端和服务器代码是客户端
import socket
import numpy as np
import cv2
UDP_IP = '127.0.0.1'
UDP_PORT = 999
cap = cv2.VideoCapture(0)
while(True):
ret, frame = cap.read()
cv2.imshow('frame',frame)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
d = frame.flatten ()
s = d.tostring ()
for i in xrange(20):
sock.sendto (s[i*46080:(i+1)*46080],(UDP_IP, UDP_PORT))
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
这是服务器:
#Server prog
import socket
import numpy
import time
import cv2
UDP_IP="127.0.0.1"
UDP_PORT = 999
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))
s=""
while True:
data, addr = sock.recvfrom(46080)
s+= data
if len(s) == (46080*20):
frame = numpy.fromstring (s, dtype=numpy.uint8)
frame = frame.reshape(480,640,3)
cv2.imshow("frame",frame)
s=""
if cv2.waitKey(1) & 0xFF == ord('q'):
break
有一些我无法理解的行
for i in xrange(20):
sock.sendto (s[i*46080:(i+1)*46080],(UDP_IP, UDP_PORT))
他为什么要用它? (我知道在UDP中你不能发送一个巨大的文件而你需要发送部分内容,但为什么会这样?为什么要46080?)
并在服务器本身if len(s) == (46080*20):
+当您运行服务器和客户端时,服务器收到的视频流滞后且帧重复出现..
答案 0 :(得分:0)
46080因为每帧由640x480 RGB像素组成,每个通道一个字节,因此每个像素三个字节,并发送20个:
>>> 640 * 480 * 3 / 20
46080
如果您的摄像头捕获不同分辨率的帧,则该值应与46080不同。大小为46k的帧可能对您的网络来说有点大,所以您可能想要尝试发送超过20个。
s[i*46080:(i+1)*46080]
表示大小为46080"的第i个片段。这是所谓的切片符号的一个例子:
>>> a = [0, 1, 2, 3, 4, 5]
>>> a[0:2] # take element #0 and #1
[0, 1]
>>> a[2:4] # take element #2 and #3
[2, 3]
这是一个简单但功能强大的工具,因此我建议learn more了解它。您还使用numpy - numpy支持a lot of additional ways来切割n维数组。有点复杂,但更强大。
关于滞后流。
首先,UPD帧可能会丢失,重新排序和重复。为了避免重复和重新排序的数据报,您可以为您发送的每个数据报附加一个序列号,并在接收器上有一个优先级队列。
其次,我怀疑cv2.imshow
是显示流畅视频的不错选择。你可能想尝试ffmpeg。
第三,确保发件人足够快,以至少20-30 fps的速度捕获和发送帧。如果没有,尝试将图像采集+处理和传输拆分为单独的线程。我的盲目猜测是你在sock.sendto
花了很多时间。不要犹豫是否要对您的代码进行分析。