본문 바로가기

OpenCV

NumPy와 Matplotlib

1. Numpy

1.1 넘파이 배열 생성

■ 넘파이 배열 생성 방법은 크게 (1) 값으로 생성 - array( ), (2) 크기와 초깃값으로 생성 - empty( ), zeros( ), ones( ), full( ) , (3) 기존 배열을 기준으로 생성 - empty_like( ), zeros_like( ), ones_like( ), full_like( ), (4) 순차적인 값으로 생성 - arrange( ), (5) 난수로 생성 - random.rand( ), random.randn( ) 이 있다.

■ 먼저, array( )로 넘파이 배열을 생성할 경우 다음과 같이 리스트를 사용해서 만들 수 있다. 이 리스트를 이용해서 배열의 차원을 설정할 수 있다.

import numpy as np

a = np.array([1, 2, 3]) # 1차원
b = np.array([[1., 2.], [3., 4.]]) # 2차원
c = np.array([[[1., 2.], [3, 4]], # 3차원
              [[5, 6], [7., 8.]]])
d = np.array([1, 2, 3], dtype = np.float32)

print(a); print(a.dtype, a.shape);print()
print(b); print(b.dtype, b.shape);print()
print(c); print(c.dtype, c.shape);print()
print(d); print(d.dtype, d.shape)
```#결과#```
[1 2 3]
int32 (3,)

[[1. 2.]
 [3. 4.]]
float64 (2, 2)

[[[1. 2.]
  [3. 4.]]

 [[5. 6.]
  [7. 8.]]]
float64 (2, 2, 2)

[1. 2. 3.]
float32 (3,)
````````````

- dtype에 데이터 타입을 지정해서 넘파이 배열을 만들 수도 있다.

empty( ), zeros( ), ones( ), full( )을 사용할 경우 넘파이 배열의 크기나 초깃값을 지정해서 넘파이 배열을 생성할 수 있다.

■ 먼저, empty( )는 크기를 지정하면 지정한 크기에 맞게 넘파이 배열을 생성한다. 이때 배열의 값은 초기화되지 않으며 임의의 값으로 채워질 수 있다.

a = np.empty((2,3))
b = np.empty((2,3), dtype=np.int16)

print(a); print(a.dtype, a.shape);print()
print(b); print(b.dtype, b.shape)
```#결과#```
[[6.23042070e-307 1.33512376e-306 1.11261230e-306]
 [7.56577399e-307 9.34600963e-307 1.05699581e-307]]
float64 (2, 3)

[[1 0 2]
 [0 3 0]]
int16 (2, 3)
````````````

zeros( )는 크기를 지정하면 지정한 크기에 맞게 넘파이 배열을 생성하되, 배열의 값을 모두 0으로 초기화한다. ones( )도 지정한 크기에 맞게 배열을 생성하는데, zeros( )와 다르게 배열의 값을 모두 1로 초기화한다.

c = np.zeros((2,3))
d = np.ones((3,2), dtype = np.float64)

print(c); print(c.dtype, c.shape);print()
print(d); print(d.dtype, d.shape)
```#결과#```
[[0. 0. 0.]
 [0. 0. 0.]]
float64 (2, 3)

[[1. 1.]
 [1. 1.]
 [1. 1.]]
float64 (3, 2)
````````````

 full( )은 지정한 배열의 크기와 지정한 값을 갖는 넘파이 배열을 생성한다.

e = np.full((2,4,3), fill_value = 255, dtype = np.float64)

print(e); print(e.dtype, e.shape)
```#결과#```
[[[255. 255. 255.]
  [255. 255. 255.]
  [255. 255. 255.]
  [255. 255. 255.]]

 [[255. 255. 255.]
  [255. 255. 255.]
  [255. 255. 255.]
  [255. 255. 255.]]]
float64 (2, 4, 3)
````````````

empty_like( ), zeros_like( ), ones_like( ), full_like( )와 같이 _like( )는 특정 배열과 동일한 데이터 타입과 크기를 가지는 배열을 생성할 때 사용한다. 이때, _like( ) 앞의 empty/zeros/ones/full에 따라 초기화 방식이 달라진다.

img = cv2.imread('../opencv/cat1.jpg')  # OpenCV로 이미지 읽기
print(type(img)) # img의 데이터 타입
print(img.ndim) # 차원 수
print(img.shape) # 이미지 형상
print(img.size) # 전체 요소의 개수
print(img.dtype) # 데이터 타입
print(img.itemsize) # 각 요소의 바이트 크기
```#결과#```
<class 'numpy.ndarray'>
3
(145, 216, 3)
93960
uint8
1
````````````

- OpenCV에서 이미지를 읽기 위해 cv2.imread( ) 함수를 사용한다. 이때 반환되는 이미지는 넘파이 배열 데이터이다. 그러므로 다음과 같이 넘파이의 속성을 이용해 이미지의 데이터 타입이나 차원 수, 데이터 타입 등의 정보를 확인할 수 있다.

a = np.empty_like(img)
b = np.zeros_like(img)
c = np.ones_like(img)
d = np.full_like(img, 255)

print(a.dtype, a.shape)
print(b.dtype, b.shape)
print(c.dtype, c.shape)
print(d.dtype, d.shape)
```#결과#```
uint8 (145, 216, 3)
uint8 (145, 216, 3)
uint8 (145, 216, 3)
uint8 (145, 216, 3)
````````````

- 동일한 크기를 가지므로, 이 예에서는 배열 a, b, c, d의 차원 수 = 3, 전체 요소의 개수도 145 * 216 * 3 =  93960으로 img와 동일한 값을 갖게 된다. 

