如何将numpy bool数组打包成一串位?

时间:2015-04-27 22:40:54

标签: python arrays numpy pickle

概述

在numpy中,我有一系列bools。从图像中检索出数组;它是二维的,包含1024列和768行。我想通过以太网电缆推送这些数据。有多种方法可以做到这一点,但就我的目的而言,速度非常关键,因此记忆也非常重要。

由于每个数组中有1024 x 768 = 786432个元素(像素),并且每个元素都是TrueFalse,理论上可以将数组打包成98,304个未压缩的字节或96千字节。

786432 bits / 8 bits per byte =         98304 bytes
98304 bytes / 1024 bytes per kilobyte = 96    kilobytes

这需要展平数组

[ [True, False, True, ..., True]
  [False, True, True, ..., True]
  ...
  [True, True, False, ..., False] ]

# flatten the array

[True, False, True, ..., False]

理论上可以将其表示为字节位,因为786,432位均匀地适合98,304字节;每个数组应该能够用98,304个八位字符表示。

问题

如何通过以太网快速发送1024×768 bool个numpy阵列?我正在查看bitstring python库,但我不确定如何快速将numpy数组管道化为bitstring类。

其他信息/问题

具体来说,我将这些数组从Raspberry Pi 2发送到常规的Raspberry Pi。

  1. socketSOCK_STREAM是最快的解决方法吗?
  2. 鉴于RPis的计算能力,压缩和解压缩阵列会更快吗?如果是这样,压缩必须是无损的。
  3. 我已经研究过序列化numpy数组而不是使用bitstring内容,但是pickle对象太大而无法通过SOCK_STREAM发送。我对socket的东西做错了吗?
  4. 我的代码/解决方案[已解决]

    客户端

    import socket
    from scipy.misc import imread
    import numpy
    
    IP = '127.0.0.1'
    PORT = 7071
    ADDRESS = (IP, PORT)
    
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    image = imread('input.png')[:,:,[2]]
    image[image < 170] = 0
    image[image != 0] = 1
    image = numpy.reshape(image, (-1, 1))
    image = numpy.packbits(image)
    data = image.tostring()
    
    sock.connect(ADDRESS)
    for i in range(0, 93804, 1024):
        sock.send(data[i:i+1024])
    sock.shutdown(socket.SHUT_WR)
    sock.close()
    

    服务器

    import socket
    from scipy.misc import imsave
    import numpy
    
    IP = '127.0.0.1'
    PORT = 7071
    ADDRESS = (IP, PORT)
    
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(ADDRESS)
    sock.listen(1)
    
    while True:
        c, addr = sock.accept()
        data = ''
        package = c.recv(1024)
        while package:
            data += package
            package = c.recv(1024)
        image = numpy.fromstring(data, dtype=numpy.uint8)
        image = numpy.unpackbits(image)
        image = numpy.reshape(image, (-1, 768))
        imsave('output.png', image)
        c.close()
    sock.close()
    

    正如您所看到的,我通过一系列1024字节的数据包通过TCP / SOCK_STREAM结束了每个数组。

1 个答案:

答案 0 :(得分:6)

您可以使用np.packbitsnp.bool数组的内容打包到np.uint8数组的1/8大小的数组中,这样每个数组都可以打包#{1}}数组。布尔元素仅使用一个位。可以使用np.unpackbits恢复原始数组。

import numpy as np

x = array([0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1], dtype=np.bool)

print(x.itemsize, x.nbytes)
# (1, 16)

xp = np.packbits(x)
print(xp)
# [ 24 139]

print(xp.itemsize, xp.nbytes)
# (1, 2)

print(np.unpackbits(xp))
# [0 0 0 1 1 0 0 0 1 0 0 0 1 0 1 1]

从这里开始最明显的方法是将打包的数组序列化为原始字符串pipe it through a UDP socket,然后反序列化并在另一侧解压缩。 numpy的本机序列化(.tostring()np.fromstring())可能比使用picklecPickle快得多。

如果你想玩压缩,一个选择是使用本机zlib模块压缩字节串然后再通过管道,然后在另一侧解压缩。您是否从中看到任何好处将在很大程度上取决于输入阵列的可压缩程度,以及执行压缩/解压缩的硬件。