개발자 블로그

영상처리 강좌 - 4. 실전! 이미지 읽어보기 본문

영상처리강좌

영상처리 강좌 - 4. 실전! 이미지 읽어보기

로이드.Roid 2016. 1. 3. 19:09


  안녕하세요~
  영상처리 강좌 네 번째 시간입니다~!

  오늘 강좌의 제목은 '실전! 이미지 읽어보기' 입니다. 
  이전 강의에서 만들고 배워봤던 PBM, PGM 파일들은 아스키(ASCII) 형식의 파일입니다. 오늘은 아스키가 아닌 헥사(16진수)로 이루어진 PBM, PGM 파일을 읽는 방법에 대해 알아보도록 하겠습니다.


본 강좌를 처음부터 보시려면 아래 링크를 클릭하세요. (새창)
 ☞ 2015/08/10 - [영상처리강좌] - 영상처리 강좌를 시작합니다~!!


  PGM이나 PBM 파일 형식을 지원하는 이미지 편집기에서 PGM, PBM 파일로 변환을 하게 되면 우리가 만들었던 아스키코드 형식의 텍스트 파일이 만들어지는 것이 아니라 바이너리 형식의 파일이 만들어집니다. 이렇게 되면 파일을 개방하는 방법부터 읽는 방법까지 조금씩 달라지는데요. 실제 이러한 이미지를 가지고 실습을 하면서 설명드리도록 하겠습니다.


▲ 오늘 실습에 사용할 샘플이미지 입니다.


  위 파일의 확장자는 jpg 입니다. XnView를 이용해서 JPG 파일을 그레이영상인 PGM 파일로 변환한 뒤 실제 코드에서 어떻게 읽는지를 보여드리겠습니다. 여러분들도 각자 자신이 마음에드는 이미지를 가지고 실습을 진행 하시면 됩니다.


  XnView로 파일을 열어서 파일 > 다른 이름으로 저장 을 선택하신 후 팝업 창 하단의 파일 형식에서 PGM - Portable Grayscale 을 선택해서 PGM 파일로 변환해주시면 됩니다. 색상 모드를 선택하는 팝업창이 뜨면 그레이 스케일 256 을 선택하시면 됩니다.



▲ 256 항목을 선택하시고 확인 버튼을 클릭하세요.


그럼 변환 된 파일을 이미지뷰어와 헥사뷰어로 확인해 보겠습니다.



▲ 그레이 영상으로 변환이 되었습니다. 이미지의 사이즈는 440 x 293 입니다.



▲ 텍스트 에디터로 PGM 파일을 열어보았습니다.


  이미지뷰어로 확인한 것은 설명이 필요없을 것 같고요, 텍스트 에디터로 파일을 열어보면 파일 헤더를 확인 할 수 있습니다. 빨간색으로 표시한 부분이 PGM 파일의 헤더로, 매직넘버는 'P5', width는 440, height는 293, 마지막으로 최대 명암도 값은 255 입니다.

매직넘버 값이 기억이 안나시나요? 
그렇다면 이전 강의를 다시한번 참고하세요. 여기를 클릭하시면 해당 강좌로 이동합니다. (새창)



  파일의 구조는 '매직넘버' '개행' '너비' '공백' '높이' '개행' '최대명암도' '개행' '픽셀값들..' 순서로 이루어져 있습니다. 실제 코드에서 파일의 정보를 읽어들일 때도 이를 감안해서 코딩해줘야 합니다. 아래 코드의 파란색 밑줄처럼 scanf() 함수 호출 시 내부에 해당 문자들을 넣어주면 원하는대로 읽을 수 있습니다.



  텍스트 에디터로 헤더값은 확인이 되었지만 픽셀값은 전혀 알아볼 수가 없습니다. 사실 픽셀값을 눈으로 확인하는 일이 의미있는 일은 아니지만, 그래도 실제로 어떻게 이루어졌는지 궁금하기는 합니다. 바이너리 파일의 내용은 헥사뷰어(헥사 에디터)를 통해서 확인 할 수 있습니다.



▲ 헥사뷰어로 확인한 샘플 이미지


  파란색으로 선택한 부분이 헤더부분이고 9D 부터 실제 픽셀이 시작되는 부분입니다. 값의 변화폭이 크지 않은 것이 어느정도 이미지 같다는 느낌이 드시나요?? 16진수 9D의 10진수 값은 157입니다. 중간값이 127정도 되니깐 살짝 밝은 회색이라고 볼 수 있겠네요. 뭐, 위에도 언급했듯이 사실 이런식의 확인이 크게 의미있는것은 아닙니다.

