달나라 노트

Python matplotlib : imshow (array에 색을 채워 이미지로 표시하기) 본문

Python/Python matplotlib

Python matplotlib : imshow (array에 색을 채워 이미지로 표시하기)

CosmosProject 2022. 1. 2. 02:42
728x90
반응형

 

 

 

 

 

matplotlib에는 imshow라는 method가 있는데 이 method는 array의 값들을 색으로 환산해 이미지의 형태로 보여줍니다.

 

 

import numpy as np
import matplotlib.pyplot as plt

arr_test = np.array(
    [  # 1차 array
        [0, 1, 0],  # 2차 array
        [1, 0, 1],
        [0, 1, 0],
    ]
)

plt.imshow(arr_test)
plt.show()

위 예시는 2차원 array를 imshow에 적용한 것입니다.

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

체스판 형태의 이미지가 나왔죠.

 

 

지금부터 왜 위처럼 된건지 알아봅시다.

 

일단 사용된 array를 보면 2차원이며 다음과 같습니다.

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

 

imshow는 2차원 array를 받아서 2차원 array의 각 위치에 있는 숫자를 색으로 변환해서 나타내줍니다.

 

위 array는 3 * 3의 형태이며 총 9개의 값이 있습니다.

즉, 종이를 3 * 3 형태의 총 9개의 정사각형 영역으로 나눠서 각 칸에 0번에 해당하는 색(보라), 1번에 해당하는 색(노랑)을 채워주는 것이죠.

 

다르게 말하면 9(= 3 * 3) 픽셀짜리 이미지에서 각 픽셀마다 색을 채워서 나타내준다고 보면 됩니다.

 

 

 

 

 

import numpy as np
import matplotlib.pyplot as plt

arr_test = np.array(
    [  # 1차 array
        [0, 1, 0, 1],  # 2차 array
        [1, 0, 1, 0],
        [0, 1, 0, 1],
        [1, 0, 1, 0],
    ]
)

plt.imshow(arr_test)
plt.show()

자 이제 위 예시는 어떻게 나올지 감이 가시나요?

 

정답은 위와 같습니다.

 

사용된 array가 2차원이며 4 * 4의 형태입니다. 따라서 총 16칸이 있고 각 칸마다 있는 숫자가 무슨 색이 될지를 정하는 것이죠.

 

 

imshow의 원리는 이와 같습니다.

2차원 array를 받아서 각 칸마다 어떤 색이 들어가야할지에 대한 정보를 기반으로 결과 이미지를 만들어주는 것이죠.

 

 

 

 

 

 

 

import numpy as np
import matplotlib.pyplot as plt

arr_test = np.array(
    [  # 1차 array
        [0, 100, 0, 100],  # 2차 array
        [100, 0, 100, 0],
        [0, 100, 0, 100],
        [100, 0, 100, 0],
    ]
)

plt.imshow(arr_test)
plt.show()

이번에는 1을 모두 100으로 바꿔봤습니다.

그 결과는 어떨까요?

 

위 결과 이미지를 보시면 1을 100으로 바꿨는데도 전혀 변화가 없습니다.

 

왜 그럴까요?

imshow는 주어진 array에서 최대값을 1, 최소값을 0으로 대응해서 전체적인 값을 동일한 비율로 조절하여 0~1 사이의 숫자로 변환한 후에 이미지를 나타내주기 때문입니다.

 

즉, 숫자를 어떻게 적던 상관없이 가장 적은 값은 0, 가장 큰 값은 1로 변환되며 그 사이의 숫자는 최대/최소 숫자에 기반하여 동일한 비율로 조절되는것이죠.

결국 숫자를 어떻게 전달하건 0~1 사이의 숫자로 변환된 후에 색상이 결정된다는 의미입니다.

 

 

 

 

 

자 여기서 한가지 더 의문이 생깁니다.

왜 0은 보라색이고, 1은 노란색일까요?

 

그 이유는 imshow에서 사용하는 colormap의 기본값이 viridis이기 때문입니다.

viridis가 뭔지 자세히 설명하진 않겠습니다. 다만, viridis는 최소값이 보라, 최대값은 노랑으로 대응되는 colormap이라고 보시면 됩니다.

 

그러면 colormap을 변경해봅시다.

 

 

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm

arr_test = np.array(
    [  # 1차 array
        [0, 1, 0, 1],  # 2차 array
        [1, 0, 1, 0],
        [0, 1, 0, 1],
        [1, 0, 1, 0],
    ]
)

plt.imshow(arr_test, cmap=cm.cividis)
plt.show()

위처럼 matplotlib의 cm에 있는 colormap을 이용할 수 있으며, imshow의 cmap 옵션을 변경해주면 됩니다.

 

- plt.imshow(arr_test, cmap=cm.cividis)

colormap을 cividis로 설정했고, 그 결과는 다음과 같습니다.

 

전체적으로 색이 변했죠.

최소값이 남색, 최대값이 노랑임을 알 수 있습니다.

 

 

 

 

 

 

 

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm

