When will you grow up?

python으로 시작하는 OpenCV (2) 본문

02. Study/Computer Vision(openframworks&opencv)

python으로 시작하는 OpenCV (2)

미카이 2020. 2. 4. 00:42

저번 포스팅에서는 입출력과 관련된 내용을 다뤄봤다면,

이번에는 행렬조작과 색 공간 및 필터에 대해 알아보자.

 

 

행렬 조작 : 생성하고 채우고, 요소 접근하고 ROI(Region of Interest)

import cv2

import numpy as np

 

img = np.full((480640,3), 255, np.uint8)

#img = np.full((480640,3), (0, 255, 0), np.uint8) # green 

#img = np.full((480640,3), (0, 255, 255), np.uint8) # yellow

#img = np.full((480640,3), (0, 0, 255), np.uint8) # red

cv2.imshow('white img', img)

cv2.waitKey()

cv2.destroyAllWindows()

cs

위와 같은 코드를 통해 특정 형태 (480,640,3) height,width,channel 형식으로 full (255)로 가득찬 이미지를 만들수 있다.

실행해보면 흰색 배경의 이미지가 만들어 질것이다.

그 외에도, 다양한 색 조합을 통해 ex) (255,255,0) 하늘색 -> 조절하면 색상을 조절 할 수 있다(0~255).  0을 채우면 black이미지가 만들어진다.

OpenCV의 파이썬 행렬은 Numpy 배열로 나타내며, 다차원 행렬(tensor)를 다루는 도구를 제공한다.

또한, 행렬은 일반적으로 너비, 높이, 채널 수의 세 가지 공간 차원을 갖는다. OpenCV는 컬러 또는 grayscale 행렬로 동작하지만 imread('path' ,-1) 를 통해 원본응로 읽어 올수도 있지만, 일반적인 형태는 두가지가 대표적이다.

RGB 표현을 위해 BGR 형식으로 저장하기 때문에 색 변경이나 이러한 부분에서 주의가 필요하다.

마지막으로 uint8로 보통 0~255로 저장하지만 np.float32나 np.float64로 값을 저장할 수도 있다.

 

 

 

이전에는 cv2.imread나 cv2.imwrite 함수를 이용하여 이미지만 저장하거나 불러왔다. 하지만 Numpy를 사용한 비이미지 데이터 속성으로 이미지뿐만 아니라 어떠한 형태나 데이터 타입의 행렬 또한 저장이 가능하다.

 

import cv2

import numpy as np

 

mat = np.random.rand(100100).astype(np.float32)

