在Python

时间:2017-12-16 21:51:18

标签: python opencv computer-vision

我有一个巨大的图像数据集,不适合内存。我想计算meanstandard deviation,从磁盘加载图片。

我目前正在尝试使用wikipedia上的此算法。

# for a new value newValue, compute the new count, new mean, the new M2.
# mean accumulates the mean of the entire dataset
# M2 aggregates the squared distance from the mean
# count aggregates the amount of samples seen so far
def update(existingAggregate, newValue):
    (count, mean, M2) = existingAggregate
    count = count + 1 
    delta = newValue - mean
    mean = mean + delta / count
    delta2 = newValue - mean
    M2 = M2 + delta * delta2

    return existingAggregate

# retrieve the mean and variance from an aggregate
def finalize(existingAggregate):
    (count, mean, M2) = existingAggregate
    (mean, variance) = (mean, M2/(count - 1)) 
    if count < 2:
        return float('nan')
    else:
        return (mean, variance)

这是我当前的实现(仅为红色通道计算):

count = 0
mean = 0
delta = 0
delta2 = 0
M2 = 0
for i, file in enumerate(tqdm(first)):
    image = cv2.imread(file)
    for i in range(224):
        for j in range(224):
            r, g, b = image[i, j, :]
            newValue = r
            count = count + 1
            delta = newValue - mean
            mean = mean + delta / count
            delta2 = newValue - mean
            M2 = M2 + delta * delta2

print('first mean', mean)
print('first std', np.sqrt(M2 / (count - 1)))

此实现在我尝试的数据集的子集上足够接近。

问题是它非常缓慢,因此无法生存。

  • 有没有一种标准方法可以做到这一点?

  • 我如何调整这个以获得更快的结果或计算所有数据集的RGB均值和标准差,而无需同时以合理的速度将其全部加载到内存中?

3 个答案:

答案 0 :(得分:3)

您也可以使用opencv的方法meanstddev

cv2.meanStdDev(src[, mean[, stddev[, mask]]]) → mean, stddev

答案 1 :(得分:2)

由于这是一项数字繁重的任务(围绕矩阵或张量进行大量迭代),我总是建议使用擅长的库:numpy。

正确安装的numpy应该能够利用底层BLAS(基本线性代数子程序)例程,这些例程针对从内存层次结构角度操作浮点数组而优化。

imread应该已经给你numpy数组了。您可以通过

获取红色通道图像的重新整形的1d数组
import numpy as np
val = np.reshape(image[:,:,0], -1)

的平均值

np.mean(val)

和标准差

np.std(val)

通过这种方式,您可以摆脱两层python循环:

count = 0
mean = 0
delta = 0
delta2 = 0
M2 = 0
for i, file in enumerate(tqdm(first)):
    image = cv2.imread(file)
        val = np.reshape(image[:,:,0], -1)
        img_mean = np.mean(val)
        img_std = np.std(val)
        ...

增量更新的其余部分应该很简单。

完成此操作后,瓶颈将成为图像加载速度,受磁盘读取操作性能的限制。对于这方面,我怀疑使用多线程,因为根据我以前的经验,其他建议会有很多帮助。

答案 2 :(得分:0)

如果您不想使用包含整个数据集的数组将事物放入内存,则可以迭代计算

# can be whatever I just made this number up
global_mean = 134.0
# just get a per-pixel array with the vals for (x_i - mu) ** 2 / |x|
sums = ((images[0] - global_mean) ** 2) / len(images)

for img in images[1:]:
    sums = sums + ((img - global_mean) ** 2) / len(images)

# Get mean of all per-pixel variances, and then take sqrt to get std
dataset_std = np.sqrt(np.mean(sums))