우리가 이미지 자료라고 하면 대개 2차원 배열의 형태를 생각하게 됩니다. 그리고 이러한 배열을 화면상에 표출하여 눈으로 보게 되는데요. 이 때 이미지 배열의 인덱스에 대한 해석에 있어서 유의할 사항이 있습니다. 특히 Y축 방향의 인덱스의 값에 있어서 혼동하기쉬운 부분입니다. 저도 사실 가끔 헷갈립니다. 설명을 위하여 다음과 같은 2차원 배열을 하나 만들어봅시다. 그리고 이 배열의 값들을출력해보면 다음과 같습니다.
tmp = INDGEN(5, 5)-12
PRINT, tmp
-12 -11 -10 -9 -8
-7 -6 -5 -4 -3
-2 -1 0 1 2
3 4 5 6 7
8 9 10 11 12
출력된 값들을 보면 -12부터 +12까지의 범위를 갖는 25개의 정수값들이 5X5의 형태로 존재하는 2차원 배열임을 알 수 있습니다. 그러면 이 2차원 배열을 화면상에 표출해봅시다. 다음과 같이 IMAGE 함수를 사용해보면 그 결과는 다음 그림과 같습니다. 화소값이색상으로 대응되어 있는데, 가장 기본적으로 사용하는 흑백 계열 컬러 테이블에서는 낮은 값일수록 검은색에 가까와지고 높은 값일수록 흰색에 가까와집니다.
win_tmp = WINDOW(DIMENSIONS=[400, 400])
im_tmp = IMAGE(tmp, MARGIN=0, /CURRENT)
그런데 이미지의 모습을 앞서 출력한 실제값들과 비교해보면 약간 이상한 점이 눈에 띕니다. 여러분들도 보이시나요? 이미지상에서 보면 아래 부분이 어둡습니다. 즉 낮은 값들이 이미지상의 하단에 존재한다는 의미입니다. 그런데 앞서 출력해본 값들의 모습을 봅시다. 그러면 (-)의 범위에 속하는 낮은 값들은 이와 반대로 위쪽에서 보입니다. 즉, 2차원 배열의 값들을 실제로 출력해서 봤을 때의 위치와 이미지상에서 판별되는 위치는 Y축 방향이 서로 반대로 보인다는 얘기입니다. 좀 이상하죠?
이러한 현상의 원인은 IDL에서 2차원 배열을 이미지로 표출할 때, 이미지상의 왼쪽 하단부터 화소값을 부여하는 방식으로 처리되기 때문입니다. 즉, 배열 인덱스상으로 (0, 0)인 값은 이미지상에서는 왼쪽 최하단에 표시됩니다. 물론 색상은 이 값에 대응되도록 표시됩니다. 이미지상에서의 표출에서는 이렇습니다. 하지만 그냥 값을 PRINT문으로 출력할 때에는 (0, 0)인 값들부터 먼저 출력이 되고, 위의 예제의 경우 마지막 원소인 (4, 4)인 값이 맨 나중에 출력됩니다. 따라서 출력을 했을 때의 모습과 이미지상에서 나타나는 모습은 Y축 방향(세로 방향)에 있어서는 서로 반대가 된다고 보면 맞습니다.
사실 위와 같은 사실은 정당성이 충분히 있는 방식입니다. 이해하는데 있어서도 그리 어렵지는 않습니다. 우리가 이미지라는 것을 눈으로 해석하는데 있어서 가장 자연스러운 방식이기 때문에, 얼핏 보면 약간 요상해 보일 수도 있지만 그래도 충분히 수긍이 가는 방식입니다. 그런데 특정한 분야의 작업을 하는데 있어서는 이와 같은 방식에 대하여 다시 한번 유의해야 할 필요성이 있는 경우가 간혹 있습니다. 제가 예를 들고자 하는 "특정한" 작업은 Convolution에서 방향성 필터(Directional Filter)를 적용하는 경우입니다. 다음은 특정한 예제 이미지 자료에 대하여 X축 및 Y축 방향의 값의 변동치, 즉 1차 미분에 해당되는 값을 얻는 예입니다. 지형으로 비유한다면 경사가 커지는 부분에서는 미분값이 (+)가 되고, 경사가 낮아지는 부분에서는 미분값이 (-)가 됩니다.
img = HANNING(30, 30)*255
여기서 원본 데이터는 HANNING 함수를 사용하여, 마치 가운데 산봉우리가 있는 것과 유사한 형태의 2차원 배열로 만들었습니다. 그리고, X축 방향 및 Y축 방향의 경사도를 탐지할 수 있는 두 종류의 커널(kernel)을 생성하여 CONVOL 함수에 투입하였습니다. 그 결과는 다음 그림과 같습니다. 왼쪽부터 원본 데이터, X축 방향의 경사 탐지 결과, Y축 방향의 경사 탐지 결과입니다.
win = WINDOW(DIMENSIONS=[300*3, 300])
im1 = IMAGE(img, MARGIN=0, /CURRENT, LAYOUT=[3, 1, 1])
k = [[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]]; kernel for x-direction
imgf1 = CONVOL(img, k, /EDGE_TRUNCATE)
im2 = IMAGE(imgf1, MARGIN=0, /CURRENT, LAYOUT=[3, 1, 2])
k = [[1, 1, 1], [0, 0, 0], [-1, -1, -1]]; kernel for y-direction
imgf2 = CONVOL(img, k, /EDGE_TRUNCATE)
im3 = IMAGE(imgf2, MARGIN=0, /CURRENT, LAYOUT=[3, 1, 3])
이 그림에서 X축 방향의 경사 탐지 결과를 보면, 이해가 어렵지 않습니다. 산봉우리로 접어드는 부분에서 경사값이 높아지기 때문에 흰색으로 나타나고, 산봉우리를 지나 평지로 접어드는 부분에서는 경사값이 낮아지기 때문에 검정색으로 나타납니다. 그런데 Y축 방향의 경사 탐지 결과를 봅시다. 우선 이 작업을 위하여 사용된 커널의 형태를 보면 다음과 같습니다.
1 1 1
0 0 0
-1 -1 -1
눈으로 봐도 아래에서 위로 증가하는 방향, 즉 우리가 통상적으로 알고 있는 Y축과 같은 방향의 경사를 탐지하기 위한 커널임을 알 수 있습니다. 하지만, 결과 그림을 보면, 산봉우리로 접어들면서 경사가 높아지는 하단 부분이 오히려 값이 검정색에 가깝습니다. 산봉우리에서 평지로 접어들면서 경사가 낮아지는 상단 부분은 오히려 흰색에 가까와지는 것이 보입니다. 뭔가 이상하지 않습니까?
이러한 현상의 근본 원인은 커널의 형태를 이미지의 특성과 정 반대로 만들었기 때문입니다. 결론부터 말하면, Y축 방향의 경사를 탐지하기 위한 커널의 형태는 다음과 같아야 맞습니다. 그 원인은 위에서 언급한 여러가지 내용들을 참조한다면 이해가 쉬울 것 같습니다. 즉, 커널도 하나의 2차원 이미지이기 때문에, 출력해서 보이는 모습과는 Y축 방향을 반대 방향으로 생각해야 한다는 것이 핵심입니다. 따라서 커널의 형태를 이와 같이 수정하여 동일한 작업을 다시 수행하면, 우리가 기대했던 것처럼 다음과 같은 모습의 결과를 얻게 됩니다.
-1 -1 -1
0 0 0
1 1 1
k = [[-1, -1, -1], [0, 0, 0], [1, 1, 1]]; kernel for y-direction
이와 같은 배열 인덱스의 해석에 관한 내용은 사실 평상시 대부분의 작업에서는 큰 문제가 되지 않지만, 특정한 성격의 작업에서는 신경을 써줘야 할 경우가 있다는 점을 항상 염두에 두면 좋을 것 같습니다.
'IDL > Image Processing' 카테고리의 다른 글
COLORTABLE 함수를 이용한 컬러테이블의 생성 [1] (0) | 2016.04.29 |
---|---|
IMAGE_THRESHOLD 함수 소개 (0) | 2016.03.07 |
iPhone Wallpapers powered by IDL (0) | 2015.10.30 |
POLAR_SURFACE 함수의 활용 (0) | 2015.08.06 |
컬러테이블 뒤집어 사용하기 (0) | 2015.05.22 |