[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 = 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]]
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
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
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()
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의 가중치를 어떻게주냐에 따라 이미지가 변환합니다.
참고자료
- https://docs.opencv.org/master/d0/d86/tutorial_py_image_arithmetics.html
- https://opencv-python.readthedocs.io/en/latest/doc/07.imageArithmetic/imageArithmetic.html
- https://dal2iya.tistory.com/85
댓글
댓글 쓰기