简体   繁体   English

将整数列表转换为位列表 Python

[英]Convert list of integers to list of bits Python

I am currently trying to feed video data to a laser (we use the laser for communications).我目前正在尝试将视频数据馈送到激光器(我们使用激光器进行通信)。 The laser works through modulation, where we have 2 states total, equivalent to 0 and 1. Hence, in order for me to feed the laser the video data, I first need to convert it to bits.激光器通过调制工作,我们总共有 2 个状态,相当于 0 和 1。因此,为了向激光器提供视频数据,我首先需要将其转换为位。 My frames, which I get from a webcam with openCV, are represented by 2D arrays which contain 8-bit integers to get a greyscale image.我从带有 openCV 的网络摄像头获得的帧由 2D arrays 表示,其中包含 8 位整数以获得灰度图像。 Currently, I am transforming these arrays as follows:目前,我正在对这些 arrays 进行如下改造:

if __name__ == '__main__':
video = Video()

frame = video.getFrameBits()

Where the Video class is defined as:其中视频 class 定义为:

class Video:
# scale_percent: percent of original size of frame
def __init__(self, scale_percent=100):
    self.cap = cv2.VideoCapture(0)

    # Get one frame to figure out sizing constraints
    _, frame = self.cap.read()

    width = int(frame.shape[1] * scale_percent / 100)
    height = int(frame.shape[0] * scale_percent / 100)
    self.dim = (width, height)

# color: If true show color frames. Not yet implemented
def getFrame(self, color=False):
    _, frame = self.cap.read()

    frame = cv2.resize(frame, self.dim, interpolation=cv2.INTER_AREA)

    if not color:
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        return gray

def getFrameBits(self):
    frame = self.getFrame()

    for row in frame:
        for pixel in row:
            frame_bits.append(intToBits(pixel))
    
    return frame_bits

And the int to bits function as:并且位 function 的 int 为:

def intToBits(x):
    send = str(bin(x).lstrip('0b'))
    send = send.zfill(8)

    return send

The reason I am using the intToBits function is because I would like to be able to take this array that I called frame , and feed it directly into the laser.我使用 intToBits function 的原因是因为我希望能够将这个我称为frame的数组直接输入激光器。 With the current implementation, the leading zeros are not truncated from the array.在当前的实现中,前导零不会从数组中截断。 So I get an output like: [10010101,10010100,10010101,10010111,10010110,10010101,10010100,10010001,10010001,01011000,...]所以我得到一个 output 像: [10010101,10010100,10010101,10010111,10010110,10010101,10010100,10010001,10010001,01011000,...]

The problem with this whole code is that it runs much too slow on the micro-controller I have available.整个代码的问题在于它在我可用的微控制器上运行得太慢了。 It takes about 5 seconds to get a single frame, which is rather abysmal.获得一帧大约需要 5 秒,这是相当糟糕的。 My first thought is to get rid of the nested for loop in getFrameBits, as follows:我的第一个想法是去掉getFrameBits中嵌套的for循环,如下:

frame_bits = [intToBits(pixel) for row in frame for pixel in row]

This did improve the time, but I would like to see if it can be improved further.这确实缩短了时间,但我想看看是否可以进一步改进。 We are still taking about 1 second to get the frame, which is better, but we are expecting a larger sampling rate.我们仍然需要大约 1 秒来获取帧,这更好,但我们期望更大的采样率。

My next idea would be to code this in C and run it in Python, but I am not too familiar with C.我的下一个想法是在 C 中编写代码并在 Python 中运行它,但我对 C 不太熟悉。 So whilst I would be willing to do this, I wanted to make sure it was the correct direction to take.因此,虽然我愿意这样做,但我想确保这是正确的方向。

Are there some more ways I can optimize this code?还有其他方法可以优化此代码吗?

Thanks!谢谢!

A bit of bit-masking should do the trick:一点位掩码应该可以解决问题:

Along with a wee bit of vectorization - no need to write the C code in case where the under-the-hood built-in code of numpy, which is written in C already, has your back.除了一点点矢量化 - 无需编写 C 代码,以防 numpy 的引擎盖下内置代码已经写在 Z0D61F8370CAD1D412F70B84D143E2 中。

import numpy as np
import cProfile, pstats, io

input_size = 1000000
#since I don't have your image, I made do with a random sample of 8bit numbers.
test_input = np.random.randint(0, 256, input_size)
#to check that we get the correct result, set input_size to 2
#and uncomment the line below
#test_input = [255, 7]

#your function for the speed comparison purposes
def intToBits(x):
    send = str(bin(x).lstrip('0b'))
    send = send.zfill(8)
    return send

#note, that in this case x is the whole array, not just one number
#to make the full use of the vectorization
#also the output is not a bitfield, but a string
#the > 0 at the end is to convert the result into booleans.
#strictly speaking it isn't necessary if you are fine with 0 1 integers.
def binary_repr(x):
    return(
    np.dstack((
    np.bitwise_and(x, 0b10000000) >> 7,
    np.bitwise_and(x, 0b1000000) >> 6,
    np.bitwise_and(x, 0b100000) >> 5,
    np.bitwise_and(x, 0b10000) >> 4,
    np.bitwise_and(x, 0b1000) >> 3,
    np.bitwise_and(x, 0b100) >> 2,
    np.bitwise_and(x, 0b10) >> 1,
    np.bitwise_and(x, 0b1)
    )).flatten() > 0)

#starting the profiler.
pr = cProfile.Profile()
pr.enable()

#the two computations that we want to compare
a = []
for i in range(input_size):
    a.append(intToBits(test_input[i]))
print(a)
b = binary_repr(test_input)
print(b)

#the comparison
sortby = 'cumulative'
pr.disable()
s = io.StringIO()
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps.print_stats()
print(s.getvalue())

For the completeness sake, the profiler results:为了完整起见,分析器结果:

  ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  1000000    0.577    0.000    0.920    0.000 (intToBits)
        2    0.195    0.098    0.195    0.098 {built-in method builtins.print}
  1000000    0.125    0.000    0.125    0.000 {method 'lstrip' of 'str' objects}
  1000000    0.119    0.000    0.119    0.000 {built-in method builtins.bin}
  1000000    0.099    0.000    0.099    0.000 {method 'zfill' of 'str' objects}
  1000008    0.082    0.000    0.082    0.000 {method 'append' of 'list' objects}
        1    0.030    0.030    0.062    0.062 (binary_repr)

As you can see, even generating the data is taking more time than the switch to the bitwise representation.如您所见,即使生成数据也比切换到按位表示需要更多时间。 While you will need to modify this a little to fit into your code since the output format is a bit different - one large array instead of an array of arrays - it should be well worth it.虽然您需要稍微修改一下以适应您的代码,因为 output 格式有点不同 - 一个大数组而不是 arrays 数组 - 它应该非常值得。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM