【发布时间】:2018-09-24 20:25:20
【问题描述】:
我有一个函数,我将调用 'rgb2something' 将 RGB 数据 [1x1x3] 转换为单个值(概率),循环遍历输入 RGB 数据中的每个像素结果相当慢。
我尝试了以下方法来加快转换速度。生成 LUT(查找表):
import numpy as np
levels = 256
levels2 = levels**2
lut = [0] * (levels ** 3)
levels_range = range(0, levels)
for r in levels_range:
for g in levels_range:
for b in levels_range:
lut[r + (g * levels) + (b * levels2)] = rgb2something(r, g, b)
并将 RGB 转换为转换后的概率图像:
result = np.take(lut, r_channel + (g_channel * 256) + (b_channel * 65536))
但是,生成 LUT 和计算结果仍然很慢。在 2 维中它相当快,但是在 3 维(r、g 和 b)中它很慢。我怎样才能提高它的性能?
编辑
rgb2something(r, g, b) 看起来像这样:
def rgb2something(r, g, b):
y = np.array([[r, g, b]])
y_mean = np.mean(y, axis=0)
y_centered = y - y_mean
y_cov = y_centered.T.dot(y_centered) / len(y_centered)
m = len(Consts.x)
n = len(y)
q = m + n
pool_cov = (m / q * x_cov) + (n / q * y_cov)
inv_pool_cov = np.linalg.inv(pool_cov)
g = Consts.x_mean - y_mean
mah = g.T.dot(inv_pool_cov).dot(g) ** 0.5
return mah
编辑 2:
我正在尝试实现的完整工作代码示例,我正在使用 OpenCV,因此欢迎使用任何 OpenCV 方法,例如 Apply LUT,以及 C/C++ 方法:
import matplotlib.pyplot as plt
import numpy as np
import cv2
class Model:
x = np.array([
[6, 5, 2],
[2, 5, 7],
[6, 3, 1]
])
x_mean = np.mean(x, axis=0)
x_centered = x - x_mean
x_covariance = x_centered.T.dot(x_centered) / len(x_centered)
m = len(x)
n = 1 # Only ever comparing to a single pixel
q = m + n
pooled_covariance = (m / q * x_covariance) # + (n / q * y_cov) -< Always 0 for a single point
inverse_pooled_covariance = np.linalg.inv(pooled_covariance)
def rgb2something(r, g, b):
#Calculates Mahalanobis Distance between pixel and model X
y = np.array([[r, g, b]])
y_mean = np.mean(y, axis=0)
g = Model.x_mean - y_mean
mah = g.T.dot(Model.inverse_pooled_covariance).dot(g) ** 0.5
return mah
def generate_lut():
levels = 256
levels2 = levels**2
lut = [0] * (levels ** 3)
levels_range = range(0, levels)
for r in levels_range:
for g in levels_range:
for b in levels_range:
lut[r + (g * levels) + (b * levels2)] = rgb2something(r, g, b)
return lut
def calculate_distance(lut, input_image):
return np.take(lut, input_image[:, :, 0] + (input_image[:, :, 1] * 256) + (input_image[:, :, 2] * 65536))
lut = generate_lut()
rgb = np.random.randint(255, size=(1080, 1920, 3), dtype=np.uint8)
result = calculate_distance(lut, rgb)
cv2.imshow("Example", rgb)
cv2.imshow("Result", result)
cv2.waitKey(0)
【问题讨论】:
-
你试过 numpy vectorise 和组合吗?
-
rgb2something看起来像什么? |是的,生成和使用 64 或 128 MB 的查找表效率不会很高(在 Python 中生成是 2^24 次迭代——解释器很慢——而且巨大的查找对缓存不是很友好)。如上述评论所述,矢量化方法(具有良好、可预测的访问模式)会好得多。 -
酷,我去看看。是的,我的意思是内存访问模式,内存是线性的。由于 CPU + 缓存的工作方式,最好按顺序(或以小步骤)读取内存 - 它确保大多数时候您需要的数据非常接近 CPU。另一方面,当您以随机模式访问非常大的内存块时,您需要的数据很有可能只在主内存中......这通常需要花费大约 100-150 个时钟周期来获取。
-
@RaymondTunstill 为什么不制作一个字典(本质上是一个哈希表),在需要时为每个
(r, g, b)元组计算rgb2something,并将其添加到字典中。这更简单,更易读。此外,在运行时,您最终可能只为一小部分 rgb 值计算rgb2something值,而不是像您当前所做的那样为所有 rgb 值计算它们。当然,这取决于您的具体用例。 -
@RohanSaxena 对于一个足够小的图像(少于生成 LUT 的 2^24 次迭代),只运行计算肯定会更快......虽然仍在解释器中运行,所以相对该死的慢。您提到的延迟初始化缓存在这种情况下可能会有所帮助(可能很大程度上取决于输入的类型)。不过,如果我们可以使用矢量化操作而不是在 interpeter 中循环,则可能会有一些加快速度的潜力。
标签: python performance numpy opencv lookup-tables