■ arange( )는 [start, stop) 구간에서 step의 크기만큼 일정하게 떨어져 있는 값들을 array 형태로 반환하는 함수이다. 

a = np.arange(3)
b = np.arange(2.0, 4.0)

print(a); print(a.dtype, a.shape);print()
print(b); print(b.dtype, b.shape)
```#결과#```
[0 1 2]
int32 (3,)

[2. 3.]
float64 (2,)
````````````

넘파이의 random.rand( )와 random.randn( )는 비슷하지만, 난수를 생성하는 분포 곡선이 다르다.

- rand는 0~1 사이의 균등 분포에서 난수를 추출하고,

- randn는 평균이 0, 표준편차가 1인 표준 정규분포에서 난수를 추출한다.

a = np.random.rand(3)
b = np.random.randn(2, 3, 4)


print(a); print(a.dtype, a.shape);print()
print(b); print(b.dtype, b.shape)
```#결과#```
[0.60754627 0.77169299 0.80426406]
float64 (3,)

[[[ 0.72732247  0.65897131  0.92542387  0.08579452]
  [ 0.06202853 -0.26427572 -0.43380782 -1.85511031]
  [ 1.29019534 -0.06401563  1.04994217  0.72781288]]

 [[-0.02672093  1.8614035  -0.66941795  0.42204103]
  [-1.05825472  0.28622641 -0.90425565 -0.02993557]
  [ 0.36551887  1.72813556  0.36394412 -0.55636602]]]
float64 (2, 3, 4)
````````````

 

1.2 이미지 생성

■ 다음과 같이 넘파이 배열로 2차원 이미지를 생성할 수 있다.

img = np.zeros((100, 100)) # 100 x 100 2차원 배열 # 검은색 이미지

cv2.imshow('Gray', img)
if cv2.waitKey(0) & 0xFF == 27:
    cv2.destroyAllWindows()

img = np.zeros((100, 100)) # 100 x 100 2차원 배열 # 검은색 이미지
img[10:30, :] = 255 # 10~30행 & 모든 열에 255 할당 
img[50:60, :] = 100 # 50~60행 & 모든 열에 100 할당
img[:, 30:50] = 255 # 모든 행 & 30~50열에 255 할당
img[:, 50:60] = 100 # 모든 행 & 50~60열에 255 할당

cv2.imshow('Gray', img)
if cv2.waitKey(0) & 0xFF == 27:
    cv2.destroyAllWindows()

■ 다음과 같이 넘파이 배열로 3차원 이미지를 생성할 수 있다. 이때 OpenCV는 이미지를 RGB가 아닌 BGR로 표현하므로 파란색은 [B, G, R] = [255, 0 ,0], 초록색은 [B, G, R] = [0, 255 ,0], 빨간색은 [B, G, R] = [0, 0 ,255]로 나타내야 한다.

img = np.zeros((100, 100, 3)) # 100 x 100 2차원 배열 # 검은색 이미지
img[10:20, :] = [255, 0, 0] # 10~20행 & 모든 열에 파란색
img[40:50, :] = [0, 255, 0] # 40~50행 & 모든 열에 초록색
img[70:80, :] = [0, 0, 255] # 70~80행 & 모든 열에 빨간색
img[:, 40:60] = [255, 255, 255] # 모든 행 & 40~60 열에 흰색

cv2.imshow('BGR', img) # OpenCV는 이미지를 BGR로 나타낸다.
if cv2.waitKey(0) & 0xFF == 27:
    cv2.destroyAllWindows()

 

2. Matplotlib

■ OpenCV에서 이미지를 cv2.imread( )로 읽은 다음, 이미지를 나타내기 위해 cv2.imshow( )를 이용해 창을 생성하고, 생성된 창 안에 이미지를 나타냈다. matplotlib을 이용하면 별도의 창을 생성하지 않아도 이미지를 출력할 수 있다.

import cv2
from matplotlib import pyplot as plt

img2 = cv2.imread('img1.jpg')
print(img2)
plt.imshow(img2) # 이미지 표시
plt.show()

■ 하지만, OpenCV의 색상 순서는 BGR인 반면 matplotlib의 pyplot의 색상 순서는 RGB이기 때문에 위의 그림과 같이  색상 채널이 뒤바뀌게 된다.
■ 이 문제를 해결하기 위해 다음과 같은 방법들을 사용할 수 있다.

- cv2.cvtColor(img,  cv2.COLOR_BGR2RGB) 함수를 사용해서 BGR 순서를 RGB 순서로 변환

- img[:,:,::-1]나 img[:,:,(2,1,0)]으로 이미지 컬러 채널을 뒤집기 (1번과 2번 축은 이미지의 크기를 나타내고 3번 째 축이 채널) 

img2 = cv2.imread('img1.jpg')
img3 = cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)

plt.imshow(img3)
plt.show()

img4 = cv2.imread('img1.jpg')

plt.imshow(img4[:,:,::-1])       
plt.show()

img5 = cv2.imread('img1.jpg')

plt.imshow(img5[:,:,(2,1,0)]) 
plt.show()

np.array_equal(img3, img4[:,:,::-1])
```#결과#```
True
````````````

np.array_equal(img3, img5[:,:,(2,1,0)])
```#결과#```
True
````````````

 

'OpenCV' 카테고리의 다른 글

기하학적 변환 (1)  (0) 2024.12.16
이미지 프로세싱 (3)  (0) 2024.12.15
이미지 프로세싱 (2)  (1) 2024.12.14
이미지 프로세싱 (1)  (0) 2024.12.13
기본 입출력  (1) 2024.12.12