print(f'Shape : {mat.shape}'# (100,100) ->np.ndarray타입

print(f'Data Type : {mat.dtype}'# flaot32

np.savetxt('mat.csv', mat) # save numpy data

 

mat = np.loadtxt('mat.csv').astype(np.float32) # load data


cs

위 코드를 간략하게 살펴보면, rand으로 100,100 크기의 float32 형태의 행렬을 만들고, np.savetxt() 함수를 통해 csv 형태로 저장한다. csv는 ,(쉼표) 로 구분된 데이터다. 또한 np.loadtxt() 함수를 통해 불러올 수 있으며, astype으로 타입변경도 가능하다!

 

만약 어떤 이미지를 불러오고 red 채널과 blue 채널을 바꾸고 싶다면, 아래 코드로 간단하게 바꿀 수 있다.

import cv2

import numpy as np

 

origin_img = cv2.imread('image.jpg')

img = origin_img.copy()

img[:, :, [02]] = img [:, :, [20]]

cv2.imshow('origin', origin_img)

cv2.imshow('blue_red_swapped', img)

cv2.waitKey()

cv2.destroyAllWindows()

cs

채널 변경 결과

 

 

 

 

이번에는 색 공간 변환을 해보자.

기본적으로 openCV의 컬러 이미지는 RGB색 공간으로 표시된다. 그러나 가끔 다른 색 표현으로 변경해야 할 필요가 있는데, 예를 들면 강도(intensity)에 대한 별도의 채널을 갖는 경우가 있는데 한번 변경해보자.

import cv2

import numpy as np

 

origin_img = cv2.imread('image.jpg').astype(np.float32) / 255

gray_img = origin_img.copy()

hsv_img = origin_img.copy()

gray_img = cv2.cvtColor(gray_img, cv2.COLOR_BGR2GRAY)

hsv_img = cv2.cvtColor(hsv_img, cv2.COLOR_BGR2HSV)

 

 

cv2.imshow('origin_img', origin_img)

cv2.imshow('gray_img', gray_img)

cv2.imshow('hsv_img', hsv_img)

cv2.waitKey()

cv2.destroyAllWindows()

Colored by Color Scripter


cs

위 코드를 간략하게 살펴보면 이미지를 normalization을 통해 불러오고, grayscale 사진 및 HSV 형태로 변경 시킨다.

cv2.cvtColor() 함수를 사용하면 간단하게 변경이 가능한데, 200가지가 넘는 유형을 지원하므로 궁금하면 document..

 

 

 

이미지를 다룰때면 픽셀 값의 통계적 값으로 설정해야 할 때가 있다. 값들의 평균값을 0으로 설정하고 분산을 1로 설정하면 이 연산은 정규화되는데, 분석이나 전처리 단계에서 유용하게 사용되며

img = img = cv2.imread('image.jpg').astype(np.float32) / 255
img = img - img.mean()
img = img / img.std()

3줄로 간단하게 정규화 할 수 있는데 간단하게 살펴보면, mean을 통해 평균을 빼주고 다시 표준편차로 나눠준다.

그 외에도 cv2.meanStdDev를 이용하면 평균과 표준 편차를 동시에 계산도 가능하다.

 

 

 

이미지 히스토그램은 값의 집합에 대한 분포 수준을 보여주고, 어떤 값으로 치우져 있거나 outlier를 제거하기 위한 지표로도 사용이 가능하다.

import cv2

import numpy as np

import matplotlib.pyplot as plt

 

img = cv2.imread('image.jpg',0)

hist, bins = np.histogram(img, 256, [0,255])

plt.fill(hist)

plt.xlabel('pixel value')

plt.show()

Colored by Color Scripter


cs

위 코드에서 cv2.calcHist함수가 제공되지만, 코드 간결성을 위해 numpy에서 제공되는 np.histogram()함수를 이용하였다. 이 함수는 (입력 이미지, bin의 수, bin의 범위) 값과 에지 값을 배열로 반환한다.

image histogram

하지만 이미지 히스토그램을 사용하다보면 대비가 낮은 이미지는 대부분 픽셀 값의 범위가 좁기 때문에 특정 값으로 군집되는 히스토그램을 갖는데, 히스토그램 평활화를 통해 세부적인 부분을 표현 할 수 있다.

import cv2

import numpy as np

import matplotlib.pyplot as plt

 

img = cv2.imread('image.jpg',0)

hist_equal= cv2.equalizeHist(img)

hist, bins = np.histogram(hist_equal, 256, [0,255])

plt.pill_between(range(256), hist, 0)

plt.xlabel('pixel value')

plt.show()

Colored by Color Scripter


cs

histogram equalization

 

 

마지막으로 노이즈 제거를 간략하게 알아보자.

모든 real world이미지에는 많은 노이즈가 포함돼 있다. 노이즈는 이미지의 형태를 망치고, 전처리하기에도 좋지 않은 영향을 준다 그래서 노이즈를 제거하거나 감소시키는 방법을 알아보자.

 

noise 추가된 이미지

위 사진 처럼 이미지에 노이즈를 추가해보고 gaussian_blur median_blur 를 이용해서 보자.

import cv2

import numpy as np

import matplotlib.pyplot as plt

 

# [0, 1] 사이의 범위의 부동소수점 데이터 타입으로 변환

img = cv2.imread('image.jpg').astype(np.float32) / 255

 

# noise 추가

noise = (img + 0.2 * np.random.rand(*img.shape).astype(np.float32))

gauss_blur = cv2.GaussianBlur(noise, (7, 7), 0)

median_blur = cv2.medianBlur((noise * 255).astype(np.uint8),7)

noise = noise.clip(01)

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

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

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

plt.show()

Colored by Color Scripter


cs

 

위 코드도 간략하게 살펴보면 가우시안 필터를 적용하기 위해 cv2.GaussianBlur 함수를 사용하는데, (img, kernel(width,height)) 형태로 파라미터를 갖는데 다양하게 파라미터를 조절하면서 만지작 거리다보면 뭔가 최적으로 noise를 줄일 수 있지 않을까? 생각이 든다.

 

reference

book : 파이썬과 OpenCV를 이용한 컴퓨터 비전 학습

document : python opencv document

Comments