IDL/New Graphics

새로운 그래픽의 IMAGE 기능 소개 [2]

이상우_IDL 2011. 7. 19. 15:34
728x90
오늘은 이미지를 일단 그리고 그 이미지위에 다각형, 선, 문자열 등을 추가하는 예제를 살펴보기로 하겠습니다. 이것은 어떤 이미지를 그리고 그 이미지에 대한 보조적인 설명의 역할을 하는 요소들을 삽입하는 경우입니다. 사실 이와 같은 기능은 우리가 파워포인트나 키노트와 같은 작업을 할 때 기본적으로 사용 가능한 기능이긴 합니다. 하지만 이미지상에서 특정한 좌표에 대하여 선이나 문자 등을 정확한 위치에 표출하고자 할 경우에는, 일반적인 프리젠테이션 소프트웨어에서 마우스 조작만으로는 한계가 있을 수도 있습니다. 어쨌든 중요한 것은 IDL의 새로운 그래픽 체계에서는 이러한 보조적인 역할의 annotation들도 비교적 쉽게 표출할 수 있다는 점을 확인해본다는 데에 의의를 두면 좋을 것 같습니다.

이번 예제에서는 이미지 하나를 표출하고 그 이미지상에서 특정 위치의 세부 영역을 설정한 다음 그 영역을 확대하여 따로 표출하고 그 확대된 이미지상에서 각 화소마다의 화소값을 해당 화소의 위치에 바로 표출해보도록 하겠습니다. 예제로 사용할 이미지는 다음과 같습니다. 이미지 파일은 이 글에 첨부파일로 올려놓습니다.


먼저 다음과 같이 이 이미지 파일을 읽고 2차원 배열로 저장해둡니다.

imfile = 'images/bw0405.jpg'

img = READ_IMAGE(imfile)

HELP, img

PRINT, MIN(img), MAX(img)


여기서 HELP 및 PRINT의 결과에서 볼 수 있듯이, 이 이미지는 1024X768의 크기를 갖고 0~255로 바이트스케일된 이미지입니다. 이 원본 이미지내에서 10X10의 크기를 갖는 서브 영역을 추출하려고 합니다. 여기서는 다음과 같이 화소 위치상으로 X방향으로 600~609, Y방향으로 390~399에 해당되는 위치를 추출하여 또 다른 2차원 배열로 저장합니다. 그리고 나중을 위하여 서브 이미지의 크기를 SIZE 함수로 얻고 이를 저장해둡니다.

x1 = 600

x2 = 609

y1 = 390

y2 = 399

sub_img = img[x1:x2, y1:y2]

sz = SIZE(sub_img, /DIM)


이렇게 원본 이미지와 서브 이미지를 각각 2차원 배열로 저장한 상태에서 원본 이미지부터 먼저 표출합니다. 다음과 같이 WINDOW 함수를 사용하여 이미지의 크기에 맞는 윈도우를 띄우고, IMAGE 함수를 사용하여 이미지를 표출합니다. 이 때 IMAGE 함수에서 MARGIN이라는 속성을 [0, 0, 0, 0]으로 설정하였는데, 이렇게 하면 상하좌우 여백공간을 남기지 않고 윈도우에 꽉 차게 표출하게 됩니다.

win1 = WINDOW(DIMENSIONS=[1024, 768])

image = IMAGE(img, MARGIN=[0, 0, 0, 0], /CURRENT)


그리고 다음과 같이 POLYGON이라는 함수를 사용하여 서브 이미지의 위치가 원본 이미지상에서 어디인지를 나타냅니다.

polygon = POLYGON([x1, x2, x2, x1], [y1, y1, y2, y2], COLOR='red', FILL_BACKGROUND=0, $

  /DATA, /CURRENT)


