【问题标题】:binary data to image raw python二进制数据图像原始python
【发布时间】:2012-11-30 21:37:09
【问题描述】:

所以这就是我想要做的: 有这个图像服务器将在端口 5003 上发送数据 它将传输的数据格式如下 图像类型为 1 个字节(0=原始,1=JPEG) 然后是图像大小的下一个 4 字节 然后之后将有n个字节,顺序如下 宽度 2 字节,高度 2 字节,B 1 字节,R 1 字节,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,

有人知道如何解决这类问题吗?

【问题讨论】:

  • 第二个错误很简单,因为 PIL 不支持“BRG”从字符串创建图像。第一个错误仅仅是因为您没有足够的图像数据来构建 1280 * 720 的图像。检查 len(imageData) == width * height * numchannels。另外,你为什么不使用 struct ?除此之外,另一个可能的错误来源是服务器,它不是您提供的。作为建议,您还需要发送图像模式,否则您将如何知道您是否有“L”、“RGB”等作为原始 jpg 中的模式?
  • 除了@mmgp 所说的(struct 模块上的+1),您可能需要多次调用 s.recv() 即,s.recv(4) 可能返回少于 4 个字节(您可以调用 f = s.makefile('rb'); f.read(4) 以确保读取 4 个字节或遇到 EOF。使用 len(buff) 而不是 buff.__len__()
  • 您提到“宽度为 2 个字节,高度为 2 个字节”,但我不认为它是 recv()ed?
  • mmgp:是的,在我将图像从 1280x720 调整为 320x240 后,错误不再存在。其实这是我第一次使用 Python,所以你能解释一下如何使用 struct ,对于服务器本身,它来自 USARSim Image Server。它提供了关于它将发送什么图像及其类型的信息 JF Sebastian,我可以尝试一下,顺便说一句 len(buff)buff.__len__( )? ArminRigo那部分,我只是从网上复制了一段代码,还有一个原因是我不会根据上面的信息如何构造图像,

标签: python image networking binary


【解决方案1】:

最好在完全给出服务器和客户端代码的情况下调试这些问题(但简化以仅显示问题)。

因此,以下是基于您的初始代码和描述的非常基本的客户端。请注意,image_type 没有被使用,它只是在那里,因为您提到您想要区分 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 本身调用。如果你没有任何充分的理由使用特殊方法,那就不要这样做。

【讨论】:

    【解决方案2】:

    您提到使用 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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-02
      • 2010-11-27
      • 2011-05-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-02
      相关资源
      最近更新 更多