더북(TheBook)

여기서는 pow 함수에 대한 결괏값을 배열에 미리 담아두어 재사용하는 룩업 테이블lookup table 기법을 사용하여 IppGammaCorrection 함수를 개선해보려고 한다. 소스 6-11에서 사용된 pow 함수는 다음과 같은 형태를 갖는다.

pow((p[i] / 255.f), inv_gamma)

pow 함수의 인자로 사용되는 값 중에서 inv_gamma는 항상 동일한 값이며, 변하는 값은 p[i]뿐이다. 그리고 p[i]가 가질 수 있는 값은 그레이스케일 범위인 256개뿐이다. 그러므로 0부터 255까지의 그레이스케일 값에 대한 pow((p[i] / 255.f), inv_gamma) 값을 미리 계산해두고, 실제 매 픽셀에 대해 감마 보정을 수행할 때에는 미리 계산된 pow 함수 결괏값을 사용하면 큰 속도 향상을 얻을 수 있다. 이때 미리 계산한 pow 함수의 결괏값을 보통 배열 같은 저장 공간에 담아두는데, 이러한 배열을 룩업 테이블이라고 부른다. 룩업 테이블을 이용하여 개선한 IppGammaCorrection 함수 구현을 소스 6-12에 나타내었다.

소스 6-12 개선된 감마 보정 함수(IppEnhance.cpp)
void IppGammaCorrection(IppByteImage& img, float gamma)
{
    float inv_gamma = 1.f / gamma;

    float gamma_table[256];
    for (int i = 0; i < 256; i++)
        gamma_table[i] = pow((i / 255.f), inv_gamma);

    int size = img.GetSize();
    BYTE* p = img.GetPixels();

    for (int i = 0; i < size; i++)
    {
        p[i] = static_cast<BYTE>(limit(gamma_table[p[i]] * 255 + 0.5f));
    }
}

소스 6-12에서 gamma_table 배열은 [0, 1] 범위로 스케일된 그레이스케일 값에 대한 지수 변환 결괏값을 담고 있다. 그러므로 gamma_table 배열이 룩업 테이블의 역할을 하고 있는 것이다.

소스 6-11과 비교했을 때 소스 6-12는 pow 연산 호출 횟수가 급격하게 감소하였다. 예를 들어 256×256 크기의 영상에 대해 감마 보정을 수행할 경우, 소스 6-11은 256×256=65536번의 pow 연산을 수행한다. 반면에 소스 6-12는 영상의 크기에 무관하게 오직 256번의 pow 연산만을 수행하고, 영상의 전체 픽셀에 대해서는 단순한 산술 연산만을 수행하기 때문에 속도 향상을 꾀할 수 있다. 소스 6-12에서는 단순히 pow 연산 부분만 룩업 테이블을 만들었지만, 좀 더 최적화를 꾀한다면 BYTE 타입으로 형변환된 결괏값을 룩업 테이블로 만들어서 사용하여도 무방하다.

그림 6-26은 lenna 영상에 감마 보정을 수행한 결과이다. 그림 6-26(a)는 입력 영상이고, 그림 6-26(b)는 γ=2.2일 때의 보정 결과이다. 얼핏 보면 앞서 설명한 밝기 조절을 통해 밝아진 것과 유사해 보이지만, 픽셀 별로 밝아진 정도가 균일하게 증가하지 않는다는 점에서 차이가 있다. 그림 6-26(b)는 γ=0.6일 때의 보정 결과이다.

그림 6-26 감마 보정 실행 예제
(a) 입력 영상
(b) γ = 2.2
(c) γ = 0.6
신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.