여기서 POLYGON 함수에 들어가는 필수 인자는 다각형의 꼭지점들의 X좌표 및 Y좌표의 값들입니다. 꼭지점들의 좌표는 원본 이미지의 화소 기반의 좌표가 되어야하므로 /DATA라는 속성이 설정되어 있습니다. 그리고자 하는 다각형인 직사각형의 꼭지점들의 X 및 Y 좌표값들이 POLYGON 함수의 첫번째 및 두번째 인자로 들어가 있습니다. 이 두 인자들은 다음 그림과 같은 방식으로 얻어진다고 보면 됩니다.



그러면 다음 그림과 같이 원본 이미지상에 서브 이미지의 위치가 붉은색 사각형으로 표시됩니다. 사각형이 잘 안보인다 싶으면 POLYGON 함수에서 두께나 색상 등의 속성들을 취향에 맞게 조정하면 됩니다.


이제 새로운 윈도우를 띄우고 여기에 10X10 크기의 서브 이미지를 좀 크게 표출합니다. 윈도우는 세로 방향으로 길게 하여 상단에는 서브 이미지 자체만 표출하고 하단에는 서브 이미지뿐만 아니라 각 화소마다의 화소값들도 표시하려고 합니다. 먼저 다음과 같이 WINDOW 함수로 새로운 윈도우를 띄우고, IMAGE 함수를 사용하여 상단에 서브 이미지를 표출합니다. 여기서 IMAGE 함수에 POSITION이라는 속성이 설정되어 있는데, 이 좌표는 기본설정인 normal좌표계를 사용하였습니다.

win2 = WINDOW(DIMENSIONS=[300, 600])

sub_image1 = IMAGE(sub_img, POSITION=[0.1, 0.52, 0.9, 0.98], /CURRENT)


앞서 원본 이미지를 표출하면서 서브 이미지의 위치를 붉은색 사각형으로 표시했었는데, 새로운 윈도우에서의 서브 이미지가 이 붉은색 사각형이라는 점을 강조하기 위하여 다음과 같이 POLYGON 함수를 사용하여 서브 이미지의 테두리를 붉은색 사각형으로 나타내었습니다. 여기서 POLYGON 함수에 인자로 들어간 X, Y 좌표들은 사각형의 4개의 꼭지점들의 위치인데, 이 좌표는 이 서브 이미지의 화소 기반의 좌표계가 되어야 합니다. 따라서 /DATA라는 속성이 들어가 있습니다.

polygon = POLYGON([0, sz[0], sz[0], 0], [0, 0, sz[1], sz[1]], COLOR='red', $

  FILL_BACKGROUND=0, TARGET=sub_image1, /DATA, /CURRENT)


일단 여기까지의 결과는 다음 그림과 같습니다.



여기서 한가지 더 눈여겨 볼 것은 POLYGON 함수에 들어가 있는 TARGET이라는 속성입니다. 이 속성은 /DATA 좌표계를 사용하고자 할 경우, 그 기준이 되는 그래픽 요소가 어떤 것인지를 명시하는 역할을 합니다. 물론 여기서는 바로 앞서 IMAGE 함수로 표출한 서브 이미지로 설정되어 있습니다. 사실 지금 이 상황에서는 굳이 TARGET이라는 속성을 설정하지 않아도 됩니다. 어차피 윈도우상에 그래픽 요소라고는 이거 하나 뿐이니까요. 하지만 윈도우상에 그래픽 요소들이 여럿 있을 경우라면 이 TARGET 속성이 꼭 필요해집니다. 바로 뒤이어 다음과 같이 윈도우의 하단부에 서브 이미지를 또 그릴 것이기 때문입니다.

sub_image2 = IMAGE(sub_img, POSITION=[0.1, 0.02, 0.9, 0.48], /CURRENT)


하단부의 서브 이미지에 대해서는 10X10 각 화소마다의 경계선을 다음과 같이 POLYLINE 함수를 사용하여 표출합니다. POLYLINE 함수의 사용법은 POLYGON 함수와 매우 유사합니다. 다만 X, Y 좌표값들을 인자로 주면 이 점들을 끝까지 이어서 다각형으로 만드느냐 아니면 시작과 끝이 있는 선으로 이어주느냐의 차이입니다. 여기서는 여러 개의 선들을 그려줘야 하므로 다음과 같이 반복문을 사용하였습니다. 

