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

use*_*189 4 python arrays numpy pickle

概观

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

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

786432 bits / 8 bits per byte =         98304 bytes
98304 bytes / 1024 bytes per kilobyte = 96    kilobytes
Run Code Online (Sandbox Code Playgroud)

这需要展平阵列

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

# flatten the array

[True, False, True, ..., False]
Run Code Online (Sandbox Code Playgroud)

从理论上讲,它可以表示为字节位,因为786,432位均匀地适合98,304字节; 每个数组应该能够由98,304个八位字符表示.

问题

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

其他信息/问题

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

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

我的代码/解决方案[求助]

客户

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()
Run Code Online (Sandbox Code Playgroud)

服务器

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()
Run Code Online (Sandbox Code Playgroud)

如您所见,我通过一系列1024字节的数据包通过TCP/SOCK_STREAM结束了每个阵列.

ali*_*i_m 6

您可以使用np.packbitsnp.bool数组的内容打包到np.uint8大小的1/8 的数组中,这样每个'packed'布尔元素只使用一个位.可以使用恢复原始阵列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]
Run Code Online (Sandbox Code Playgroud)

从这里开始最明显的方法是将打包的数组序列化为原始的字节串,通过UDP套接字管道,然后反序列化并在另一侧解压缩.numpy的本机序列化(.tostring()np.fromstring())可能比使用pickle或更快cPickle.

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