2014-12-09 4 views
3

아래 코드는 객체 감지 프로그램에서 집중적으로 호출되며 실행 시간은 약 80 %입니다. 상당히 속도를 높이는 방법이 있습니까? CPU에서 LBP를 계산하기 위해 아래의 코드를 빠르게하는 방법은 무엇입니까?

#define CALC_SUM_(p0, p1, p2, p3, offset) ((p0)[offset] - (p1)[offset] - (p2)[offset] + (p3)[offset]) 
inline int calc_lbp2(float *p[], int offset) 
{ 
    int cval = CALC_SUM_(p[5], p[6], p[9], p[10], offset); 

    return (CALC_SUM_(p[0], p[1], p[4], p[5], offset) >= cval ? 128 : 0) | // 0 
      (CALC_SUM_(p[1], p[2], p[5], p[6], offset) >= cval ? 64 : 0) | // 1 
      (CALC_SUM_(p[2], p[3], p[6], p[7], offset) >= cval ? 32 : 0) | // 2 
      (CALC_SUM_(p[6], p[7], p[10], p[11], offset) >= cval ? 16 : 0) | // 5 
      (CALC_SUM_(p[10], p[11], p[14], p[15], offset) >= cval ? 8 : 0)| // 8 
      (CALC_SUM_(p[9], p[10], p[13], p[14], offset) >= cval ? 4 : 0)| // 7 
      (CALC_SUM_(p[8], p[9], p[12], p[13], offset) >= cval ? 2 : 0)| // 6 
      (CALC_SUM_(p[4], p[5], p[8], p[9], offset) >= cval ? 1 : 0); 
} 

나는 SSE를 시도했지만 프로그램 (원래 실행 시간은 약 170 밀리)에 대한 자세한 50ms의 비용 :

inline int calc_lbp_sse(float *p[], int offset) 
{ 
    static unsigned short bits[] = {0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002, 0x0001}; 
    short c = CALC_SUM_(p[5], p[6], p[9], p[10], offset); 
    __m128i a = _mm_setr_epi16 
       (
        CALC_SUM_(p[0], p[1], p[4], p[5], offset), 
        CALC_SUM_(p[1], p[2], p[5], p[6], offset), 
        CALC_SUM_(p[2], p[3], p[6], p[7], offset), 
        CALC_SUM_(p[6], p[7], p[10], p[11], offset), 
        CALC_SUM_(p[10], p[11], p[14], p[15], offset), 
        CALC_SUM_(p[9], p[10], p[13], p[14], offset), 
        CALC_SUM_(p[8], p[9], p[12], p[13], offset), 
        CALC_SUM_(p[4], p[5], p[8], p[9], offset) 
       ); 
    __m128i b = _mm_setr_epi16(c, c, c, c, c, c, c, c); 

    __m128i res = _mm_cmplt_epi16(b,a); 
    unsigned short* vals = (unsigned short*)&res; 

    return ((vals[0]&bits[0]) | (vals[1]&bits[1]) | (vals[2]&bits[2]) | (vals[3]&bits[3]) | 
      (vals[4]&bits[4]) | (vals[5]&bits[5]) |(vals[6]&bits[6]) |(vals[7]&bits[7])); 
} 
+1

지금은 SSE를 사용하여 단일 위치에서 LBP 평가의 속도를 높이고 있습니다. 코드 s.t를 리팩터링하십시오. 당신은 8 또는 16 연속 픽셀에 대한 LBP를 연속적으로 평가하고 있습니다. 이것은 훨씬 잘 작동 할 수 있습니다. –

+1

또한 LBP 평가는 본질적으로 추악한 메모리 액세스 패턴을 가지고 있으며, 특히 많은 기능과 이미지가있는 경우 캐시 미스가 많이 발생할 수 있습니다. –

+1

모든 '...> = cval? 64 : 0' 식 표현식으로'(...> = cval) << 6'과 같은 식으로 분기를 제거 할 수 있습니까? – japreiss

답변

1
내가 200,000,000 번 내 데스크톱 컴퓨터에서 함수를 실행

를 그리고 5.3을했다 초. 이것에

int cval = CALC_SUM_(p[5], p[6], p[9], p[10], offset); 

: 그럼이 라인 변경

float cval = CALC_SUM_(p[5], p[6], p[9], p[10], offset); 

내가 같은 테스트를 reran을하고 지금은 3.0 초 걸렸습니다. 이제는 LBP에 익숙하지 않지만 의도적으로 중심 값을 int로 변환하지 않은 것으로 보입니다. LBP에 대해 읽은 것에서는 이웃 값을 중심 값과 비교하는 것입니다. 그러나 int로 변환하는 것이 실제로 중요하다면이 대답을 무시하십시오.

제쳐두고 japreiss가 ? :<< 6으로 대체하여 제안한 것을 시도했지만 정확히 동일한 속도를 얻었습니다. 그래서 분명히 컴파일러는 이미 그것을 멀리 최적화했습니다 (저는 gcc -O3을 사용하고 있습니다).

+0

저는 실제로 LBP를 직접 구현했습니다. (그리고 OP 코드는 OpenCV의 깊은 곳에서 제공된다는 것을 알고 있습니다.) 당신이 발견 한 것이 그럴듯하다는 것을 확인할 수 있습니다. 어떤 종류의 유형 변환이 필요한 경우, 성능은 개로갑니다. LBP 평가를 완전히 다시 작성하는 데 더 많은 이득을 얻었습니다.하지만 이는 매우 특수화 된 프로세서를위한 것이 었으며이 마진은 너무 작아서 어떻게 수행했는지 설명 할 수 없었습니다. –