FOR i = 0, sz[0] DO pline = POLYLINE([i, i], [0, sz[1]], TARGET=sub_image2, /DATA)

FOR i = 0, sz[1] DO pline = POLYLINE([0, sz[0]], [i, i], TARGET=sub_image2, /DATA)


여기서는 선의 시작점 및 끝점에 대한 X, Y 좌표들을 인자로 주었고, 물론 이 좌표의 기준은 하단부 서브 이미지의 화소 기반이 됩니다. 따라서 TARGET 및 /DATA 속성이 사용되었습니다. 첫번째 반복문은 세로방향의 선들을 차례로 그리고, 두번째 반복문은 가로방향의 선들을 차례로 그리게 됩니다. 여기까지의 결과는 다음 그림과 같습니다.



이제 하단부의 서브 이미지의 각 화소마다 화소값을 문자열로 표출해보겠습니다. 이와 같이 문자열을 표출하고자 할 경우에는 TEXT라는 함수를 사용하면 됩니다. 마치 다이렉트 그래픽에서 XYOUTS와 유사한 역할을 한다고 보면 됩니다. 삽입할 문자열의 위치에 대한 X, Y 좌표값 및 해당 문자열값이 차례로 기본인자로 들어가는 방식입니다. 그런데 지금의 경우는 문자열을 하나만 넣는 것이 아니고 각 화소셀마다 넣어줘야 합니다. 따라서 반복문이 나와야 하겠죠. 일단 그 반복문의 내용은 다음과 같습니다.

FOR j = 0, sz[1]-1 DO BEGIN

  FOR i = 0, sz[0]-1 DO BEGIN

    str = STRTRIM(STRING(sub_img[i, j], FORMAT='(I5)'), 2)

    tt = TEXT(i+0.5, j+0.5, str, TARGET=sub_image2, /DATA, FONT_SIZE=10, $

      ALIGNMENT=0.5, VERTICAL_ALIGNMENT=0.5, COLOR='blue', /CURRENT)

  ENDFOR

ENDFOR


좀 복잡해 보일 수도 있겠지만, i는 X방향이고 j는 Y방향을 뜻합니다. 그리고 각 화소 위치마다 들어갈 문자열은 그 화소의 화소값이 되어야 하므로 이를 str이라는 문자변수로 먼저 만듭니다. 그리고 바로 TEXT 함수를 사용하여 이 문자열을 해당 위치에 표출합니다. 여기서 문자열의 위치 좌표 역시 하단부 서브 이미지의 화소 기반의 좌표가 됩니다. 따라서 TARGET 및 /DATA 속성은 앞서 POLYGON이나 POLYLINE 함수의 경우와 마찬가지 요령으로 사용되었습니다. 폰트의 크기나 색상은 FONT_SIZE, COLOR 속성으로 조정됩니다. 그리고 ALIGNMENT 및 VERTICAL_ALIGNMENT라는 속성들도 보이는데, 이들은 수평방향 및 수직방향의 문자 정렬 방식을 나타냅니다. 여기서는 주어진 좌표에 대하여 가로 및 세로 방향 모두 가운데 정렬을 하기 위하여 0.5라는 값이 사용되었습니다. 이와 같이 화소값들까지 표시된 최종적인 결과는 다음 그림과 같습니다.


오늘은 위와 같이 이미지를 그리고 그 위에 보충적인 설명을 위하여 필요한 각종 추가요소들을 삽입하는 예제를 살펴보았습니다. 기존에 소개했던 IMAGE 함수외에도 POLYGON, POLYLINE, TEXT 등 annotation에 필요한 함수들도 추가로 소개되었는데요. 좌표를 매기는 기준에 대한 이해만 확실히 된다면 비교적 쉽게 사용할 수 있는 함수들이므로 잘 기억해두시면 나중에 다른 그래픽 표출 작업에 있어서도 매우 요긴하게 사용될 것이라 생각됩니다.


bw0405.jpg
0.19MB
LIST