[opencv-python] 이미지 연산하는 법


Image Addition

이미지 연산으로 OpenCV에 add()와 numpy 연산으로 이미지를 더할 수 있습니다.


두 이미지를 연산하기 위해서는 반드시 "채널"과 "데이터 타입" 이 같아야하며 이미지에 scalar 값을 더할 수 있습니다.

OpenCV와 numpy 연산의 차이점은
OpenCV의 cv2.add()는 Saturation 연산,
numpy는 modulo 연산을 합니다.



Saturation 연산

Saturation은 임계값을 정해 그 값을 벗어나는 경우 특정 값으로 계산하는 방식입니다.

이미지에서는 add 연산으로 픽셀 값이 255(임계값) 이상인 값들은 255로
0(임계값) 이하인 값들은 0으로 표현하는 연산입니다.

import numpy as np

mat0 = np.uint8([[130, 140], [150, 160]])
mat1 = np.uint8([[100, 100], [150, 150]])
mat0_add_mat1 = cv2.add(mat0, mat1)

print("mat0\n{0}\n".format(mat0))
print("mat1\n{0}\n".format(mat1))
print("add(mat0, mat1)\n{0}".format(mat0_add_mat1))

# 출력
# mat0
# [[130 140]
#  [150 160]]

# mat1
# [[100 100]
#  [150 150]]

# add(mat0, mat1)
# [[230 240]
#  [255 255]]

mat0 + mat1 과정에서
(150 + 150), (160 + 150) = 300, 310이 각각 나와야하지만
Saturation 연산을 통해 255가 넘은 값들을 모두 255로 변경하였음을 확인할 수 있습니다.



modulo 연산

mod 또는 MOD로 표현되며 나머지 연산을 뜻합니다.

이미지에서는 연산 결과가 256(이미지는 0-255를 표현)보다 큰 경우에 256으로 나눈 나머지 값을 사용합니다.

mat0 = np.uint8([[130, 140], [150, 160]])
mat1 = np.uint8([[100, 100], [150, 150]])
mat0_add_mat1 = mat0 + mat1

print("mat0\n{0}\n".format(mat0))
print("mat1\n{0}\n".format(mat1))
print("add(mat0, mat1)\n{0}".format(mat0_add_mat1))

# 출력
# mat0
# [[130 140]
#  [150 160]]

# mat1
# [[100 100]
#  [150 150]]

# add(mat0, mat1)
# [[230 240]
#  [ 44  54]]

mat0 + mat1 과정에서
(150 + 150), (160 + 150) = 300, 310이 각각 나와야하지만
modulo 연산을 통해 255가 넘은 값들은 모두 나머지값으로 대체함을 볼 수 있습니다.
300 % 256 = 44
300 % 256 = 54



numpy를 이용한 이미지 연산(modulo)

두개의 이미지 픽셀 값들을 더해줍니다.
두개의 이미지를 더하기 위해서는 이미지의 크기(reshape), 데이터 타입(dtype)이 같아야합니다.

import cv2

img1 = cv2.imread("image/add1.jpg")
print("img1.shape = {0}, img1.dtype = {1}".format(img1.shape, img1.dtype))
img2 = cv2.imread("image/add2.jpg")
print("img2.shape = {0}, img1.dtype = {1}".format(img2.shape, img2.dtype))
img1_add_img2 = img1 + img2 
print("img1 + img2.shape = {0}, img1_add_img2.dtype = {1}".format(img1_add_img2.shape, img1_add_img2.dtype))

cv2.imshow("img1", img1)
cv2.imshow("img2", img2)
cv2.imshow("img1 + img2", img1_add_img2)
cv2.waitKey()

# 출력
# img1.shape = (360, 360, 3), img1.dtype = uint8
# img2.shape = (360, 360, 3), img1.dtype = uint8
# img1_add_img2.shape = (360, 360, 3), img1_add_img2.dtype = uint8


2개의 이미지를 더해 픽셀 값이
255 이상인 값들은 256 으로 나누어 나머지 값으로 대체하기 때문에
기존에 이미지 색상이 깨지는걸 확인할 수 있습니다.



cv2.add()를 이용한 이미지 연산(saturation)

두개의 이미지 픽셀 값들을 더해줍니다.
두개의 이미지를 더하기 위해서는 이미지의 크기(reshape), 데이터 타입(dtype)이 같아야합니다.

import cv2

img1 = cv2.imread("image/add1.jpg")
print("img1.shape = {0}, img1.dtype = {1}".format(img1.shape, img1.dtype))
img2 = cv2.imread("image/add2.jpg")
print("img2.shape = {0}, img1.dtype = {1}".format(img2.shape, img2.dtype))
img1_add_img2 = cv2.add(img1, img2)
print("cv2.add(img1, img2).shape = {0}, img1_add_img2.dtype = {1}".format(img1_add_img2.shape, img1_add_img2.dtype))

cv2.imshow("img1", img1)
cv2.imshow("img2", img2)
cv2.imshow("img1 + img2", img1_add_img2)
cv2.waitKey()

# 출력
# img1.shape = (360, 360, 3), img1.dtype = uint8
# img2.shape = (360, 360, 3), img1.dtype = uint8
# cv2.add(img1, img2).shape = (360, 360, 3), img1_add_img2.dtype = uint8


2개의 이미지를 더해 픽셀 값이
255 이상인 값들은 255로 0 이하인 값들은 0으로 표현하여
img1과 img2의 픽셀 값들을 더해 img1_add_img2로 반환했습니다.

각각의 이미지 픽셀 값들을 더하는 과정에서
픽셀 값들이 255에 가까워지기 때문에 img1_add_img2를 imshow()로 출력했을 때
하얀색 부분이 많은걸 볼 수 있습니다. (255로 갈수록 백, 0으로 갈수록 흑)



cv2.addWeighted를 이용한 이미지 연산(saturation)

cv2.addWeighted(src1, alpha, src2, beta, gamma)


서로다른 가중치를 주어 2개의 이미지를 더해줍니다.
blending(혼합) or transparency(투명성)의 효과를 볼 수 있습니다.

즉. 2개의 이미지를 더하는 과정에서 가중치를 두어 이미지가 결합된 형식으로 사용할 수도, 이미지를 투명하게 표현할 수도 있습니다.

weighted1 = cv2.addWeighted(img1, 0.5, img2, 0.5, 0)
weighted2 = cv2.addWeighted(img1, 0.7, img2, 0.3, 0)

cv2.imshow("addWeighted(0.5, 0.5)", weighted1)
cv2.imshow("addWeighted(0.7, 0.3)", weighted2)
cv2.waitKey()


img1과 img2의 가중치를 어떻게주냐에 따라 이미지가 변환합니다.


참고자료



댓글

이 블로그의 인기 게시물

[opencv-python] 이미지 크기조절(resize) 하는 법

[python]파이썬: csv reader header skip (첫번째 행 무시하기, 안읽기)

[python] selenium close와 quit 차이점