1. 디지털 이미지
- 디지털 화면은 수많은 점들로 이루어져 있으며, 색상을 가지는 점 하나를 화소(pixel, picture element)라고 한다.
- 화소는 RGB(Red, Green, Blue) 세 개의 단일 색의 강도를 각각 조절하여 색상을 표현한다.
- 색의 종류가 3개인 이유는 눈의 망막에 있는 시세포가 인간의 경우 대부분 세 가지로 이루어져 있기 때문이다.
- 특이한 점은 일부 인간들과 새들은 시세포 종류가 하나씩 더 있어서 색을 조금 세밀하게 인식하거나 일부 자외선 영역을 감지할 수 있다.
- 이렇게 구성된 디지털 화면에 표실될 이미지를 저장하는 방법 중 가장 단순한 방법은, 각 점 하나하나의 색상 값을 저장하는 방식이다.
- 위의 방식을 래스터(raster) 또는 비트맵(bitmap) 방식의 이미지라 하며, 보통 한 점마다 각 색상별로 8비트를 사용하여 0 ~ 255 사이의 값(2 ^ 8 = 256)으로 해당 색의 감도를 표시한다.
- 반면 벡터(vector) 방식의 이미지는 상대적인 점과 선의 위치를 방정식으로써 기록해 뒀다가, 확대 및 축소에 따라 디지털 화면의 각 화소에 어떻게 표현될지를 재계산하기에 깨짐이 없다.
- 우리가 주로 다루는 파일 중에는 사진 파일들이 래스터 방식이고, 확대 축소가 자유로이 가능한 글꼴들이 주로 벡터 방식이다.
- 디지털 화면의 화소로 표시되는 이미지를 저장하는 방법이 여러 가지가 있듯이, RGB로 표시되는 색상값도 RGB형식으로만 저장될 필요가 없다. 다른 방법으로는 흑백(grayscale), YUV 방식도 있다.
- 또한 디지털 화면에서 색감을 수치적으로 조작할 때 좀 더 직관적으로 이해할 수 있는 HSV(Hue 색상, Saturation 채도, Value 명도)도 있고, 인쇄에서는 CMYK(Cyan, Magenta, Yellow, Black)의 방식도 있다.
- 이렇게 색을 표현하는 다양한 방식을 각각 컬러 스페이스(color space, 색 공간)라고 하며, 스페이스를 구성하는 단일 축을 채널(channel)이라고 한다.
- 이런 색상 정보를 그대로 저장하기에는 많은 용량을 차지한다. 그래서 사진 저장에 흔히 쓰이는 JPEG 이미지 형식의 경우 근처에 있는 화소들을 묶어, 비슷한 색들을 뭉뚱그리는 방식으로 이미지를 압축한다.
- 위 방식에는 색상 정보의 손실이 있기에, 저장할 때 압축률을 높이거나, 여러 번 다시 저장하는 등 재압축이 일어나게 될 경우, 흔히 디지털 풍화라고 불리는 색상이 지저분해지는 현상을 볼 수 있다.
- 또, 스크린샷 등에 많이 사용되는 PNG 이미지 형식의 경우 색상의 손실 없이 이미지를 압축하는데, 이미지에 사용된 색상을 미리 정의해두고 그를 참조하는 팔레트 방식을 사용할 수 있기에, 사용된 색상이 적은 단순한 이미지의 경우 동일한 해상도의 JPEG 파일보다도 용량이 작을 수 있지만, 색상이 많아지면 용량이 더 커진다.
- 이외에도 움짤에 익숙한 GIF형식은 이미지 내에 여러 프레임을 두어 움직일 수 있게 만들었고, 또한 색상 정보를 손실 없이 저장하나, 256개의 색상만 기억할 수 있는 팔레트 방식으로 제한된다.
2. Pillow 사용법
- 파이썬에서 이미지 처리를 위해 PIL(Python Image Library)라는 라이브러리가 있었는데, 2011년 마지막 커밋 이후로 개발이 중단됬다.
- 대신 Pillow가 위 패키지의 정신을 이어받아 현재까지도 지속적으로 이어져 내려오고 있다.
- 오늘 학습의 주인공은 OpenCV이지만 간단한 작업에는 Pillow는 Numpy와 결합하여 간편하게 사용할 수 있는 도구이니 간단히 알아보겠다.
- 이미지를 작업할 때 명심할 점은 결국 이미지는 배열 형태의 데이터라는 점이다.
- 코드 실습을 통해
1) numpy의 zeros와 uint8 / Image의 fromarray을 이용해서 이미지 하나를 생성해보고
2) 모든 픽셀을 검은색과 빨간색, 흰색으로 3차례 변환을 시켜보고,
3) Image의 open을 이용해서 이미지 파일 하나를 불러와서 열어보고 width와 height를 출력하고, 다른 확장자로 바꿔서 저장시켜보고,
4) resize를 하여 크기를 변환해보고, crop을 이용하여 부분만 잘라보았다.
3. Pillow를 활용한 데이터 전처리
- 이미지 데이터베이스 구축을 위해 CIFAR-100 데이터셋을 활용했다. 압축을 해제하면 meta, test, train 3개의 파일이 나오는데, 이 중 train 파일만 사용했다.
- 이 데이터를 reshape, fromarray, swapaxes, save를 사용하여 이미지 파일로 만들어서 저장시켰다.
4. 안녕, OpenCV
- OpenCV는 오픈소스로 제공되는 컴퓨터 비전용 라이브러리이다. C++, Python, Java, MATLAB 등 다양한 언어에서 호출하여 사용할 수 있으며, 영상 처리에 대한 다양한 고급 기능들이 사용하기 쉽도록 구현되어 있다.
- 파이썬 튜토리얼 페이지에 들어가면 여러 가지 고급 예제들이 친절하게 살명되어 있는데, 이 중 이미지에서 특정 색을 가진 영역만 추출하는 예제를 볼 것이다.
- 이미지는 결국 [너비, 높이, 채널] 형태를 가지는 배열이고, 컴퓨터 비전이란 결국 이러한 배열 형태의 데이터를 처리하는 것이 중요한 분야라는 것을 배웠다.
- 이미지에서 관심 있는 부분이 특정 색을 가지고 있다면, 이 정보를 통해 원하는 부분을 배경을 구분하고, 원하는 부분만 따로 떼어낼 수 있다.
- 노드의 예제에서는 카메라를 통해서 영상을 읽어 들이고, 파란색을 찾기 쉽도록 컬러스페이스를 BGR(RGB)에서 HSV로 변환한 뒤, 해당 색상과 맞는 영역만 표시하는 작업이 진행된다. (OpenCV에서는 RGB가 아닌 BGR순서를 사용한다는것을 주의해야한다.)
- 해당 이미지는 노드의 예제를 그대로 타이핑쳤다. 다음 장에서는 이 코드를 하나하나 파악하기에 꼭 필요해보였다.
5. 톺아보기 (이름이 왜 이런지는 모르겠다)
- 1번 코드를 살펴본다. 필요한 패키지를 로딩한 코드이다.
1) OpenCV는 pip로 설치 시 open-python의 이름으로 설치하지만, import할 때는 cv2라는 이름은 사용한다.
2) OpenCV와 함께, 숫자 배열을 처리하는데 궁합이 잘 맞는 Numpy도 불러왔다.
- 2번 코드를 살펴본다. VideoCapture라는 함수를 호출했다.
1) 입력값을 0으로 입력하면 영상 캡쳐를 위해 카메라를 여는데, 기본 카메라가 제공된다는 것이다. (함수 설명에서 보면 영상을 캡쳐할 장치의 ID라고 나와있다)
- 3번 코드를 살펴본다. 여기서 while(1):은 while True:와 같다. 사실 while True:가 더 올바른 표기다.
1) 위에서 VideoCapture()을 통해서 열었던 카메라 객체 cap에 read() 메서드를 호출했다.
2) 여기서 두 개의 출력(retval(return value), image) 중 하나(retval)는 _를 통해서 버렸다.
3) 필요한 영상 이미지만 frame이라는 변수명으로 받았다.
- 4번 코드를 살펴본다.
1) 여기서는 frame을 BGR에서 HSV로 변환시켜서 hsv라는 변수에 저장했다.
- 5번 코드를 살펴본다.
1) 숫자로 파란색이라는 부분을 정의하고, 이 값들을 기준으로 이미지에서 마스크를 생성하는 과정이다.
2) 마스크란 수채화를 그리거나 인테리어 공사 중 실리콘을 바를 때 사용하는 마스킹 테이프의 역할과 동일하다. 우리가 원하는 부분만을 떼어낼 수 있도록 하는 역할이다.
3) HSV 색 공간에서 색상(Hue) 값 110 ~ 130, 채도(Saturation) 및 명도(Value) 값 50 ~ 255 사이의 색들을 파란색이라고 정의하고 있다.
4) hsv에 파란색으로 정의한 기준을 적용하여, 해당하는 픽셀들에는 1, 그렇지 않은 픽셀들에는 0을 찍어놓은 배열을 반환하는 것이 cv의 inRange()의 역할이다.
- 6번의 코드를 살펴본다.
1) cv의 bitwise_and()는 설명이 좀 복잡하다.
2) 이미지 두 장을 받아서 AND 비트 연산을 한다는 것인데, 지금은 이 기능이 필요한 것이 아니니 두 장 다 같은 이미지인 frame을 넣어서 동일한 이미지가 나오게 했다.
3) 대신 중요한 mask를 같이 넣어줘서, 해당 영역만 따오도록 한다. 따온 영역은 함수에서 dst가 주어진다면 그 위에, 아니면 새로 빈 검정색 영역 위에 이미지를 만들고 반환한다.
- 7번의 코드를 살펴본다. 이 부분은 직관적이다. 추가로 & 0xFF는 Numlock을 제거하는 기능을 한다.
1) imshow를 이용해서 각 이미지를 시각화했다.
2) cv의 waitKey(5)를 통해서 5초간 키 입력을 감지하고, 키 입력이 특정 키(27번 = ESC)가 되면 루프를 빠져나오고, 아니면 루프를 돌게 만들었다.
3) 마지막으로 cv의 destroyAllwindows()를 통해 열려있던 창들을 모두 닫으면서 끝내도록 했다.
6. 실습 : 비슷한 이미지 찾아내기
'공부 > AIFFEL' 카테고리의 다른 글
Exploration 13 : 어제 오른 내 주식, 과연 내일은? (0) | 2021.03.01 |
---|---|
Exploration 12 : 프로젝트 시각화(gif파일) - 번호는 과제파일의 번호와 일치함. (0) | 2021.02.25 |
Exploration 12 : 인공지능으로 세상에 없던 새로운 패션 만들기 (0) | 2021.02.23 |
풀잎스쿨 - DeepML(CS231N) Lec. 09 (0) | 2021.02.22 |
FUNDAMENTAL 22. 딥러닝 레이어의 이해 (1) Linear, Convolution (0) | 2021.02.22 |