2017-04-26 5 views
1

현재 파이썬 2.7 OpenCV 3.1 용지에서 알고리즘을 구현하려고하지만 프로세스가 너무 오래 걸립니다.OpenCV 3.1 최적화

width, height = mr.shape[:2] 
Pm = [] 
for i in d: 
    M = np.float32([[1,0,-d[i]], [0,1,1]]) 
    mrd = cv2.warpAffine(mr, M, (height,width)) 
    C = cv2.subtract(ml, mrd) 
    C = cv2.pow(C,2) 
    C = np.divide(C, sigma_m) 
    C = p0 + (1-p0)**(-C) 
    Pm.append(C) 
ml, mrmrd이 CV2 객체와 d 있습니다

, p0sigma_m는 정수 :

나에게 문제를주고 내 코드의 섹션은 다음과 같이 보인다.

마지막 3 줄의 나누기 및 최종 수식이 여기 실제 문제입니다. 이 사이클의 모든 반복은 독립적이므로 이론적으로는 몇 개의 프로세서를 통해 'for 루프'를 분할 할 수 있지만 문제를 해결하는 대신 문제를 우회하는 게으른 접근 방법처럼 보입니다.

누구든지 이러한 계산을 더 빨리 수행 할 수있는 방법을 알고 있습니까?

+0

또한 OpenCV를 어떻게 작성했는지에 따라 getBuildInformation() 출력을 게시 할 수 있습니다. –

+0

@MarkSetchell'cv2.getBuildInformation()'의 출력이 너무 커서 메모에 쓸 수 없습니다. 당신은 그 산출물로부터 특별한 것을 생각하고 있습니까? – Mira

답변

1

우리는 numexpr module을 사용하여 모든 후자의 산술 연산을 하나의 평가 식으로 효율적으로 수행 할 수 있습니다. 따라서

다음 단계 :

C = cv2.subtract(ml, mrd) 
C = cv2.pow(C,2) 
C = np.divide(C, sigma_m) 
C = p0 + (1-p0)**(-C) 

가 하나의 식으로 대체 될 수 -

import numexpr as ne 
C = ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)') 

이의 물건을 확인하자.

def original_app(ml, mrd, sigma_m, p0): 
    C = cv2.subtract(ml, mrd) 
    C = cv2.pow(C,2) 
    C = np.divide(C, sigma_m) 
    C = p0 + (1-p0)**(-C) 
    return C 

검증 - - 데이터 세트의 다양한 크기에서

In [28]: # Setup inputs 
    ...: S = 1024 # Size parameter 
    ...: ml = np.random.randint(0,255,(S,S))/255.0 
    ...: mrd = np.random.randint(0,255,(S,S))/255.0 
    ...: sigma_m = 0.45 
    ...: p0 = 0.56 
    ...: 

In [29]: out1 = original_app(ml, mrd, sigma_m, p0) 

In [30]: out2 = ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)') 

In [31]: np.allclose(out1, out2) 
Out[31]: True 

타이밍 - FUNC으로 원래의 접근 방식 주위에

In [19]: # Setup inputs 
    ...: S = 1024 # Size parameter 
    ...: ml = np.random.randint(0,255,(S,S))/255.0 
    ...: mrd = np.random.randint(0,255,(S,S))/255.0 
    ...: sigma_m = 0.45 
    ...: p0 = 0.56 
    ...: 

In [20]: %timeit original_app(ml, mrd, sigma_m, p0) 
10 loops, best of 3: 67.1 ms per loop 

In [21]: %timeit ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)') 
100 loops, best of 3: 12.9 ms per loop 

In [22]: # Setup inputs 
    ...: S = 512 # Size parameter 

In [23]: %timeit original_app(ml, mrd, sigma_m, p0) 
100 loops, best of 3: 15.3 ms per loop 

In [24]: %timeit ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)') 
100 loops, best of 3: 3.39 ms per loop 

In [25]: # Setup inputs 
    ...: S = 256 # Size parameter 

In [26]: %timeit original_app(ml, mrd, sigma_m, p0) 
100 loops, best of 3: 3.65 ms per loop 

In [27]: %timeit ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)') 
1000 loops, best of 3: 878 µs per loop 

5x 큰 배열에 대한 더 나은 속도 향상과 다양한 크기에서 속도 향상 !

사이드 노트로, 마지막 단계에서 추가하는 대신 초기화 된 배열을 사용하는 것이 좋습니다. 따라서 우리는 루프에 들어가기 전에 out = np.zeros((len(d), width, height))/np.empty을 초기화하고 마지막 단계에서 출력 배열에 out[iteration_ID] = C을 할당 할 수 있습니다.

+0

자세한 답변 해 주셔서 감사합니다. numexpr을 사용하여 빠른 구현을 시도했으며 약 4 배의 속도 향상이있었습니다. – Mira

+0

@Mira 굉장! 대부분의 시나리오에서'cv2 '를 이길 수 없으므로'numexpr'을 통해 좋은 경쟁과 승리를 얻는 것이 좋습니다! – Divakar

+0

np.empty()에 관한 답변에 대한 간단한 질문입니다. 나는 당신이 그것을 어떻게 사용할 것인지 정말로 이해하지 못했습니다. np.zeros() 초기화 대신 사용합니까? 또한 np.zeros() 접근 방식을 시도해 보았을 때 성능이 약간 향상 될 수 있지만 프로그램 실행을 몇 초 만에 측정 할 때의 차이는 100 분의 1 초입니다. 어떤 제안을 주셔서 감사합니다;) – Mira