혹시 16진수 <-> 10진수간 변환 프로그램이 필요하신가요? 그렇다면 아래 링크를 클릭하세요.
 ☞ 2011/03/01 - [프로그래밍/윈도우즈 프로그래밍] - 10진수 16진수 진수변환 프로그램 



  따라서 이번 실습의 결과 확인은 또 다른 이미지 파일을 만들어서 정상적으로 파일을 읽어들여서 처리했는지는 확인해 보도록 하겠습니다. 아래 함수는 새로운 pgm 파일을 만드는 역할을 하는 함수로 똑 같은 파일을 만들면 재미가 없으므로 살짝 밝게 변화를 줘보도록 하겠습니다.




  파일 저장은 아스키(ASCII)타입으로 하도록 하였고, 밝기 변화를 위해서 픽셀값에 +25를 해서 저장을 하고 있습니다. 이를 위해서 int 타입의 임시변수 하나를 선언해서 쓰고 있는데, unsigned char 타입이 아닌 int 타입을 사용하는 이유는 오버플로우(overflow) 방지를 위해서 입니다. 만약 기존 픽셀들과 같은 타입인unsigned char 타입을 사용하였다면, 수정전 값이 250인 픽셀은 250 + 25 = 275 이 나오므로 unsigned char 타입에는 그 값을 담아둘 수 없습니다. 따라서 그보다 큰 변수 타입인 int나 short 같은 변수를 사용해야 합니다.


  tmp변수의 값이 255를 초과하는 체크하는 로직도 동일한 이유로 들어간 것이고요. 
  이중 for문 안에 있는 fprintf() 함수에서 %d 뒤에 공백이 한 칸 있다는 것도 염두해 두셔야 합니다.(공백문자가 각 픽셀값을 구분짓는 딜리미터 역할을 합니다.)



  그럼 이번 강의의 핵심인 바이너리 형식의 PGM 이미지를 읽어들이는 부분의 코드를 살펴보도록 하겠습니다.




  이전 강좌의 아스키(ASCII) 형식의 이미지를 읽는 것과 다른 부분은 많지 않습니다. 빨간색으로 강조한 부분이 달라진 부분인데요. 바이너스 형식의 파일에 접근하기 위해서 fopen() 함수의 인자로 "rb"를 전달해 주었습니다. 또 픽셀값을 읽는 부분에서도 fread() 함수를 사용해서 unsigned char 변수 크기만큼 읽어들이도록하였습니다. 
  아스키 형식은 fscanf() 함수에서 "%d "로 숫자를 읽도록 한 반면, 바이너리 파일은 그냥 1byte씩 읽어주면 됩니다. 이는 아스키 형식은 픽셀값들이 white space(공백문자 - 개행, 공백, 탭 등)로 구분되지만, 바이너리 파일은 한 픽셀이 1byte 씩만 차지하기 때문입니다. 


  그럼 프로그램을 실행해서 눈으로 결과를 확인해 보도록 하겠습니다.


 



  결과 파일은 동일한 경로에 "result.pgm" 이란 파일명으로 저장하도록 하였습니다. 이미지 뷰어로 확인해 보니 실제로 영상이 살짝 밝게 변환되어 정상적으로 저장이 되었다는 것이 확인 되었습니다. 
  한편 입력 영상과 결과 영상은 모두 동일한 PGM 이미지 이지만 두 파일의 크기차이는 126KB, 477KB로 바이너리 형식으로 저장된 이미지 파일이 용량이 훨씬 적다는 것을 알 수 있습니다. 

  이번 강의에서는 바이너리 형식으로 저장된 PGM 파일을 읽는 방법과 프로그램에서 아스키 형식의 PGM 파일을 만드는 방법에 대해서 배웠습니다. 다음 강의는 이미지를 밝게, 어둡게, 반전효과 등에 대해서 알아보도록 하겠습니다. 

  혹시 궁금한 부분이나 잘못된 부분은 댓글로 남겨주세요~ 응원의 메시지도 환영입니다~ㅋ

  부족한 강의 봐주셔서 대단히 감사합니다.



이번 강의에 사용된 소스코드를 다운받으시려면 아래 파일을 클릭하세요.


※ 본 포스트에 대한 링크는 가능하지만, 퍼가는 것은 정중하게 사양합니다.


Comments