IDL/Image Processing

IDL 8.9의 Gabor Filter 기능 소개

이상우_idl 2023. 7. 4. 16:22
728x90
반응형

IDL 8.9 버전에서 새로 추가된 Gabor Filter 기능은 2차원 이미지에 대하여 적용 가능한 필터링 옵션이라고 볼 수 있으며 주로 경계선 추출(Edge Detection) 또는 텍스쳐 분석(Texture Analysis)에 사용되는 처리 기법입니다. IDL 8.9에서 이 기능을 사용하기 위해서는 GABOR_KERNEL 및 GABOR_FILTER 함수를 사용해야 합니다. 그래서 오늘은 이 기능에 관하여 관련 예제와 함께 소개를 해보고자 합니다.

 

Gabor 필터링 자체는 기본적으로는 컨볼루션(Convolution)의 일종이며 적용되는 커널(Kernel)의 세부 형태에 따라 결과가 달라지게 됩니다. 따라서 GABOR_KERNEL 함수를 사용하여 커널의 형태를 먼저 정의한 후, 이 커널 데이터를 대상 이미지 배열과 함께 GABOR_FILTER 함수에 투입하여 결과를 얻는 방식으로 작업을 해야 합니다. 그러면 예제 이미지 데이터를 사용하여 그 과정을 살펴보도록 합시다. 예제 이미지는 Gabor 필터링에 대한 기본적인 이해에 도움이 될만한 것을 사용하는 것이 좋을 것 같아서 아래와 같은 이미지 파일을 사용하고자 합니다.

 

letter_writing.jpg
0.01MB

 

먼저 IDL에서 이 원본 이미지를 읽고 표출해보는 과정은 다음과 같습니다.

 

ifile = 'letter_writing.jpg'
READ_JPEG, ifile, img, /GRAY
HELP, img
sz = SIZE(img, /DIM)
win0 = WINDOW(DIMENSIONS=sz, /NO_TOOLBAR)
i0 = IMAGE(img, MARGIN=0, /CURRENT)

 

원본 이미지는 바이트형 값들로 구성된 2차원 배열입니다. 그리고 위와 같이 SIZE 함수를 사용하여 이미지의 가로 및 세로 방향 크기(600, 299)를 추출하여 그래픽창을 크기에 맞게 띄우고 표출하는 과정에 의하여 표출된 원본 이미지의 모습은 다음과 같습니다.

 

 

이제 Gabor 필터링 처리에 사용될 커널을 정의해야 합니다. 이를 위하여 GABOR_KERNEL 함수를 다음과 같이 사용해봅시다.

 

kernel = GABOR_KERNEL(LAMBDA=7.5, SIGMA=3, THETA=!pi/2)
HELP, kernel

 

여기서는 커널의 세부적인 형태를 결정하는 역할을 하는 LAMBDA, SIGMA, THETA 등의 키워드들이 사용되었음에 주목해야 합니다. HELP에 의하여 출력된 내용을 보면, 여기서 사용될 커널에 해당되는 배열인 kernel은 19x19의 2차원 구조를 갖는 것으로 확인됩니다. 일단 이렇게 정의된 커널의 실제 모습을 보기 위하여 다음과 같이 별도의 그래픽창을 띄우고 커널 배열을 이미지 형태로 표출해봅시다.

 

win_k = WINDOW(DIMENSIONS=[600, 600], /NO_TOOLBAR)
i_k = IMAGE(kernel, MARGIN=0, /CURRENT)

 

표출된 모습은 다음과 같습니다.

 

 

이와 같이 마치 Y축 방향으로 퍼져나가는 파동과 같은 형태가 보입니다. 실제로 Gabor 필터링은 일종의 방향성 필터링(Directional Filtering)의 성격을 가지며, 해당 커널의 형태는 마치 특정한 방향으로 퍼져나가는 사인 곡선 형태의 물결(Sine Wave)와 같은 모습을 띕니다. 다만 분석 대상이 될 이미지의 특성에 따라서 그 패턴의 세부인자 값들을 조정하는 것이 필요합니다. 이러한 세부인자 값들을 여기서는 LAMBDA, SIGMA, THETA 등의 키워드를 통하여 조정한 것입니다. 이러한 키워드들에 관한 자세한 내용은 IDL 도움말의 GABOR_KERNEL 함수 관련 내용을 참조하면 됩니다.

 

이제 이 커널을 사용하여 이미지를 처리해봅시다. 이를 위해서는 GABOR_FILTER 함수를 다음과 같이 사용해야 합니다.

 

img_f = GABOR_FILTER(img, kernel)
HELP, img_f
PRINT, MIN(img_f), MAX(img_f)

 

여기서는 GABOR_FILTER 함수에 원본 이미지 배열인 img와 커널 배열인 kernel을 인수로 투입하여 그 결과를 img_f라는 배열로 얻었습니다. 그리고 일단 먼저 이 img_f 배열에 관한 정보들을 출력하였는데 그 내용을 보면 다음과 같습니다.

 

IMG_F           DOUBLE    = Array[600, 299]
      -65.680740       66.881438

 

