본문 바로가기
강의 (Lecture)/OpenCV 마스터 with Python (초급)

OpenCV + Python 산술 연산과 논리 연산

by codingwalks 2024. 10. 8.
728x90
반응형

 

 

안녕하세요. 코딩산책입니다.

이미지 처리에서 산술 및 논리 연산은 두 개 이상의 이미지를 결합하거나, 이미지의 특정 부분을 수정하는 데 매우 유용하게 사용됩니다. 이 글에서는 OpenCV와 Python을 사용하여 이미지 간의 산술 및 논리 연산을 적용하는 방법을 다루어 보겠습니다. 이를 통해 이미지 합성, 밝기 및 대비 조정, 이미지 마스킹 등의 작업을 수행할 수 있습니다.
 

1. 산술 연산 (Arithmetic Operations)

OpenCV는 두 이미지 간의 덧셈, 뺄셈, 곱셈, 나눗셈 등의 산술 연산을 쉽게 수행할 수 있도록 다양한 함수를 제공합니다. 산술 연산을 통해 두 이미지를 결합하거나, 이미지의 밝기를 조정하는 등의 작업을 할 수 있습니다. 두 이미지 간의 곱셈이나 나눗셈은 이미지의 대비를 조정하는 작업에 사용은 가능하지만 거의 사용하지 않으며, 덧셈과 뺄셈을 주로 사용합니다. saturate는 8bit 이미지의 밝기 값은 0~255만을 표현하기 때문에, 범위를 벗어나는 경우에는 0 혹은 255로 값을 대체한다.

• cv2.add(): 이미지의 픽셀 값들에 상수를 더하거나 두 이미지의 픽셀 값을 더한다.

\[result(x,y)=saturate(img1(x,y)+constant)\]

\[result(x,y)=saturate(img1(x,y)+img2(x,y))\]

• cv2.subtract(): 이미지의 픽셀 값들에 상수를 빼거나 두 이미지의 픽셀 값을 뺀다.

\[result(x,y)=saturate(img1(x,y)-constant)\]

\[result(x,y)=saturate(img1(x,y)-img2(x,y))\]

• cv2.multiply(): 이미지의 픽셀 값들에 상수를 곱하거나 두 이미지의 픽셀 값을 곱한다.

\[result(x,y)=saturate(img1(x,y)*constant)\]

\[result(x,y)=saturate(img1(x,y)*img2(x,y))\]

• cv2.divide(): 이미지의 픽셀 값들에 상수를 나누거나 두 이미지의 픽셀 값을 나눈다.

\[result(x,y)=saturate(img1(x,y)/constant)\]

\[result(x,y)=saturate(img1(x,y)/img2(x,y))\]

 

1.1. 이미지와 상수 간 덧셈과 곱셈 연산

이미지와 상수간 산술연산 중에서도 덧셈과 곱셈 연산을 사용하면 이미지의 밝기와 대비를 상수를 이용하여 쉽게 조정할 수 있습니다.

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('resources/lena.bmp', cv2.IMREAD_GRAYSCALE)

# Increase brightness (add constant)
bright_img = np.clip(cv2.add(img, 100), 0, 255).astype(np.uint8)

# Increase contrast (multiply by a constant)
contrast_img = np.clip(cv2.multiply(img, 1.5), 0, 255).astype(np.uint8)

plt.figure(figsize=(15, 4), linewidth=2)

plt.subplot(1, 3, 1)
plt.imshow(img, cmap='gray')
plt.title('Original Image')
plt.axis('off')

plt.subplot(1, 3, 2)
plt.imshow(bright_img, cmap='gray')
plt.title('Bright Image')
plt.axis('off')

plt.subplot(1, 3, 3)
plt.imshow(contrast_img, cmap='gray')
plt.title('Contrast Image')
plt.axis('off')

# Show plot
plt.tight_layout()
plt.savefig('results/arithmetic.png', dpi=200, facecolor='#eeeeee', edgecolor='black')
plt.show()

original, brightness(+100), contrast(x1.5)

1.2. 이미지 간 덧셈 연산

import cv2
import numpy as np

