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

时间:2014-05-07 20:46:53

标签: python arrays numpy

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

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

相机可以高速运行到PC,最高可达80帧/秒。我很喜欢这种速度,但是知道Python不可行,因为它是一种脚本语言,但我想知道我能接近多少 - 是否是我在代码中遗漏的一些优化,线程化,或使用其他方法。我立刻认为打破最耗时的循环并将它们放入C代码中,但我没有太多的C代码经验,也不确定让Python与它内联进行交互的最佳方法,如果那样&# 39;可能。我使用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位(跨越8位/字节= 256位的32字节),即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每个像素

结果是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.25秒/帧,其中GetFrame函数是最弱的)来确定~0.02秒/帧的总执行时间。设备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的结果传递给另一个并行运行的循环。

1 个答案:

答案 0 :(得分:5)

有几个地方你可以大大加快速度。也许最明显的是重写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)

即使它没有加快这个功能的速度,因为它占据了大部分时间的读数,它已经为你提供了一个庞大的字节数组。然后,您可以继续ProcessRawData并尝试:

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

比你的版本快10倍。