파이썬이 인기가 많은 이유 중 하나는 다양한 라이브러리에 있고 각 라이브러리가 사용하기도 쉽고 사용할 데도 많습니다.

opencv같은 경우도 이미지 처리하는데 필수적인 라이브러리로 말 그대로 코딩으로 포토샵하기 입니다.

그리고 numpy는 다차원 배열을 지원하는 파이썬 라이브러리로 opencv 라이브러리 안에 포함되는 라이브러리입니다.

 

인터넷에 정말 무수한 사용 예제 및 설명들이 있어 이 포스트에서는 아주 기본적인 개념을 잡아볼까 합니다.

 

이미지는 기본적으로 수많은 픽셀들이 가로세로로 배치되어 만들어집니다. 그렇기 때문에 이미지의 정보는 각 픽셀이 가로세로로 몇개 있느냐와 각 픽셀 하나하나의 색 정보가 전부일 것입니다.

numpy는 간단하게 위에서 말하는 두가지 정보를 배열로 담을 수 있습니다. 직접 실험해 봅시다.

 

배경 회색은 무시하고 알아보기 쉽게 흑백으로 색을 나누었습니다.

가로X세로가 각각 3픽셀인 그림파일을 만듧니다. 귀찮으시면 아래 다운로드 받으실 수 있습니다.

(위 사진은 엄청나게 확대한 사진입니다. 검은색/흰색 한칸이 1 픽셀이라고 보면 됩니다.😁)

test.jpg
0.01MB

그리고 다음과 같이 그림파일을 불러옵니다.

1
2
3
4
5
6
import numpy as np
import cv2
 
img = cv2.imread('test.jpg')
print(img)
print(type(img))
cs

그리고 결과는 다음과 같습니다.

[[[  0   0   0]
  [255 255 255]
  [  0   0   0]]

 [[255 255 255]
  [  0   0   0]
  [254 254 254]]

 [[  0   0   0]
  [254 254 254]
  [  1   1   1]]]
<class 'numpy.ndarray'>

 

.imread 함수를 이용하여 단순하게 이미지를 불러오기만 했는데 numpy의 다차원 array로 결과가 나옵니다. 그리고 array와 실제 이미지를 대입해보면 하나의 픽셀은 값을 세개 갖는 array로 나오게 되고 그 상위 array는 x축(가로) 그 array들의 배열은 y축(세로)를 나타낸다는 것을 알 수 있습니다. 더불어 검은색은 [ 0 0 0 ] 값을 갖고 [255 255 255]는 흰색의 값을 갖는다는 것을 알 수 있습니다.(위에서 [1 1 1] 이나 [254 254 254]로 저장되는 경우는 파일로 저장할때 압축하는 과정에서 생겼으니 이부분은 그냥 모른척하고 넘어가 줍니다.😅)

 

이제 색을 다양하게 해보겠습니다.

이렇게 보니 예전 TV 화면 조정에서 봤을법한 색들입니다.
test2.jpg
0.01MB

사실은 상당히 의도적인 색 선택입니다. 위 파일 역시 .imread로 파일을 읽어들이면 똑같이 numpy array값으로 결과가 나올테고 이제 우리는 각각의 가장 작은 단위 array의 픽셀 위치를 알고 있기 때문에 아래와 같이 색 위에 대입해 봅니다.

위 결과를 통해서 색은 어떻게 구성되는가에 대해서 쉽게 이해할 수 있고 결과를 요약하자면 다음과 같습니다.

 

가장 어두운 검은색은 [ 0 0 0 ] 이고 가장 밝은 흰색은 [ 255 255 255 ] 입니다. 빨간색은 [ 0 0 255 ] 녹색(형광)은 [ 0 255 0 ], 파란색은 [ 255 0 0 ] 입니다.

두번째 열과 같이 각 값들이 줄어들면 어두워집니다.

그리고 세번째 열을 보면 각 색상의 조합으로 나오는 색상도 알 수 있습니다. 검은색과 흰색 그리고 위의 첫번째/세번째열의 색상 6가지가 가장 기준이 되는 색상이라고도 볼 수 있고 그렇기 때문에 우리가 옛날 TV에서 보던 화면조정 화면에서 본 색들로 구성되어 있는 것입니다.😎

 

각 array의 첫번째, 두번째, 세번째 순서대로 blue, green, red이라고 말할 수 있습니다. 하지만 여기서 주목할 점이 순서가 Blue/Green/Red로 이니셜을 붙여보면 BGR입니다. 맞습니다. opencv는 이미지를 BGR 순서로 매핑한다고 할 수 있습니다.

 

이러한 BGR은 우리가 흔히 접한 RGB 색상과 같은 개념입니다. 그런데 일반적으로 컴퓨터는 RGB 색상으로 불리는대로 Red/Green/Blue 순서로 매핑을 하게되고 RGB 순서라면 파란색은 [ 255 0 0 ]이 아니라 [ 0 0 255 ]가 되는 것입니다.

 

opencv 내에서만 이미지를 편집한다면 큰 문제가 아니지만 결국 이미지를 편집하는 것은 각 픽셀의 세 상수를 조정하여 색을 만들게 되고 그렇기 때문에 BGR순서라는 것은 항상 염두해 두어야 합니다.

 

