2012-10-19 3 views
4

이것은 numpy에서 스트라이드를 사용하는 첫 번째 시도이며 다른 필터보다 간단한 반복에 비해 속도가 향상되었지만 아직 느리다 (그리고 느껴진다. 완전히 중복되거나 비효율적 인 최소한 하나 또는 두 가지).numpy/scipy로 회전 마스크를 최적화하는 방법

그럼 내 질문에 :이 코드를 사용하면 훨씬 빠르게 수행 할 수있는 더 좋은 방법이 있습니까?

알고리즘은 각 픽셀에 대해 9 가지 필터의 로컬 평가를 수행하고 설명 된대로 표준 편차가 가장 적은 것을 선택합니다 (Nagau 및 Matsuyma (1980) "복잡한 지역 사진의 구조 분석"을 구현하려는 시도). 이미지 분석 서적에서). 결과는 모두 부드러워 및 에지 선명 이미지 (당신이 저를 요구하는 경우에 아주 멋진!)

import numpy as np 
from scipy import ndimage 
from numpy.lib import stride_tricks 

def get_rotating_kernels(): 

    kernels = list() 

    protokernel = np.arange(9).reshape(3, 3) 

    for k in xrange(9): 

     ax1, ax2 = np.where(protokernel==k) 
     kernel = np.zeros((5,5), dtype=bool) 
     kernel[ax1: ax1+3, ax2: ax2+3] = 1 
     kernels.append(kernel) 

    return kernels 


def get_rotation_smooth(im, **kwargs): 

    kernels = np.array([k.ravel() for k in get_rotating_kernels()], 
       dtype=bool) 

    def rotation_matrix(section): 

     multi_s = stride_tricks.as_strided(section, shape=(9,25), 
      strides=(0, section.itemsize)) 

     rot_filters = multi_s[kernels].reshape(9,9) 

     return rot_filters[rot_filters.std(1).argmin(),:].mean() 

    return ndimage.filters.generic_filter(im, rotation_matrix, size=5, **kwargs) 

from scipy import lena 
im = lena() 
im2 = get_rotation_smooth(im) 

(거의 시간이 어쨌든이 소요되기 때문에 그냥 주석의 get_rotating_kernel 정말 최적화되지 않은)

입니다

내 netbook에서 126 초가 걸렸으며 Lena는 결국 아주 작은 이미지입니다.

편집 :

꽤 몇 평방 뿌리를 저장 rot_filters.var(1)rot_filters.std(1)을 변경할 수있는 제안을 얻었 그것은 5S의 순서로 뭔가를 면도.

+0

당신이 (예를 들어'cProfile'로)를 프로파일 링 시도 유무 :

windows_strides = a.strides + a.strides 

이제 우리는 우리가 윈도우를 생성하는 데 필요한 모든 정보가? – nneonneo

+0

실제로'rotation_matrix' 함수가 262144 번 호출되었으므로 구할 수있는 시간이 있기 때문에 실제로는 알지 못합니다. 그리고 그것은 그것이 나에게 도움이 될 것 같은 방법을 모른다는 것을 지적 할 것입니다. 그러나 어쩌면 그것은'cProfile'을 사랑하는 법을 배우지 못했을 것입니다 ... – deinonychusaur

답변

1

난 당신이 파이썬 + scipy를 사용하여 상당히 최적화 어려운 시간을 가질 것으로 판단된다. 그러나 부울 인덱싱을 사용하는 대신 as_strided을 사용하여 직접 rot_filters을 생성하여 약간의 개선을 만들 수있었습니다. 이것은 매우 단순한 n 차원 windows 함수를 기반으로합니다. (에 2 차원 회선 함수가 있다는 것을 깨닫기 전에 this problem을 풀도록 썼습니다.) 다음 코드는 내 컴퓨터에서 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() 

위의 기능 rotation_matrix2 다음과 같은 두 가지 기능에 해당합니다 (함께 실제로 본래의 기능보다 약간 느린, windows 더 일반화되어 있기 때문). 이는 원래 코드가하는 것과 정확히 동일합니다. 5x5 배열에 9 개의 3x3 창을 만든 다음이를 처리하기 위해 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 작품.

windows_shape = tuple(sa - sw + 1 for sa, sw in zip(a.shape, w)) 

우리는 N-D 배열의 N-D 배열로 windows 배열 생각할 수 있습니다 : 여기 그것이 작동하는 방법의 고장입니다.바깥 쪽 n-d 배열의 모양은 큰 배열 내에서 창의 자유도에 의해 결정됩니다. 모든 차원에서 윈도우가 취할 수있는 위치의 수는 더 큰 배열의 길이에서 윈도우의 길이를 뺀 길이와 같습니다. 이 경우 5x5 배열로 3x3 창을 가지므로 외부 2-d 배열은 3x3 배열입니다.

windows_shape += w 

내부 n-d 어레이의 모양은 창 자체의 모양과 같습니다. 여기서는 다시 3x3 배열입니다.

이제 걷습니다. 외부 n-d 배열과 내부 n-d 배열에 대한 스트라이드를 정의해야합니다. 그러나 그들이 동일하다는 것이 밝혀졌습니다! 결국, 창은 개별 색인이 배열을 통해 이동하는 것과 똑같은 방식으로 더 큰 배열을 이동합니다. 맞습니까?

return _as_strided(a, windows_shape, windows_strides) 
+0

나는 def 밖에서'windows_strides' 정의를 옮기고'std (1)'을'var (1)'로 바꿨습니다. 여러분이 지적했듯이, 파이썬처럼 현명하지 못하다는 것을 지적했습니다. – deinonychusaur

1

복잡한 픽셀 단위 + 이웃 작업의 경우 성능 향상을 위해 cython을 사용할 수 있습니다. 나중에 C 코드로 변환 된 파이썬 구문에 가까운 for 루프로 코드를 효율적으로 작성할 수 있습니다.

영감 위해 당신은 인스턴스에 대한 scikit 이미지 코드를 좀 걸릴 수 있습니다 :

https://github.com/scikit-image/scikit-image/blob/master/skimage/filter/_denoise.pyx

+0

나는 당신이 옳다고 생각합니다. 그것은 시간일지도 모릅니다. cython을 배울 수 있습니다. – deinonychusaur