2012-12-13 87 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)