왜 opencv에서는 BGR을 사용하는지에 대해서 인터넷에 찾아봤는데 아래와 같은 페이지를 찾았습니다.

learnopencv.com/why-does-opencv-use-bgr-color-format/

 

Why does OpenCV use BGR color format ? | Learn OpenCV

One of the elements of good design is the principle of least astonishment ( a.k.a principle of least surprise). A good intuitive design makes the user not think. When you see a handle on a door, you want to pull it. When you see a door with a metal plate,

learnopencv.com

결론은 그냥 옛날 카메라 제작 업체들이 BGR 포맷을 많이 사용해서라는데 뭐 별로 중요하진 않은 것 같습니다. 

(그냥 그런가보다 하면 됩니다.)

그리고 opencv에서는 간단하게 이러한 BGR 포맷을 RGB로 바꿔줄 수 있습니다.

1
2
3
4
5
6
7
import numpy as np
import cv2
 
img = cv2.imread('test2.jpg')
print(img)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
print(img)
cs

결과

[[[  0   0 254]
  [  1 255   0]
  [254   0   1]]

 [[  0   0 128]
  [  1 128   0]
  [128   0   1]]

 [[  0 255 255]
  [254   0 255]
  [255 255   0]]]


[[[254   0   0]
  [  0 255   1]
  [  1   0 254]]

 [[128   0   0]
  [  0 128   1]
  [  1   0 128]]

 [[255 255   0]
  [255   0 254]
  [  0 255 255]]]

 

 

 

이제 색상을 RGB기준으로 얘기해 봅시다. 하지만 개인적으로 녹색은 위에서 보시는 대로 녹색(green)이라기 보단 연두색에 가깝고 실제 html color name역시 green이 아니라 lime 입니다. 그렇기 때문에 RGB가 아닌 RLB로 사용해야 한다고 주장할 수 있으나... 뻘소립니다.😁

 

또 두번째 열을 통하여 각 해당 RGB의 값을 줄이니 어둡게 나왔습니다. 값이 클수록 색이 밝아지고 값이 작을수록 어두워 진다는 것을 재확인 할 수 있습니다.

 

그리고 세번째 열은 array값을 보면 알 수 있듯이 세가지 색을 합치면 어떤 색이 나오는지 알 수 있습니다. 

각각의 html color name은 yellow magenta aqua 입니다. (전 항상 color name으로 기억해 둡니다.)

 

그리고 각 array 안의 각 값들의 최고값은 255이고 익숙한 이 숫자는 '2의 8제곱 빼기 1' 이며 '16의 제곱 빼기 1'로 16진수로 나타낼수 있습니다. 맞습니다, 이러한 array 값을 16진수로 바꾸고 앞에 #을 붙이면 html hex 코드가 됩니다.

 

[ 256 256 256 ] ➡ #FFFFFF

 

파이썬에는 다음과 같이 10진법의 수를 쉽게 16진수로 바꿔주면 됩니다.

가령 [ 70, 130, 180 ] 이란 10진법 색 코드 리스트를 html color hex code 로 쉽게 바꿀 수 있습니다.

1
2
3
color = [70130180]
hex_color = "#%02x%02x%02x" % (color[0], color[1], color[2])
print(hex_color)
cs

결과는 #4682b4 로 제가 좋아하는 steelblue 색입니다.😁

 

opencv라는 포토샵 라이브러리 역시 수많은 function들은 일단 이미지를 numpy array 형태로 바꾸고 각 배열의 숫자를 조정하여 각각의 함수를 수행합니다. 아주 단순하게 위에서 보았듯이 이미지를 어둡게 만들고 싶다면 모든 배열의 각 최소단위의 array의 값들을 줄이게 되면 이미지도 어둡게 되고 이런식으로 수많은 함수들이 각각의 공식에 의해서 array의 값을 조정하게 됩니다. 

 

구체적인 하나의 예를 들자면 보색(complementary/inverted color)의 경우 255에서 각 픽셀값을 빼면 됩니다.

[255, 255, 255] (white)의 경우 [0, 0, 0] (black)이 되고

[255, 0, 0] (red)의 경우 [0, 255, 255] (aqua)이 됩니다. 

 

이러한 식으로 보색도 함께 htm hex color code로 출력해 봅니다.

1
2
3
4
5
color = [70130180]
hex_color = "#%02x%02x%02x" % (color[0], color[1], color[2])
com_color = "#%02x%02x%02x" % (255-color[0], 255-color[1], 255-color[2])
print(hex_color)
print(com_color)
cs

결과는 #4682b4(steelblue) #b97d4b 가 나왔습니다. (보색은 아쉽게도 html color name은 없는 듯 합니다.😥)

 

하지만 encycolorpedia 라는 홈페이지에서 위 코드를 입력하여 보면 다양한 설명을 볼 수 있습니다.

encycolorpedia.com/b97d4b

 

#b97d4b Hex Color Code

No great artist ever sees things as they really are. If he did, he would cease to be an artist. Oscar Wilde

encycolorpedia.com

정식으로 코딩에 쓸 수는 없는 듯 하지만 shade of orange 색이라고 합니다.😅

그리고 그 밖에도 색상의 다양한 정보를 얻을 수 있습니다.

이런 홈페이지도 있다니 참 대단한 것 같습니다.

+ Recent posts