python从套接字流接收图像

时间:2018-08-19 20:02:53

标签: python image python-2.7 sockets opencv

我正在尝试使用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

框架客户端

框架服务器端

1 个答案:

答案 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字节。 )