여기서 주목해야 할 부분은 바로 최소 및 최대 값들인데 각각 약 -66, +67 정도의 값이 얻어졌습니다. 앞서 언급했듯이 Gabor 필터링은 기본적으로 방향성 필터링이기 때문에 이러한 값들은 특정 방향의 화소값 변동폭이 됩니다. 즉 여기서는 Y축 방향으로 화소값 변동이 가장 큰 경우가 이 정도라는 의미이며, (+)는 증가폭이고 (-)는 감소폭에 해당됩니다. 결국 원본 이미지 상에서 검정 배경에 흰색 문자 형태가 존재하는데, 그 색상이 검정에서 흰색으로 또는 흰색에서 검정으로 급격하게 변하는 부분들이 Gabor 필터링 결과에서 (+) 또는 (-)로 높은 값으로 나타난 것입니다. 마치 지형으로 비유한다면 고도가 급격히 상승하는 부분 또는 급격히 하강하는 부분에 해당될 것입니다. 그리고 한가지 더 주목해야 할 것은 Y축으로 양방향 모두에 대한 변화폭을 찾는다는 것입니다. 즉 기본적으로는 Y축의 방향이긴 하지만 정방향과 역방향의 경사도를 모두 찾아낸다는 것임에 유의할 필요가 있습니다. 그러면 필터링의 결과 이미지인 img_f의 모습을 다음과 같이 표출해봅시다.

 

win1 = WINDOW(DIMENSIONS=sz, /NO_TOOLBAR)
i1 = IMAGE(img_f, MARGIN=0, /CURRENT)

 

표출된 img_f의 모습은 다음과 같습니다.

 

 

이와 같이 Y축 방향으로 화소값 변동이 심한 부분들이 어디인지를 육안으로도 확인할 수 있습니다. 그러면 여기서 관심의 대상을 좀 더 좁혀보는 것도 괜찮을 것 같습니다. 이를 위하여 다음과 같이 마스킹(Masking) 기법을 동원해봅시다.

 

img_f_mask = img_f GE 40

 

여기서는 Gabor 필터링의 결과인 img_f에 대하여 화소값이 40보다 크냐 아니냐 여부를 1과 0으로 환산한 결과인 img_f_mask를 얻었습니다. 이 결과를 다음과 같이 별도의 그래픽창에 표출해봅시다.

 

win2 = WINDOW(DIMENSIONS=sz, /NO_TOOLBAR)
i2 = IMAGE(BYTSCL(img_f_mask), MARGIN=0, /CURRENT)

 

표출된 모습은 다음과 같습니다.

 

 

이 모습을 보면 원본 이미지 상에서 Y축의 양방향으로 화소값의 증가폭이 큰 부분들만 흰색으로 표시된 것을 확인할 수 있습니다. 물론 마스킹을 어떻게 하느냐에 따라 다양한 결과를 얻을 수도 있을 것입니다. 그러면 이번에는 이렇게 마스킹에 의하여 얻은 결과를 원본 이미지 상에 중첩하여 표출해봅시다. 다만 이러한 처리를 위해서는 약간의 추가적인 과정이 필요한데 그 내용은 다음과 같습니다.

 

img_f_mask = FLOAT(img_f_mask)
ww = WHERE(img_f_mask EQ 0)
img_f_mask[ww] = !values.f_nan

 

여기서는 마스킹 결과 이미지를 먼저 실수형으로 변환하고, 화소값들 중 0인 부분은 NaN으로 대체하였습니다. 그 다음에는 별도의 그래픽창을 띄우고 원본 이미지를 먼저 표출한 후, 방금 얻은 NaN이 포함된 마스크 이미지를 그대로 중첩하면 됩니다. 이러한 표출 과정은 다음과 같습니다.

 

ct = COLORTABLE(['red'])
win3 = WINDOW(DIMENSIONS=sz, /NO_TOOLBAR)
i3 = IMAGE(img, MARGIN=0, /CURRENT)
i3_o = IMAGE(img_f_mask, RGB_TABLE=ct, MARGIN=0, /CURRENT)

 

다만 여기서는 COLORTABLE 함수를 사용하여 우리의 목적에 맞는 특수한 컬러테이블을 별도로 생성하였습니다. 이렇게 하면 img_f_mask의 화소값들 중 1인 부분은 빨간색으로 표시되고 NaN인 부분은 아예 아무 색상도 대응되지 않습니다. 따라서 이렇게 중첩 표출을 하면 NaN인 부분은 그냥 투명하게 비춰지는 효과를 얻게 됩니다. 어쨌든 이러한 과정에 의한 표출의 결과는 다음과 같습니다.

 

 

이와 같이 Gabor 필터링에 의한 결과 이미지에 대하여 추가적으로 마스킹 처리를 한 결과를 원본 이미지에 중첩하면 이와 같은 표출 결과를 얻을 수 있습니다. 이렇게 하면 필터링의 결과를 원본 이미지와 쉽게 비교할 수 있도록 표출하는 것이 가능합니다. 즉 원본 이미지 상에서 Y축의 양방향으로 화소값이 급격하게 증가하는 부분들이 어디인지를 좀 더 쉽게 알 수 있습니다. 그리고 이번에는 마스킹만 다음과 같이 다르게 해볼 수도 있습니다.

 

img_f_mask = img_f LE -40

 

즉 Gabor 필터링의 결과인 img_f에 대하여 화소값이 -40보다 작냐 아니냐 여부를 1과 0으로 환산한 결과인 img_f_mask를 얻는 것입니다. 물론 그 외의 나머지 과정들은 모두 동일합니다. 이렇게 마스킹만 다르게 했을 경우의 결과는 다음과 같습니다.

 

 

이렇게 하면 원본 이미지 상에서 Y축의 양방향으로 화소값이 급격하게 감소하는 부분들이 어디인지를 좀 더 쉽게 알 수 있습니다. 어쨌든 Gabor 필터링 기능은 대략 이러한 방식으로 활용하면 됩니다. 물론 원본 이미지의 특성, 적용될 커널의 세부적인 패턴 등에 따라서 결과는 얼마든지 달라질 수 있기 때문에 분석의 대상이 될 이미지 데이터 및 분석 목적에 맞는 최선의 결과를 얻기 위해서는 다양한 시도들이 필요할 가능성이 높다는 점을 염두에 두어야 하겠습니다.

반응형