Python numpy/scipy中旋转掩模的优化实现
这是我第一次尝试在numpy中使用STERPS,与不同过滤器上的简单迭代相比,它确实提高了速度,但它仍然非常慢(感觉至少有一两件事情是完全冗余或低效的) 所以我的问题是:是否有更好的方法来执行此操作或对我的代码进行调整,从而显著加快速度 该算法对每个像素执行9个不同滤波器的局部评估,并选择标准偏差最小的滤波器(我尝试实现Nagau和Matsuyma(1980)“复杂区域照片的结构分析”,如图像分析书中所述)。结果是一个平滑和边缘锐化的图像(如果你问我的话,这很酷!) (只是一个注释,Python numpy/scipy中旋转掩模的优化实现,python,image-processing,numpy,scipy,Python,Image Processing,Numpy,Scipy,这是我第一次尝试在numpy中使用STERPS,与不同过滤器上的简单迭代相比,它确实提高了速度,但它仍然非常慢(感觉至少有一两件事情是完全冗余或低效的) 所以我的问题是:是否有更好的方法来执行此操作或对我的代码进行调整,从而显著加快速度 该算法对每个像素执行9个不同滤波器的局部评估,并选择标准偏差最小的滤波器(我尝试实现Nagau和Matsuyma(1980)“复杂区域照片的结构分析”,如图像分析书中所述)。结果是一个平滑和边缘锐化的图像(如果你问我的话,这很酷!) (只是一个注释,get\u
get\u rotating\u内核
没有真正优化过,因为几乎没有在那里花费时间)
在我的上网本上,它花了126秒,而莉娜毕竟是一个相当小的图像
编辑:
我建议修改<代码> RoTyFaster。STD(1)到<代码> RoTyFaster。var(1)< /Cord>保存相当多的平方根,并以5s的顺序擦除某物。< /P> < P>对于复杂的每个像素+邻域操作,您可以考虑使用Cython来改进性能。它允许以接近python的语法高效地编写循环代码,稍后转换为C代码
要获得灵感,您可以查看scikit图像代码,例如:我相信,使用Python+
scipy
进行重大优化将非常困难。然而,我通过使用as_strip
直接生成rot_过滤器,而不是通过布尔索引,实现了一个小小的改进。这是基于一个非常简单的n维windows
函数。(在我意识到scipy
中存在2d卷积函数之前,我编写了它来解决这个问题)下面的代码在我的机器上提供了适度的10%加速;有关其工作原理的说明,请参见下文:
import numpy as np
from scipy import ndimage
from numpy.lib import stride_tricks
# pass in `as_strided` as a default arg to save a global lookup
def rotation_matrix2(section, _as_strided=stride_tricks.as_strided):
section = section.reshape(5, 5) # sqrt(section.size), sqrt(section.size)
windows_shape = (3, 3, 3, 3) # 5 - 3 + 1, 5 - 3 + 1, 3, 3
windows_strides = section.strides + section.strides
windows = _as_strided(section, windows_shape, windows_strides)
rot_filters = windows.reshape(9, 9)
return rot_filters[rot_filters.std(1).argmin(),:].mean()
def get_rotation_smooth(im, _rm=rotation_matrix2, **kwargs):
return ndimage.filters.generic_filter(im, _rm, size=5, **kwargs)
if __name__ == '__main__':
import matplotlib.pyplot as plt
from scipy.misc import lena
im = lena()
im2 = get_rotation_smooth(im)
#plt.gray() # Uncomment these lines for
#plt.imshow(im2) # demo purposes.
#plt.show()
windows_shape = tuple(sa - sw + 1 for sa, sw in zip(a.shape, w))
上面的函数rotation\u matrix2
相当于以下两个函数(这两个函数加起来实际上比原始函数慢一点,因为windows
更通用)。这正是您的原始代码所做的——将9个3x3窗口创建为一个5x5数组,然后将其重塑为一个9x9数组进行处理
def windows(a, w, _as_strided=stride_tricks.as_strided):
windows_shape = tuple(sa - sw + 1 for sa, sw in zip(a.shape, w))
windows_shape += w
windows_strides = a.strides + a.strides
return _as_strided(a, windows_shape, windows_strides)
def rotation_matrix1(section, _windows=windows):
rot_filters = windows(section.reshape(5, 5), (3, 3)).reshape(9, 9)
return rot_filters[rot_filters.std(1).argmin(),:].mean()
windows
适用于任何维度的数组,只要该窗口具有相同数量的维度。下面是它的工作原理:
import numpy as np
from scipy import ndimage
from numpy.lib import stride_tricks
# pass in `as_strided` as a default arg to save a global lookup
def rotation_matrix2(section, _as_strided=stride_tricks.as_strided):
section = section.reshape(5, 5) # sqrt(section.size), sqrt(section.size)
windows_shape = (3, 3, 3, 3) # 5 - 3 + 1, 5 - 3 + 1, 3, 3
windows_strides = section.strides + section.strides
windows = _as_strided(section, windows_shape, windows_strides)
rot_filters = windows.reshape(9, 9)
return rot_filters[rot_filters.std(1).argmin(),:].mean()
def get_rotation_smooth(im, _rm=rotation_matrix2, **kwargs):
return ndimage.filters.generic_filter(im, _rm, size=5, **kwargs)
if __name__ == '__main__':
import matplotlib.pyplot as plt
from scipy.misc import lena
im = lena()
im2 = get_rotation_smooth(im)
#plt.gray() # Uncomment these lines for
#plt.imshow(im2) # demo purposes.
#plt.show()
windows_shape = tuple(sa - sw + 1 for sa, sw in zip(a.shape, w))
我们可以将windows
数组看作是n-d数组中的n-d数组。外部n-d阵列的形状由较大阵列内窗口的自由度决定;在每个维度中,窗口可以占据的位置数等于较大数组的长度减去窗口的长度加上一。在本例中,我们将3x3窗口转换为5x5数组,因此外部的二维数组是3x3数组
windows_shape += w
内部n-d阵列的形状与窗口本身的形状相同。在我们的例子中,这也是一个3x3阵列
windows_shape += w
现在是大踏步。我们必须定义外部n-d阵列和内部n-d阵列的跨距。但事实证明他们是一样的!毕竟,窗口在较大的数组中移动的方式与单个索引在数组中移动的方式相同,对吗
windows_strides = a.strides + a.strides
现在我们有了创建窗口所需的所有信息:
return _as_strided(a, windows_shape, windows_strides)
您是否尝试过对其进行分析(例如使用cProfile
)?事实上,自从我发现rotation\u matrix
函数调用262144次后,我就没有这样做过,因为可以节省时间。无论它指向哪一部分,我仍然不知道它会对我有什么帮助……但也许只是我还没有学会爱cProfile
…我将windows\u-strips
定义移到def之外,并将std(1)
更改为var(1)
正如您所指出的,我认为在python方面没有更多的工作要做。