Maddel
Maddel

Reputation: 55

Convert a byte array to single bits in a array [Python 3.5]

I am looking for a operation witch converts my byte array:

mem = b'\x01\x02\xff'

in something like this:

[ [0 0 0 0 0 0 0 1]
  [0 0 0 0 0 0 1 0]
  [1 1 1 1 1 1 1 1] ]

These are operations that I tried:

import numpy as np

mem = b'\x01\x02\xff' #define my input
mem = np.fromstring(mem, dtype=np.uint8) #first convert to int

#print(mem) give me "[  1   2 255]" at this piont

mem = np.array(['{0:08b}'.format(mem[b]) for b in mem]) #now convert to bin
data= np.array([list(mem[b]) for b in mem]) #finally convert to single bits

print(data)

This code will crash at line 4.. IndexError: index 255 is out of bounds for axis 0 with size 9 Otherwise, it crash at line 5.. IndexError: too many indices for array

These are my Questions:

Why are the number of spaces different after the conversion from hex to int?

Is that the reason that my next conversion from int to bin failed?

Finally, what is wrong with my list operation?

Thank you for your help! :)

Upvotes: 2

Views: 2648

Answers (4)

John1024
John1024

Reputation: 113984

Using unpackbits:

>>> import numpy as np
>>> mem = b'\x01\x02\xff'
>>> x = np.fromstring(mem, dtype=np.uint8)
>>> np.unpackbits(x).reshape(3,8)
array([[0, 0, 0, 0, 0, 0, 0, 1],
       [0, 0, 0, 0, 0, 0, 1, 0],
       [1, 1, 1, 1, 1, 1, 1, 1]], dtype=uint8)

Documentation

From help(np.unpackbits):

unpackbits(...)
unpackbits(myarray, axis=None)

Unpacks elements of a uint8 array into a binary-valued output array.

Each element of myarray represents a bit-field that should be unpacked into a binary-valued output array. The shape of the output array is either 1-D (if axis is None) or the same shape as the input array with unpacking done along the axis specified.

Upvotes: 2

Jal
Jal

Reputation: 215

mem = b'\x01\x02\xff'
[[int(digit) for digit in "{0:08b}".format(byte)] for byte in mem]

outputs:

[[0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 1, 0], [1, 1, 1, 1, 1, 1, 1, 1]]

Upvotes: 0

Qwerp-Derp
Qwerp-Derp

Reputation: 487

I'm fairly certain the problem with your code is that you're assuming the int in each item in the list will become 8 bits (so 2 will, in your assumption, return 00000010). But it doesn't (2 = 10), and that screws up your code.

For your last two lines, I think this should be fine:

data = [list(str(bin(x))[2:]) for x in mem]
for a in range(len(data)):
    while len(data[a]) < 8:
        data[a] = "0" + data[a]

str(bin(x))[2:] converts to binary (because it returns 0b1 for 1, you need to use [2:] to get 1).

The last chunk of code is to "pad" out your numbers with extra 0's.

Upvotes: 0

Sayali Sonawane
Sayali Sonawane

Reputation: 12609

To solve IndexError you can use numpy.ndindex:

import numpy as np

mem = b'\x01\x02\xff' #define my input
mem = np.fromstring(mem, dtype=np.uint8) #first convert to int

#print(mem) give me "[  1   2 255]" at this piont
mem=np.array(['{0:07b}'.format(mem[b]) for b in np.ndindex(mem.shape)])

data= np.array([list(mem[b]) for b in np.ndindex(mem.shape)]) #finally convert to single bits

print(data)

Output:

[['0', '0', '0', '0', '0', '0', '1'] ['0', '0', '0', '0', '0', '1', '0']
 ['1', '1', '1', '1', '1', '1', '1', '1']]

Upvotes: 0

Related Questions