我正在尝试使用opencv通过python发送帧并抛出套接字。 图像作为字符串流发送,但是当我在服务器上重新制作图像时,字节的顺序不正确。
客户代码:
import socket
import numpy as np
import cv2
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
cap = cv2.VideoCapture(1)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while 1:
ret, frame = cap.read()
cv2.imshow('client', frame)
d = frame.flatten()
s = d.tostring()
#sock.sendall(s)
#print len(s)
for i in range(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()
服务器端:
import socket
import numpy as np
import cv2
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))
s = ""
while True:
for i in range(20):
data,addr = sock.recvfrom(46080)
s = s + data
#data, addr = sock.recvfrom(46080)
#s = s+data
frame = np.fromstring(s, dtype='uint8')
frame = frame.reshape(480, 640, 3)
#cv2.imwrite('frame.png',frame)
cv2.imshow('server', frame)
s=""
'''
if len(data) == 921600:
frame = np.fromstring(s, dtype='uint8')
frame = frame.reshape(480, 640, 3)
cv2.imshow('frame', frame)
s = ""
'''
if cv2.waitKey(1) & 0xFF == ord('q'):
break
框架客户端
框架服务器端
答案 0 :(得分:2)
不保证UDP数据报以任何特定顺序显示。在许多平台上,无论如何,localhost UDP最终还是有序的,或者至少在机器没有高负载时却最终还是有序的,但这在任何地方都不能保证。
因此,如果要通过UDP发送数据,则需要自行处理订单。
这意味着想出一个协议,该协议在每个帧中都包含某种索引或偏移量。例如,在发送方:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for framenum in itertools.count():
# etc.
#print len(s)
for i in range(20):
buf = struct.pack('>II', (framenum, i)) + s[i*46080:(i+1)*46080])
sock.sendto(buf, (UDP_IP, UDP_PORT))
在接收方:
s = [None]*20
for framenum in itertools.count():
for i in range(20):
data,addr = sock.recvfrom(46080)
frame, index = struct.unpack('>II', data[:8])
if frame == framenum:
s[idx] = data[8:]
if all(s):
framedata = ''.join(s)
# now we have a full frame to display
我还没有编写代码来处理从第2帧获取数据甚至还没有完成第1帧的情况,因为您必须考虑在这种情况下要做什么。扔掉框架1并开始收集框架2吗?显示第1帧的内容,用第0帧剩余的片段填充缺失的间隙?保留框架列表的清单,并在完成时立即显示每个清单?保留框架列表以及已经完成的列表,以便确保按顺序显示它们?使用时间戳记,以便如果第1帧的时间超过X ms并且尚未完成,则将其丢弃?
如果您是通过Internet而不是localhost进行此操作,则还有另一个问题:第1帧的最后一个块可能永远不会到达。显然,这会影响您的选择-如果您要在显示第1帧之前等待所有第1帧,则可能会永远挂起。您可以添加一种方法,让客户端要求服务器重新发送它认为应该已经到达的(frame, i)
,或者为客户端确认已看到的内容,以便服务器可以告知某些内容丢失,或者是客户端告诉服务器“很多东西失灵或丢失,变慢的一种方式”,……
所有这些以及更多这些都是针对视频流客户端的可行设计。因此,您必须选择所需的一个并实现它。
或者,如果您想要始终按顺序显示帧,则可能要使用TCP而不是UDP。在幕后,TCP只是发送一堆带有附加索引的数据包,但是它具有所有逻辑,可以按顺序将数据包放回原处,确认并重新发送丢失的数据包,当数据包丢失过高时放慢速度(并再次加快速度) (如果那是暂时性的问题)等等,那么您不必编写任何此类内容。您得到的只是字节流,其发送顺序完全相同。 (当然,这意味着您必须知道如何从下一条消息中划出一条消息,但是对于您而言,这是微不足道的:每条消息的长度恰好是921600字节,因此,您将一直循环读取直到拥有921600字节。 )