arr_test = np.array(
    [  # 1차 array
        [0.2, 1, 0, 1],  # 2차 array
        [1, 0.4, 1, 0],
        [0, 1, 0.6, 1],
        [1, 0, 1, 0.8],
    ]
)

plt.imshow(arr_test, cmap=cm.Greys)
plt.show()

이번엔 cmap(colormap)을 Greys로 설정했고, Greys는 흑백 colormap입니다.

 

array의 값들도 좀 바꿔봤는데 그 결과는 다음과 같습니다.

 

 

 

 

 

 

 

colormap은 매우 다양한 종류가 존재합니다.

https://matplotlib.org/stable/tutorials/colors/colormaps.html

위 링크에서 보면 다양한 colormap을 볼 수 있고, 그 중 일부는 다음과 같습니다.

 

 

 

 

 

 

 

 

 

import numpy as np
import matplotlib.pyplot as plt

arr_test = np.array(
    [  # 1차 array
        [[0, 0, 0], [255, 0, 0], [0, 255, 0], [0, 0, 255]],  # 2차 array
        [[0, 0, 0], [255, 0, 0], [0, 255, 0], [0, 0, 255]],
        [[0, 0, 0], [255, 0, 0], [0, 255, 0], [0, 0, 255]],
        [[0, 0, 0], [255, 0, 0], [0, 255, 0], [0, 0, 255]],
    ]
)

plt.imshow(arr_test)
plt.show()

많은 분들이 익숙하신 RGB도 이용할 수 있습니다.

다만 RGB는 단 하나의 값으로 색이 정해지는게 아니라, 하나의 색을 정하기 위해 R, G, B 총 3개의 색상값이 필요합니다.

 

그래서 위처럼 하나의 칸에 [0, 255, 0] / [0, 0, 0] 처럼 순서대로 R, G, B를 얼마만큼 적용시킬지 정해줘야 합니다.

RGB는 최소값이 0이며 최대값은 255입니다.

 

위 코드는 4 * 4 (16) 픽셀 이미지이며,

하나의 픽셀의 색을 정하는 값은 [0, 0, 0] 같은 3개의 요소(R, G, B)를 가진 array인 것이죠.

 

 

위 코드의 결과는 다음과 같습니다.

 

RGB는 빛이라고 보시면 됩니다.

따라서 [0, 0, 0]은 어떤 색상의 빛도 섞이지 않았으므로 검은색이 됩니다. (가장 왼쪽 열)

 

 

 

 

 

 

 

 

RGB를 사용할 수 있으면 RGB에 투명도까지 표시할 수 있는 RGBA도 사용할 수 있을까요?

정답은 사용할 수 있다 입니다.

 

아래 코드를 보시죠.

import numpy as np
import matplotlib.pyplot as plt

arr_test = np.array(
    [  # 1차 array
        [[0, 0, 0, 1.0], [255, 0, 0, 1.0], [0, 255, 0, 1.0], [0, 0, 255, 1.0]],  # 2차 array
        [[0, 0, 0, 0.7], [255, 0, 0, 0.7], [0, 255, 0, 0.7], [0, 0, 255, 0.7]],
        [[0, 0, 0, 0.4], [255, 0, 0, 0.4], [0, 255, 0, 0.4], [0, 0, 255, 0.4]],
        [[0, 0, 0, 0.1], [255, 0, 0, 0.1], [0, 255, 0, 0.1], [0, 0, 255, 0.1]],
    ]
)

plt.imshow(arr_test)
plt.show()

방금 전에 봤던 RGB예시에서 투명도를 나타내는 하나의 값이 더 생겼습니다.

 

[0, 0, 0, 1.0]을 보면 가장 왼쪽 3개의 0은 RGB 값을 나타내는 것이며, 네 번째 요소인 1.0은 투명도를 의미합니다.

RGB값은 0~255의 값이라면

투명도는 0~1 사이의 값입니다.

또한 0은 완전 투명한 것이고, 1은 완전 진한 것을 의미한다고 보시면 됩니다.

 

위 코드의 결과입니다.

가장 왼쪽에 검정색 열을 예시로 보면,

투명도가 1로 설정된 영역은 검은색이 진하게 나타나는데

아래로 갈수록 투명도가 0.7, 0.4, 0.1 등으로 낮아지고, 색도 점점 투명해지는 것을 볼 수 있습니다.

 

 

 

 

 

 

 


 

 

 

 

 

아래 코드는 지금까지 본 imshow method와 numpy의 randint를 이용해서

가로 200, 세로 200개의 픽셀에 랜덤한 색상을 넣은 이미지를 만드는 코드입니다.

 

import numpy as np
import matplotlib.pyplot as plt

def rgb_generator():
    rgb_color = np.random.randint(0, 256, size=(3,)).tolist()

    return rgb_color


img_x_length = 200
img_y_length = 200

list_image = []
for y in range(img_y_length):
    list_row = []
    for x in range(img_x_length):
        rgb_color = rgb_generator()
        list_row.append(rgb_color)

    list_image.append(list_row)

arr_image = np.array(list_image)

plt.imshow(arr_image)
plt.show()

 

결과는 다음과 같습니다.

 

 

 

 

 

 

728x90
반응형
Comments