最近我写了算法来量化RGB图像。每个像素由(R,G,B)矢量表示,并且量化码本是一对三维矢量。需要将图像的每个像素映射到(例如,“替换为”)最接近欧氏距离的码本像素(更准确地说,是欧氏平方)。 我这样做了:
class EuclideanMetric(DistanceMetric):
def __call__(self, x, y):
d = x - y
return sqrt(sum(d * d, -1))
class Quantizer(object):
def __init__(self, codebook, distanceMetric = EuclideanMetric()):
self._codebook = codebook
self._distMetric = distanceMetric
def quantize(self, imageArray):
quantizedRaster = zeros(imageArray.shape)
X = quantizedRaster.shape[0]
Y = quantizedRaster.shape[1]
for i in xrange(0, X):
print i
for j in xrange(0, Y):
dist = self._distMetric(imageArray[i,j], self._codebook)
code = argmin(dist)
quantizedRaster[i,j] = self._codebook[code]
return quantizedRaster
......它的功能非常好,我的Pentium Core Duo 2.2 GHz,4 Gigs内存和2600 * 2700像素的图像差不多800秒:(
有没有办法对此进行一些优化?也许是其他算法或某些特定于Python的优化。
UPD :我尝试使用平方欧几里德,但仍然花了很多时间。
答案 0 :(得分:4)
一个简单的优化是放弃sqrt
调用。 x与sqrt(x)是单调的,因为你不需要实际距离,只需要最小距离,而是使用x ^ 2。因为sqrt很贵所以应该有所帮助。
这种技巧在使用距离时会被大量使用。例如,如果您有距离阈值,则可以使用阈值^ 2并在距离计算中删除sqrt。实际上,只有在需要绝对距离时才需要sqrt。对于相对距离,请删除sqrt。
更新:可能需要进行算法更改。现在,您将每个码本矢量与每个像素进行比较。它会加快速度,减少距离计算的次数。
使用kd-tree可能会做得更好,这会减少从O(codebook)到O(log(codebook))的每个像素的搜索。我从来没有在python中做过这个,但是一些谷歌搜索给了一个可能有效的实现here。
答案 1 :(得分:1)
您可以使用scipy.cluster.vq
中的矢量量化函数vq
。
答案 2 :(得分:0)
如果X
非常大,那么您打印的i
相当多,这可能会严重影响性能。如需不太具体的答案,请继续阅读。
为了找出你的过程中的瓶颈在哪里,我建议一个时间装饰器,就像
一样。from functools import wraps
import time
def time_this(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
finish = time.time()
elapsed = (finish - start) * 1000
print '{0}: {1} ms'.format(func.__name__, elapsed)
return result
return wrapper
我曾经在某个地方找到过这个,并且一直用它来弄清楚我的代码速度慢的地方。您可以将算法分解为一系列单独的函数,然后使用此装饰器修饰函数以查看每个函数调用需要多长时间。然后,这是一个摆弄哪些语句的函数,以查看改进装饰函数运行时间的函数。主要是你正在寻找两件事:1)需要很长时间才能执行的语句,或者2)执行时间不一定需要很长时间的语句,但这些语句执行的次数很多,性能的改善很小对整体表现影响很大。
祝你好运!