OpenCV 프로그래밍 - Chapter 03 OpenCV 기본연산(2)

업데이트:

카테고리:

태그:

이 포스팅은 ‘python으로 배우는 OpenCV 프로그래밍’ 교재를 참고하여 작성하였습니다.

05 컬러 공간 변환

cvtColor() 함수는 GRAY, HSV, YCrCb 등의 다양한 컬러 공간 포맷으로 변환한다.
cvtColor()의 문법은 다음과 같다.
cv2.cvtColor(src, code[, dst[, dstCn]]) -> dst 입력 영상 src를 code에 따라 출력 영상 dst에 변환한다.
dstCn은 출력 영상의 채널수이다.
컬러 변환에서 R, G, B 채널의 값은 영상의 자료형에 따라 np.uint8 = 0 ~ 255, np.uint16 = 0 ~ 65535, np.float32 = 0 ~ 1 범위로 간주한다.
선형 변환의 경우는 화소 자료형을 따르는 값의 범위가 문제 되지 않지만, 비선형 변환의 경우 문제가 될 수 있다.
그러므로 컬러 변환 전에 astype() 함수를 사용하여 np.uint16, np.uint32, np.float32로 변환해야할 수도 있다.

주요 컬러 변환 코드는 다음과 같으며, 어떤 유형의 컬러 공간이 존재하는지 정도만 알고 넘어가자.

| 입력 영상(src) | 변환 코드(code) | 출력 영상(dst) | |————|———————|————| | BGR | cv2.COLOR_BGR2GRAY | GRAY | | GRAY | cv2.COLOR_GRAY2BGR | BGR | | BGR | cv2.COLOR_BGR2HSV | HSV | | HSV | cv2.COLOR_HSV2BGR | BGR | | BGR | cv2.COLOR_BGR2YCrCb | YCrCb | | YCrCb | cv2.COLOR_YCrCb2BGR | BGR |

컬러 변환

import cv2
src = cv2.imread('./data/lena.jpg')

gray   = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
yCrCv = cv2.cvtColor(src, cv2.COLOR_BGR2YCrCb)
hsv    = cv2.cvtColor(src, cv2.COLOR_BGR2HSV)

cv2.imshow('gray',  gray)
cv2.imshow('yCrCv', yCrCv)
cv2.imshow('hsv',   hsv)

cv2.waitKey()    
cv2.destroyAllWindows()

BGR로 읽어온 이미지를 여러가지 컬러 공간으로 변환하는 코드이며 실행 결과는 다음과 같다.
image

06 영상의 크기 변환과 회전

cv2.resize() 함수를 사용해서 영상의 크기를 변환하고, 확대 축소 하며 문법은 다음과 같다.
cv2.resize(src, dsize[, dst[ ,fx [, fy[, interpolation]]]]) -> dst
위 문장은 입력 영상(src)의 크기를 변환하여 반환(dst)한다.
src는 입력 영상, dsize는 출력 영상의 크기, dst는 출력 영상, fx, fy는 가로와 세로의 스케일이고, interpolation은 보간법인데 여러가지 보간법이 존재하며 필요에 의해 검색해서 찾아보도록 한다.

영상 크기 변환

import cv2
import numpy as np
src = cv2.imread('./data/lena.jpg', cv2.IMREAD_GRAYSCALE)

dst = cv2.resize(src, dsize=(320, 240))
dst2 = cv2.resize(src, dsize=(0,0), fx=1.5, fy=1.2)
print('dst.shape =', dst.shape)
print('dst2.shape =', dst2.shape)

cv2.imshow('dst', dst)
cv2.imshow('dst2', dst2)
cv2.waitKey()    
cv2.destroyAllWindows()

cv2.resize() 함수를 사용해서 간단하게 영상의 크기를 변환하는 코드이며 실행 결과는 다음과 같다.

dst.shape = (240, 320)
dst2.shape = (614, 768)

image

cv2.rotate() 영상 회전

src = cv2.imread('./data/lena.jpg')

dst1 = cv2.rotate(src, cv2.ROTATE_90_CLOCKWISE)
dst2 = cv2.rotate(src, cv2.ROTATE_90_COUNTERCLOCKWISE)

cv2.imshow('dst1',  dst1)
cv2.imshow('dst2',  dst2)
cv2.waitKey()    
cv2.destroyAllWindows()

cv2.rotate() 함수는 간단한 회전 함수이며 매개변수에 따라 90도, 180도를 시계방향, 반시계방향으로 회전할 수 있다. 또 다른 영상 어파인 변환이라는 확대/축소, 회전이 가능한 변환이 존재하는데, 이는 필요에 따라 추후에 학습하도록 한다.

07 산술연산, 비트연산, 비교범위, 수치연산 함수

