【问题标题】:High-speed alternatives to replace byte array processing bottlenecks替代字节数组处理瓶颈的高速替代方案
【发布时间】:2014-05-08 10:15:13
【问题描述】:

>> 见下方编辑

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

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

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


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

ReadStream: '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


最后,

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

在处理每 14 行之后,结果为 256x256 数组,这些字节以二进制形式读取(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 FPS!

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

【问题讨论】:

  • ftdi.read(RXcount) 需要多长时间?您可以return bytearray(RXdata) 代替几乎不需要时间的列表。
  • 在我的系统上(非常快),将 1 MB 字节串转换为 list 需要 13 毫秒。您应该将其保留为字节串,numpy 可以处理。
  • Python、C++ 和 C 标签,但只显示 Python 代码...请按预期使用标签。当然,您提到如果需要,您准备使用 C,但您承认从未使用过该语言...哦,此外:如果您编写标准 C,那么它可以在所有平台上编译,这就是 C 的意义
  • 我也怀疑你建立RowData 的方式真的(真的)很慢。在双重嵌套的for 循环中通过+ 进行字符串连接...是的,这可以加快速度。
  • @gnibbler,我改为bytearray(RXdata),它只将ReadStream 函数时间提高了0.001(现在为0.036 秒)。不过,每一点都有帮助。是的,@roippi,看着RowData,这当然是可疑的......嗯,我会看看如何改进

标签: python arrays numpy


【解决方案1】:

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

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

这要求ProcessedMatrixndarray 类型的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 倍。

【讨论】:

  • 太棒了!现在非常优雅,我现在得到 8 帧/秒(三个函数的总执行时间现在下降到 0.12 秒)。 np.unpackbits() 是一个很棒的功能!让我们看看是否还有其他人可以添加任何其他内容来从中挤出更多帧。非常感谢您的帮助和对细节的关注 - 谢谢!
猜你喜欢
  • 2023-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多