python - 替代字节数组处理瓶颈的高速替代方案

标签 python arrays numpy

>> 请参阅下面的编辑 <<

我正在通过 pyUSB 使用 FTDI D2xx 驱动程序通过串行处理来自特殊像素化 CCD 相机的数据。

相机可以以高带宽运行到 PC,高达 80 帧/秒。我很喜欢这样的速度,但我知道 Python 不可行,因为它是一种脚本语言,但我想知道我能得到多接近 - 无论是我在代码中遗漏的一些优化,线程,或使用其他方法。我立即认为打破最耗时的循环并将它们放入 C 代码中,但我对 C 代码没有太多经验,如果可能的话,我不确定让 Python 与其进行内联交互的最佳方式。我有使用 SciPy/Numpy 在 Python 中大量开发的复杂算法,这些算法已经过优化并且具有可接受的性能,所以我需要一种方法来加速数据的获取以反馈给 Python,如果这是最好的方法.

困难,以及我使用 Python 而不是其他语言的原因,是因为需要能够轻松地跨平台运行它(我在 Windows 中开发,但将代码放在嵌入式 Linux 板上,使独立系统)。如果您建议我使用其他代码,例如 C,我将如何跨平台工作?我从来没有在 Windows 和 Linux 之间编译过像 C 这样的低级语言,所以我想确定这个过程 - 我必须为每个系统编译它,对吗?你有什么建议?

这是我的函数,具有当前的执行时间:

读取流: 'RXcount' 为 114733,表示设备读取,从字符串格式化为等效字节

返回字节列表 (0-255),表示二进制值

当前执行时间:0.037 秒

def ReadStream(RXcount):
    global ftdi
    RXdata = ftdi.read(RXcount)
    RXdata = list(struct.unpack(str(len(RXdata)) + 'B', RXdata))
    return RXdata

ProcessRawData:将字节列表重塑为与像素方向匹配的数组

修剪掉一些不需要的字节后,结果为 3584x32 数组。

数据是唯一的,因为每个 14 行块代表设备上一行像素的 14 位(跨 32 字节@8 位/字节 = 256 位跨),即 256x256 像素。处理后的数组有 32 列字节,因为每个字节以二进制形式表示 8 个像素(32 字节 * 8 位 = 256 像素)。仍在研究如何做到这一点... I have already posted a question for that previously

当前执行时间:0.01 秒 ... 不错,只是 Numpy
def ProcessRawData(RawData):
    if len(RawData) == 114733:
        ProcessedMatrix = np.ndarray((1, 114733), dtype=int)
        np.copyto(ProcessedMatrix, RawData)
        ProcessedMatrix = ProcessedMatrix[:, 1:-44]
        ProcessedMatrix = np.reshape(ProcessedMatrix, (-1, 32))
        return ProcessedMatrix
    else:
        return None

最后,

获取帧:该设备有一种模式,它只输出一个像素是否检测到任何东西,使用数组的最低位(每 14 行) - 获取该数据并为每个像素转换为 int

结果为 256x256 数组,在处理每 14 行之后,这些字节是要作为二进制读取的字节(跨 32 个字节 ... 32 个字节 * 8 位 = 跨 256 个像素)

当前执行时间:0.04 秒
def GetFrame(ProcessedMatrix):
    if np.shape(ProcessedMatrix) == (3584, 32):
        FrameArray = np.zeros((256, 256), dtype='B')
        DataRows = ProcessedMatrix[13::14]
        for i in range(256):
            RowData = ""
            for j in range(32):
                RowData = RowData + "{:08b}".format(DataRows[i, j])
            FrameArray[i] = [int(RowData[b:b+1], 2) for b in range(256)]
        return FrameArray
    else:
        return False

目标:

我想根据您提出的任何建议将总执行时间设定为 ~0.02 秒/帧(目前为 0.25 秒/帧,GetFrame 函数最弱)。设备 I/O 不是限制因素,因为它每 0.0125 秒输出一个数据包。如果我缩短了执行时间,那么我是否可以与某些线程并行运行采集和处理?

让我知道您建议的最佳前进道路 - 感谢您的帮助!

编辑,感谢@Jaime:

现在的功能是:
def ReadStream(RXcount):
    global ftdi
    return np.frombuffer(ftdi.read(RXcount), dtype=np.uint8)

... 时间 0.013 秒
def ProcessRawData(RawData):
    if len(RawData) == 114733:
        return RawData[1:-44].reshape(-1, 32)
    return None

...时间 0.000007 秒!
def GetFrame(ProcessedMatrix):
    if ProcessedMatrix.shape == (3584, 32):
        return np.unpackbits(ProcessedMatrix[13::14]).reshape(256, 256)
    return False

... 时间 0.00006 秒!

因此,使用纯 Python,我现在能够以所需的帧速率获取数据!在对 D2xx USB 缓冲区和延迟计时进行了一些调整后,我将其计时在 47.6 帧每秒!

最后一步是是否有任何方法可以使其与我的处理算法并行运行?需要某种方式来传递 GetFrame 的结果到另一个并行运行的循环。

最佳答案

有几个地方可以显着加快速度。也许最明显的是重写GetFrame :

def GetFrame(ProcessedMatrix):
    if ProcessedMatrix.shape == (3584, 32):
        return np.unpackbits(ProcessedMatrix[13::14]).reshape(256, 256)
    return False

这要求 ProcessedMatrix成为 ndarray类型 np.uint8 ,但除此之外,在我的系统上它的运行速度提高了 1000 倍。

与您的其他两个功能,我认为在 ReadStream你应该做这样的事情:
def ReadStream(RXcount):
    global ftdi
    return np.frombuffer(ftdi.read(RXcount), dtype=np.uint8)

即使它不会大大加快该函数的速度,因为它大部分时间都在读取,它已经为您提供了一个 numpy 字节数组来处理。有了它,您就可以继续访问 ProcessRawData并尝试:
def ProcessRawData(RawData):
    if len(RawData) == 114733:
        return RawData[1:-44].reshape(-1, 32)
    return None

这比您的版本快 10 倍。

关于python - 替代字节数组处理瓶颈的高速替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23528107/

相关文章:

Python 列表仅在等于 n 个前任时才保留值

python - 在Python中使用负数对字符串进行切片时,0被禁用?

Python:最后的While循环不断生成新的随机卡,如何让它生成一次并停止?

php - 跟踪 2 个键数组

python - MySQL fetchall() - 如何在字典中而不是在元组中获取数据

javascript - 为什么这个 3 维数组不起作用?

javascript - 开 Jest : test that an array contains none of these values?

python - 如何访问滚动运算符中的多列?

Python numpy 数组——关闭最小区域

python - 在两个二维数组中查找匹配行的索引