# Load image
img1 = cv2.imread('resources/lena.bmp', cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread('resources/baboon.bmp', cv2.IMREAD_GRAYSCALE)

# Resize images (scale to the same size)
img1 = cv2.resize(img1, (512, 512))
img2 = cv2.resize(img2, (512, 512))

# Image addition operation
added_image = np.clip(cv2.add(img1, img2), 0, 255).astype(np.uint8)

cv2.imshow('Added Image', added_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

image's arithmetic operation

1.3. 이미지 간 뺄셈 연산

이미지 간 뺄셈 연산은 이미지 마스킹으로 사용할 수 있습니다. 영상처리에서 많이 사용하는 예제로는 그라데이션 마스크를 사용해 특정 영역을 마스킹 하는 방식을 볼 수 있습니다. 그라데이션 마스크는 픽셀 값이 0에서 255로 점진적으로 변화하는 마스크로, 이를 통해 이미지의 일부 영역을 부드럽게 처리할 수 있습니다. 그라데이션 마스크를 만들기 위해 Sigmoid 함수를 사용해 그라데이션을 생성한 후, 이를 원 모양으로 확산하여 그라데이션 마스크 이미지를 만들 수 있습니다. 만들어진 그라데이션 마스크를 사용해 뺄셈 연산을 수행하면 아래의 결과와 같이 확인 할 수 있습니다.

import cv2
import numpy as np

# Load image (convert to black and white image)
img = cv2.imread('resources/lena.bmp', cv2.IMREAD_GRAYSCALE)

# Check the image size and create a gradient mask of the same size
height, width = img.shape[:2]

# Set the center coordinates and radius of the circle
center = (width // 2, height // 2)
radius = 200

# Create coordinates for creating gradients
X, Y = np.meshgrid(np.arange(width), np.arange(height))

# # Calculating distance from the center of the image
dist_from_center = np.sqrt((X - center[0])**2 + (Y-center[1])**2)

# Calculating gradient using sigmoid function
scale = 0.05
gradient_mask = 1 / (1 + np.exp(-scale * (dist_from_center - radius)))
gradient_mask = gradient_mask * 255
gradient_mask = gradient_mask.astype(np.uint8)

# Subtraction operation
subtracted_image1 = cv2.subtract(img, gradient_mask)
subtracted_image2 = cv2.subtract(gradient_mask, img)

cv2.imshow('Original Image', img)
cv2.imshow('Gradient Mask', gradient_mask)
cv2.imshow('Subtracted Image1', subtracted_image1)
cv2.imshow('Subtracted Image2', subtracted_image2)
cv2.waitKey(0)
cv2.destroyAllWindows()

cv2.subtract

1.4. cv2.addWeighted 산술 연산

OpenCV의 addWeighted() 함수는 두 이미지를 가중치를 적용하여 병합할 수 있는 매우 유용한 함수입니다. 이를 사용하면 두 이미지 간의 선형 보간(Linear Interpolation)을 통해 자연스러운 합성을 할 수 있습니다.

\[dst(x,y)=saturate(\alpha \cdot src1(x,y)+\beta \cdot src2(x,y)+\gamma)\]

OpenCV에서 제공되는 함수는 cv2.addWeighted(src1, alpha, src2, beta, gamma) 이다.

• src1, src2: 합성할 두 이미지
• alpha: 첫 번째 이미지의 가중치
• beta: 두 번째 이미지의 가중치
• gamma: 결과 이미지에 더할 추가값 (일반적으로 0)

 

import cv2

# Load image
img1 = cv2.imread('resources/lena.bmp', cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread('resources/airplane.bmp', cv2.IMREAD_GRAYSCALE)

# Resize images (scale to the same size)
img1 = cv2.resize(img1, (512, 512))
img2 = cv2.resize(img2, (512, 512))

# Merge image weights
blended_image = cv2.addWeighted(img1, 0.7, img2, 0.3, 0)

cv2.imshow('Blended Image', blended_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

blended image

 

2 논리 연산 (Logical Operations)

OpenCV에서 제공하는 논리 연산(bitwise operations)은 이미지 처리에서 특정 영역을 마스킹하거나 합성할 때 매우 유용하게 사용됩니다. 논리 연산은 각 픽셀 값에 대해 비트 단위로 연산을 수행하며, 일반적으로 이미지 간의 연산이나 마스크를 사용하여 특정 영역만 처리할 때 사용됩니다.

• cv2.bitwise_and(): AND 연산\((A \land B)\)은 두 이미지의 픽셀 값이 모두 1일 때만 결과가 1이 됩니다. 그렇지 않으면 결과는 0입니다.

\[\text{Result}(x, y) = A(x, y) \land B(x, y)\]

A (픽셀 값) B (픽셀 값) A AND B
1 1 1
1 0 0
0 1 0
0 0 0

 cv2.bitwise_or(): OR 연산\((A \lor B)\)은 두 이미지 중 하나라도 1이면 결과가 1이 됩니다.

\[\text{Result}(x, y) = A(x, y) \lor B(x, y)\]

A (픽셀 값) B (픽셀 값) A OR B
1 1 1
1 0 1
0 1 1
0 0 0

 cv2.bitwise_xor(): XOR 연산\((A \oplus B)\)은 두 값이 다를 때 1이 됩니다. 즉, A와 B가 서로 다른 경우에만 결과가 1입니다.

\[\text{Result}(x, y) = A(x, y) \oplus B(x, y)\]

A (픽셀 값) B (픽셀 값) A XOR B
1 1 0
1 0 1
0 1 1
0 0 0

 cv2.bitwise_not(): NOT 연산\((\neg A)\)은 하나의 이미지 또는 픽셀에 적용되며, 각 비트를 반전시킵니다. 즉, 1은 0으로, 0은 1로 변환됩니다.

\[\text{Result}(x, y) = \neg A(x, y)\]

A (픽셀 값) NOT A
1 0
0 1

 

import cv2
import numpy as np

# Load image (convert to black and white image)
img = cv2.imread('resources/lena.bmp', cv2.IMREAD_GRAYSCALE)

# Check the image size and create a gradient mask of the same size
height, width = img.shape[:2]
mask = np.zeros((height, width), dtype=np.uint8)
cv2.circle(mask, (height//2, width//2), 200, 255, -1)
cv2.imshow('Mask', mask)

# Logical operations
bitwise_and = cv2.bitwise_and(img, mask)
bitwise_or = cv2.bitwise_or(img, mask)
bitwise_xor = cv2.bitwise_xor(img, mask)
bitwise_not = cv2.bitwise_not(img, mask)

cv2.imshow('Original Image', img)
cv2.imshow('Bitwise AND', bitwise_and)
cv2.imshow('Bitwise OR', bitwise_or)
cv2.imshow('Bitwise XOR', bitwise_xor)
cv2.imshow('Bitwise NOT', bitwise_not)
cv2.waitKey(0)
cv2.destroyAllWindows()

bitwise results



3. 결론

이번 글에서는 OpenCV와 Python을 사용하여 이미지 간의 산술 및 논리 연산을 수행하는 방법과 addWeighted()를 이용한 배열 병합을 다루었습니다. 산술 연산을 통해 이미지의 밝기와 대비를 조정하고, 논리 연산을 통해 마스킹 작업을 수행하는 방법과 addWeighted() 함수를 사용해 두 이미지를 가중치를 적용하여 자연스럽게 병합할 수 있음을 확인했습니다. 이러한 기법들은 이미지 처리에서 매우 유용하며, 다양한 편집 및 합성 작업에 쉽게 적용할 수 있습니다.

해당 포스트가 유용하셨다면 하단의 좋아요와 구독하기 부탁드립니다. ^^

Buy me a coffee

 

[Codingwalks]에게 송금하기 - AQR

[Codingwalks]에게 송금하기 - AQR

aq.gy

★ 모든 내용은 아래의 링크를 참조하였습니다. ★

 

OpenCV: OpenCV-Python Tutorials

Core Operations In this section you will learn basic operations on image like pixel editing, geometric transformations, code optimization, some mathematical tools etc.

docs.opencv.org

 

728x90
반응형