当迭代次数高达40,000时,在图像分析中加速"for-loop"

WBM*_*WBM 11 python performance for-loop numpy equality

这段代码的先决条件的细节很长,所以我会尽力总结.WB/RG/BYColor是基本图像,FIDO是应用于此基本图像的叠加.S_wb/rg/by是最终输出图像.WB/RG/BYColor与FIDO的大小相同.

对于FIDO中的每个唯一元素,我们希望计算基础图像中该区域的平均颜色.下面的代码执行此操作,但由于numFIDO非常大(最多40,000),这需要很长时间.

计算三个独立RGB通道的平均值.

sX=200
sY=200
S_wb = np.zeros((sX, sY))
S_rg = np.zeros((sX, sY))
S_by = np.zeros((sX, sY))
uniqueFIDOs, unique_counts = np.unique(FIDO, return_counts=True) 
numFIDOs = uniqueFIDOs.shape  
for i in np.arange(0,numFIDOs[0]):
    Lookup = FIDO==uniqueFIDOs[i]
    # Get average of color signals for this FIDO
    S_wb[Lookup] = np.sum(WBColor[Lookup])/unique_counts[i]
    S_rg[Lookup] = np.sum(RGColor[Lookup])/unique_counts[i]
    S_by[Lookup] = np.sum(BYColor[Lookup])/unique_counts[i]
Run Code Online (Sandbox Code Playgroud)

运行大约需要7.89秒,不会这么长,但这将包含在另一个循环中,所以它会累积起来!

我尝试过矢量化(如下所示),但我无法做到

FIDOsize = unique_counts[0:numFIDOs[0]:1]
Lookup = FIDO ==uniqueFIDOs[0:numFIDOs[0]:1]
S_wb[Lookup] = np.sum(WBColor[Lookup])/FIDOsize
S_rg[Lookup] = np.sum(RGColor[Lookup])/FIDOsize
S_by[Lookup] = np.sum(BYColor[Lookup])/FIDOsize
Run Code Online (Sandbox Code Playgroud)

数组大小匹配错误

cht*_*mon 5

根据我的时间,这比原始方法快10倍.我测试了这些数组:

import numpy as np

sX=200
sY=200

FIDO = np.random.randint(0, sX*sY, (sX, sY))
WBColor = np.random.randint(0, sX*sY, (sX, sY))
RGColor = np.random.randint(0, sX*sY, (sX, sY))
BYColor = np.random.randint(0, sX*sY, (sX, sY))
Run Code Online (Sandbox Code Playgroud)

这是我定时的部分:

import collections

colors = {'wb': WBColor, 'rg': RGColor, 'by': BYColor}
planes = colors.keys()
S = {plane: np.zeros((sX, sY)) for plane in planes}

for plane in planes:
    counts = collections.defaultdict(int)
    sums = collections.defaultdict(int)
    for (i, j), f in np.ndenumerate(FIDO):
        counts[f] += 1
        sums[f] += colors[plane][i, j]
    for (i, j), f in np.ndenumerate(FIDO):
        S[plane][i, j] = sums[f]/counts[f]
Run Code Online (Sandbox Code Playgroud)

可能是因为即使Python中的循环很慢,这也会减少数据的遍历.

请注意,如果存在少量唯一值,则原始版本会变得更快FIDO.对于大多数情况,这大致相同.


小智 3

这已经在 Scipy 中实现了,所以你可以这样做:

from scipy.ndimage.measurements import mean as labeled_mean

labels = np.arange(FIDO.max()+1, dtype=int)
S_wb = labeled_mean(WBColor, FIDO, labels)[FIDO]
S_rg = labeled_mean(RGColor, FIDO, labels)[FIDO]
S_by = labeled_mean(BYColor, FIDO, labels)[FIDO]
Run Code Online (Sandbox Code Playgroud)

这是假设FIDO包含相对较小的整数。如果不是这种情况,您可以通过 进行改造np.unique(FIDO, return_inverse=True)

对于 200x200 图像并包含从 0 到 40,000 的随机整数,这个简单的代码比原始代码快约 1000 倍FIDO