2012-12-13 42 views
3

所以这里是我想要做的事: 有这个图像服务器将在端口5003 发送数据就会传输数据的格式是如下的 1个字节图像类型(0 = raw,1 = JPEG) 然后接下来的4字节用于图像大小 然后将会有n字节,其顺序如下 2字节宽度,2字节高度,1字节用于B, 1个字节为R,对于G二进制数据的图像原始蟒蛇

1个字节

所以我想要做的是获取数据,并将其与下面的代码转换成图像:

#! /usr/bin/python 
import socket 
import sys 
import binascii 
from PIL import Image 
from StringIO import StringIO 


# Connect to the server image 
serverHost = 'localhost' 
serverPort = 5003 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.connect((serverHost, serverPort)) 

print >>sys.stderr, 'Connecting to host: ' + str(serverHost) 
print >>sys.stderr, 'and server Port: ' + str(serverPort) 

s.settimeout(1) 

#Receive the image type 
imageType = s.recv(1) 
print>>sys.stderr, 'received %r' %binascii.hexlify(imageType) 
print>>sys.stderr, 'Unpacked: ', int(binascii.hexlify(imageType), 16) 
received = imageType.__len__() 
print>> sys.stderr, "Received: ", received 

#Receive the image size 
imageSize = s.recv(4) 
print>>sys.stderr, 'received %r' %binascii.hexlify(imageSize) 
print>>sys.stderr, 'Unpacked: ', int(binascii.hexlify(imageSize), 16) 
received = imageSize.__len__() 
print>> sys.stderr, "Received: ", received 


#Receive the image Data 
imageData = '' 
received =0 
while(received < int(binascii.hexlify(imageSize), 16)): 
    buffer = s.recv(4096) 
    imageData += buffer 
    received += buffer.__len__() 
    print>> sys.stderr, "Received: ", received 

img = Image.fromstring('RGB', (1280, 720), imageData, 'raw') 

#img = Image.open(StringIO(binascii.hexlify(imageData))) 
img = img.convert('RGB') 
img.save('out.png') 

#file = open('test.png', 'w'); 
#file.write(imageData) 
#file.close() 

#When we receive the image, we send the acknowledgement 
s.send('OK') 
s.close()`enter code here` 

但每次我运行代码总是得到这样的错误

"Value error not enough Image Data" 

如果变化

img = Image.fromstring('RGB', (1280, 720), imageData, 'raw') 

img = Image.fromstring('BRG', (1280, 720), imageData, 'raw') 

我得到这个错误:

Value error: Unrecognized mode, 

任何人都知道如何解决这类问题?

+0

第二个错误是简单的因为PIL不支持“BRG”从字符串创建图像。第一个错误是由于您没有足够的图像数据来构建1280 * 720的图像。请检查len(imageData)== width * height * numchannels。另外,为什么不使用'struct'?除此之外,另一个可能的错误来源是服务器,而不是由您提供。作为一个建议,你还需要发送图像模式,否则你怎么知道你是否有'L','RGB'等等,作为原始jpg中的模式? – mmgp

+0

除了@mmgp所说的(struct结构模块上的+1)之外,你可能需要多次调用s.recv(),也就是's.recv(4)'可能返回少于4个字节(你可以调用' f = s.makefile('rb'); f.read(4)'确保读取4个字节或遇到EOF,使用'len(buff)'而不是'buff .__ len __()' – jfs

+0

您提到过“2个字节的宽度,2个字节的高度”,但我没有看到它被recv()编辑? –

回答

2

当服务器的代码和客户端都完全给出(但简化为只显示问题)时,最好调试这些问题。

因此,以下是基于您的初始代码和说明的非常基本的客户端。请注意0​​没有使用,它只是在那里,因为你提到你想区分JPEG和RAW。我总是假设收到的数据是RGB数据,您可以根据您的实际问题进行调整。这里的主要区别是使用struct,这是一种标准方式,以通用格式打包数据以通过网络发送并避免与字节排序相关的问题。此代码还希望获得图像的宽度和高度(不存在于您的代码中),因此您可以在客户端重新构建图像。

import socket 
import struct 
from PIL import Image 

def recv(sock, size): 
    data = '' 
    to_receive = size 
    while to_receive > 0: 
     data += sock.recv(size) 
     to_receive = size - len(data) 
    return data 

serv_host = '' 
serv_port = 5003 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.connect((serv_host, serv_port)) 

s.settimeout(1) 

image_type = struct.unpack('!b', recv(s, 1))[0] 
print "Image type: %d" % image_type 
image_size = struct.unpack('!i', recv(s, 4))[0] 
print "Image size: %d" % image_size 
image_width, image_height = struct.unpack('!hh', recv(s, 4)) 
print "Image dimensions: %d x %d" % (image_width, image_height) 

# Receive image data 
image_data = recv(s, image_size) 
print len(image_data) 

# When we receive the image, we send the acknowledgement. 
s.send('OK') 
s.close() 

img = Image.fromstring('RGB', (image_width, image_height), image_data) 
img.save('out.png') 

由于没有包含服务器,因此以下是一个简单的,尊重您所描述的协议。我没有打扰检查服务器中的完整接收数据。另请注意,此服务器仅运行在运行时在命令行中指定的单个映像。再次,适应你的问题。还要注意我没有发送图像模式,这可能是实际应用中的问题。

import sys 
import socket 
import struct 
from PIL import Image 

host = '' 
port = 5003 
backlog = 5 

serv_img = Image.open(sys.argv[1]) 
simg_size = serv_img.size 
serv_data = serv_img.tostring() 
data_size = len(serv_data) 

print "Serving data of size %d" % data_size 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
s.bind((host, port)) 
s.listen(backlog) 
while True: 
    client, address = s.accept() 

    client.sendall(struct.pack('!b', 1)) 
    client.sendall(struct.pack('!i', data_size)) 
    client.sendall(struct.pack('!hh', *simg_size)) 
    client.sendall(serv_data) 

    data = client.recv(2) 
    if data == 'OK': 
     print "OK", address 

    client.close() 

关于不使用__len__升高的音符仅仅是由于它是在Python,这是由len自己称为一个特殊的方法。如果你没有任何理由使用特殊方法,那就不要这样做。

0

您提到使用USARSim的图像服务器。下面是我使用从USARSim接收图像的代码(UT2004版):

def get_image(sock):  
    image_type = struct.unpack('b', sock.recv(1))[0]  
    image_size = struct.unpack('>i', sock.recv(4))[0] 

    if image_size < 250000:  
     image_data = "" 
     received = 0 
     while (received < image_size): 
      data = sock.recv(image_size-received) 
      received += len(data) 
      image_data += data   

     filename = "image_%s.jpg" % str(now()) 
     with open(filename, "wb") as f: 
      f.write(image_data) 

def write_ack(sock): 
    sock.send("OK") 

def main(): 
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    sock.connect((host, port)) 

    while True: 
     get_image(sock) 
     write_ack(sock)