如何更快地处理nparrays

时间:2019-03-18 07:12:21

标签: python arrays numpy opencv

我将两个图像加载到两个numpy数组中。我想得到它们的区别,并删除小于50的值,并将其其余部分设置为255,最终得到黑白图像的结果。

def count(base, image):
    x, y, z = base.shape
    sheet = np.zeros(base.shape)
    for i in range(x):
        for j in range(y):
            temp = 0
            for k in range(z):
                if base[i, j, k] > image[i, j, k]:
                    t = base[i, j, k] - image[i, j, k]
                    if t > 50:
                        temp = 255
                else:
                    t = image[i, j, k] - base[i, j, k]
                    if t > 50:
                        temp = 255
            sheet[i, j] = [temp, temp, temp]

    array = sheet[:, :, 0]

此代码执行了我需要执行的操作。但是如您所见,我为此功能使用了最简单的for循环,并且图像的大小为2000 * 2000,因此处理时间很长。我需要一种以更快的方式重写它的方法。

谢谢

2 个答案:

答案 0 :(得分:3)

向量化代码看起来很简单,除了一个陷阱:您的数据似乎是无符号的整数(从外观上看uint8),这需要额外的注意,因为它们经常下溢而产生意想不到的结果。例如,明显的np.abs(image-base)>50不能检测大于50的差异,实际上np.abs是对未签名数据的否定。仔细的翻译看起来更像

sheet = np.array([[0,0,0],[255,255,255]], 'u1')[((np.maximum(base, image)-np.minimum(base, image))>50).any(2).view('u1')]

sheet = np.array([[0,0,0],[255,255,255]], 'u1')[(np.abs(np.subtract(image, base, dtype='i2'))>50).any(2).view('u1')]

  1. 正确计算子像素的差异,

    • 第一个版本模仿您的if / else子句

    • 第二个强制差异值的签名结果类型为'i2'int16

  2. 检测到大于50的那些

  3. 用至少一个这样的子像素(any(2))标记像素,

  4. 将生成的布尔掩码转换为索引(.view('u1'))0和1

  5. ,并使用这些索引到模板数组中。

答案 1 :(得分:1)

大多数操作的工作方式与在相同大小的NumPy数组的标量上的工作方式相同。我将函数重新编写为

def count_new(base, image, thresh=50):
    # these are the pixel absolute value differences
    differences = np.abs(base - image)

    # whether the difference exceeds the threshold
    big_difference = differences > thresh

    # whether each pixel has at least one big difference
    big_difference = big_difference.any(axis=2)

    # return 255 where big differences, and 0 everywhere else
    return 255 * big_difference.astype(int)

希望注释使每一行的意图清楚。还检查了它是否与先前的输出相同

x = np.random.randint(256, size=(10, 11, 3))
y = np.random.randint(256, size=(10, 11, 3))
assert((count(x,y) == count_new(x,y)).all())

表明确实如此。