OpenCV에서는 영상을 numpy.ndarray로 표현하기 때문에 numpy 연산을 사용할 수 있다.
numpy 연산을 사용할 때, 연산 결과가 자료형의 범위를 벗어나는 경우 주의해서 사용한다.
예를 들어, uint8 자료형의 영상 src1과 src2에서 dst = src1 + src2의 연산을 하는 경우, 255를 넘는 화소 값은 256으로 나눈 나머지를 갖는다.
그러나 dst = cv2.add(scr1, scr2)는 255를 넘는 화소 값은 최대값 255를 저장한다.
아래 표는 OpenCV의 주요 산술 사칙연산, 비트연산, 비교연산, 범위연산, 수치연산 함수이다.
src, src1, src2는 입력 영상이고, dst는 연산의 결과 영상이다.
대괄호 []는 옵션, mask는 8비트 1-채널 마스크 영상으로, mask(y, x) ≠ 0인 화소에서만 연산을 수행한다. dtype에 출력 영상의 화소 자료형을 명시할 경우 비트, 타입, 채널수를 명시한 상수를 사용해야한다.
OpenCV 함수의 매개변수 dst를 생략하거나, dst = None을 사용하면 결과 영상을 생성하여 반환한다.

image
주요 연산 함수가 많으므로 외우는 것은 불가능하고 필요에 따라 검색해서 사용하면 될 것 같다.

영상 연산 1

import cv2
import numpy as np

src1 = cv2.imread('./data/lena.jpg', cv2.IMREAD_GRAYSCALE)
src2 = np.zeros(shape=(512,512), dtype=np.uint8) + 100

dst1 = src1 + src2
dst2 = cv2.add(src1, src2)
#dst2 = cv2.add(src1, src2, dtype = cv2.CV_8U)

cv2.imshow('dst1',  dst1)
cv2.imshow('dst2',  dst2)
cv2.waitKey()    
cv2.destroyAllWindows()

앞서 설명했듯 연산방법에 따른 연산범위 차이에 의해 출력 결과가 다르게 나타난다.
image

영상 연산2 : 비트연산

import cv2
import numpy as np

src1 = cv2.imread('./data/lena.jpg')
src2 = cv2.imread('./data/opencv_logo.png')
cv2.imshow('src2',  src2)

#1
rows,cols,channels = src2.shape
roi = src1[0:rows, 0:cols]

#2
gray = cv2.cvtColor(src2,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(gray, 160, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)
cv2.imshow('mask',  mask)
cv2.imshow('mask_inv',  mask_inv)

#3
src1_bg = cv2.bitwise_and(roi, roi, mask = mask)
cv2.imshow('src1_bg',  src1_bg)

#4
src2_fg = cv2.bitwise_and(src2, src2, mask = mask_inv)
cv2.imshow('src2_fg',  src2_fg)

#5
##dst = cv2.add(src1_bg, src2_fg)
dst = cv2.bitwise_or(src1_bg, src2_fg)
cv2.imshow('dst',  dst)

#6
src1[0:rows, 0:cols] = dst

cv2.imshow('result',src1)
cv2.waitKey(0)
cv2.destroyAllWindows()

#1 : src2의 전체 크기에 대한 src1의 영역을 roi에 저장한다. #2 : 컬러영상 src2를 gray로 변환하고 전경과 배경을 분할하기 위해 이진 영상 mask를 생성하고, 비트 반전 영상 mask_inv를 생성한다.
#3 : roi영상에서 mask의 255(흰색 영역)인 화소에서만 bitwise_and() 함수로 src1의 배경영역을 복사하고, 전경 영역은 0(검은색 영역)인 src1_bg를 생성한다.
#4 : cv2.bitwise_and()로 mask_inv 마스크를 사용하여 src2에서 전경 영역을 src2_fg에 복사한다.
#5 : cv2.bitwise_or()로 src1_bg와 scr2_fg를 비트 OR 연산하여 dst를 생성한다. cv2.add()함수를 사용해도 결과는 같다.
#6 : dst를 src1[0:rows, 0:cols]에 복사하여, 결과 영상을 생성한다.
출력 결과는 다음과 같다.
image
image
image
마지막 출력 결과를 만들기 위해(두가지 영상을 한 윈도우에 표시하기 위해) 생각보다 복잡한 과정을 거쳐야 하며 이때 mask에 대한 개념과 사용 방법, 비트단위 연산 사용법에 대해 숙지할 필요가 있다.

08 수학 및 통계 함수

이 장에서는 여러가지 내용들을 담고 있지만, 영상처리에 사용되는 수학적인 이론들과, 이를 구현하는 여러가지 장치들에 대해서는 추후에 필요할때 찾아보도록 하자.

댓글남기기