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

OpenCV + Python 필터와 컨볼루션

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

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

이번 글에서는 OpenCV와 Python을 사용하여 다양한 이미지 필터링 기법에 대해 알아보겠습니다. 필터링의 기본적인 이론, 수학적 표현, 그리고 실제 코드를 통해 필터링 기법을 이해하고 구현해 보겠습니다. 특히 샤프닝과 언샤프 마스킹에 대해서도 다룰 예정입니다.

 

1. 이미지 필터링

이미지 필터링은 이미지의 픽셀 값을 조작하여 특징을 강조하거나 노이즈를 줄이는 작업입니다. 필터는 이미지를 부드럽게 하거나, 더 선명하게 만들거나, 특정 특징을 추출하는 데 사용됩니다. 아래는 필터링 연산에서 중요한 컨볼루션의 원리를 설명합니다. 컨볼루션은 작은 필터(커널)를 사용하여 이미지의 각 픽셀을 변환하는 연산입니다.

이미지 필터링은 이미지를 수정하거나 향상시키는 이미지 처리의 기본 연산입니다. 이미지 필터링에 가장 일반적인 기술 중 하나는 합성입니다. 합성은 두 함수를 결합하여 세 번째 함수를 생성하는 수학적 연산입니다. 이미지 처리의 맥락에서 한 함수는 입력 이미지이고 다른 함수는 커널(필터 또는 마스크라고도 함)입니다. 합성 연산은 커널을 이미지 위로 밀어서 요소별 곱셈을 수행하고 결과를 합산하여 출력 픽셀 값을 생성하며, 이 프로세스는 이미지의 모든 픽셀에 대해 반복됩니다. 커널을 사용해 적용되는 분야로는 이미지를 부드럽게 하거나, 더 선명하게 만들거나, 특정 특징을 추출하는 데 사용됩니다.

\[ G(x, y) = \sum_{i=-k}^{k} \sum_{j=-k}^{j} I(x+i, y+j) \cdot H(i, j) \]

여기서 \( I(x, y) \) 는 입력 이미지, \( H(i, j) \) 는 커널, \( G(x, y) \) 는 출력 이미지입니다.

소스코드:

import cv2
import numpy as np

# Load an image
img = cv2.imread('resources/lena.bmp')

# Define a Gaussian blur kernel
kernel_blur = np.array([[1, 2, 1],
                       [2, 4, 2],
                       [1, 2, 1]]) / 16

# Apply Gaussian blur using convolution
blurred_img = cv2.filter2D(img, -1, kernel_blur)

# Define a sharpening kernel
kernel_sharpen = np.array([[0, -1, 0],
                         [-1, 5, -1],
                         [0, -1, 0]])

# Apply sharpening using convolution
sharpened_img = cv2.filter2D(img, -1, kernel_sharpen)

# Display the results
cv2.imshow('Original Image', img)
cv2.imshow('Blurred Image', blurred_img)
cv2.imshow('Sharpened Image', sharpened_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

2d-image filtering

이 코드는 OpenCV에서 합성 연산인 cv2.filter2D() 함수를 사용하여 이미지를 흐리게 및 선명하게 적용하는 방법을 보여줍니다.

 

2. 이미지 블러링 (Blurring)

다양한 종류의 필터는 각기 다른 특징과 장단점을 가지고 있으며, 어떤 필터를 사용할지는 이미지의 특성과 처리 목적에 따라 달라집니다. 일반적으로 가우시안 노이즈는 평균 필터나 가우시안 필터, 임펄스 노이즈는 미디언 필터, 노이즈 제거와 엣지 보존을 동시에 원할 때는 바이레터럴 필터를 사용합니다.

2.1. 평균 필터 (Average filter)

커널 내 픽셀 값을 평균하여 이미지를 부드럽게 만드는 필터입니다.

\[ G(x, y) = \frac{1}{n^2} \sum_{i=-k}^{k} \sum_{j=-k}^{j} I(x+i, y+j) \]

여기서 \( n \) 은 커널의 크기입니다.

장점:

  • 구현이 간단하고 계산량이 적어 실시간 처리에 적합합니다.
  • 가우시안 노이즈와 같은 랜덤 노이즈 제거에 효과적입니다.

단점:

  • 이미지의 디테일(엣지, 모서리 등)이 흐릿해지는 문제가 발생합니다.
  • 이미지의 경계선이 번지는 현상(blurring)이 발생할 수 있습니다.
  • 모든 종류의 노이즈에 효과적인 것은 아닙니다.

OpenCV 함수:

average_blurred = cv2.blur(image, (5, 5))

2.2. 가우시안 필터 (Gaussian filter)

가우시안 커널을 사용하여 이미지의 고주파 노이즈를 감소시키는 필터로, 평균 필터보다 가장자리 보존이 더 우수합니다.

\[ G(x, y) = \sum_{i=-k}^{k} \sum_{j=-k}^{j} I(x+i, y+j) \cdot \frac{1}{2\pi\sigma^2} e^{-\frac{x^2 + y^2}{2\sigma^2}} \]

여기서 \( \sigma \) 는 가우시안 분포의 표준 편차입니다.

장점:

  • 평균 필터보다 자연스러운 블러링 효과를 얻을 수 있습니다.
  • 가우시안 노이즈 제거에 매우 효과적입니다.

단점:

  • 계산량이 평균 필터보다 많습니다.
  • 이미지의 디테일 손실은 여전히 발생할 수 있습니다.

OpenCV 함수:

gaussian_blurred = cv2.GaussianBlur(img, (5, 5), 0)

2.3. 미디언 필터 (Median filter)

커널 내의 픽셀 값들을 오름차순 또는 내림차순으로 정렬하고, 정렬된 값 중 중앙값을 해당 픽셀의 새로운 값으로 대체하여 노이즈를 제거하는 비선형 필터입니다. 특히 소금-후추 노이즈 제거에 효과적입니다.

장점:

  • 임펄스 노이즈(소금과 후추 노이즈) 제거에 매우 효과적입니다.
  • 이미지의 디테일을 비교적 잘 보존합니다.
  • 에지 번짐 현상이 적습니다.

단점:

  • 가우시안 노이즈 제거에는 평균 필터나 가우시안 필터만큼 효과적이지 않습니다.
  • 계산량이 평균 필터보다 많습니다.

OpenCV 함수:

median_blurred = cv2.medianBlur(img, 5)

2.4. 양방향 필터 (Bilateral filter)

가장자리를 보존하면서 노이즈를 제거하는 필터입니다. 필터링 과정에서 픽셀 값의 차이뿐 아니라 공간적 거리도 고려합니다. 공간 영역과 픽셀 값 영역 두 가지 영역에서 가우시안 가중치를 사용하여 필터링하는 필터로써, 공간 영역에서는 공간적인 거리에 따라 가중치를 부여하고, 값 영역에서는 픽셀 값의 차이에 따라 가중치를 부여합니다.

장점:

  • 노이즈 제거와 동시에 엣지를 보존하는 효과가 뛰어납니다.
  • 자연스러운 블러링 효과를 얻을 수 있습니다.

단점:

  • 계산량이 매우 많아 실시간 처리에는 부적합할 수 있습니다.
  • 파라미터 조절이 복잡합니다.

OpenCV 함수:

bilateral_filtered = cv2.bilateralFilter(img, 9, 75, 75)

2.5. 전체 소스코드

import cv2
import matplotlib.pyplot as plt

def apply_blurring(image):
    # Average Blur
    avg_blur = cv2.blur(image, (5, 5))
    # Gaussian Blur
    gauss_blur = cv2.GaussianBlur(image, (5, 5), 0)
    # Median Blur
    median_blur = cv2.medianBlur(image, 5)
    # Bilateral Filter
    bilateral = cv2.bilateralFilter(image, 9, 75, 75)
    return avg_blur, gauss_blur, median_blur, bilateral

# Load an image
image = cv2.imread('input_image.jpg', cv2.IMREAD_GRAYSCALE)

# Apply blurring techniques
avg, gauss, median, bilateral = apply_blurring(image)

# Display the results
cv2.imshow('Average Blur', avg)
cv2.imshow('Gaussian Blur', gauss)
cv2.imshow('Median Blur', median)
cv2.imshow('Bilateral Filter', bilateral)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

image blurring

 

3. 엠보싱 (Embossing)

엠보싱은 이미지의 여러 영역 간의 전환을 강조하여 3D와 같은 효과를 내는 필터링 기술입니다. 엠보싱은 원본 이미지의 경계에 따라 각 픽셀을 하이라이트 또는 섀도우로 대체하여 작동하며, 아래의 엠보싱 커널을 사용합니다.

\[ K = \begin{bmatrix}
0 & -1 & -1 \\
1 & 0 & -1 \\
1 & 1 & 0
\end{bmatrix} \]

import cv2
import matplotlib.pyplot as plt

def apply_emboss(image):
    # Embossing kernel
    kernel = np.array([[0, -1, -1],
                       [1,  0, -1],
                       [1,  1,  0]])
    
    return cv2.filter2D(image, -1, kernel, anchor=(-1,-1), delta=128)

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

# Apply embossing filter
embossed = apply_emboss(image)

# Display results
cv2.imshow('Original Image', image)
cv2.imshow('Embossed Image', embossed)
cv2.waitKey(0)
cv2.destroyAllWindows()

image embossing

 

4. 이미지 샤프닝과 언샤프 마스크

4.1. 샤프닝 (Sharpening)

컨볼루션 연산을 통해 이미지의 가장자리를 강조하여 이미지를 선명하게 만드는 기법으로 아래의 샤프닝 커널을 사용합니다.

\[ K = \begin{bmatrix}
-1 & -1 & -1 \\
-1 & 9 & -1 \\
-1 & -1 & -1
\end{bmatrix} \]

OpenCV 함수:

kernel = np.array([[-1, -1, -1], [-1, 9, -1], [-1, -1, -1]])
sharpened = cv2.filter2D(img, -1, kernel)

4.2. 언샤프 마스크 (Unsharp Mask)

언샤프 마스크는 블러 처리된 이미지와 원본 이미지의 차이를 이용해 가장자리를 강조하는 기법입니다.

\[ I_{\text{unsharp}} = I + \lambda (I - G(I)) \]

여기서 \( I \) 는 원본 이미지, \( G(I) \) 는 가우시안 블러 처리된 이미지, \( \lambda \) 는 샤프닝 강도를 조절하는 계수입니다.

OpenCV 함수:

# Gaussian blur processing
gaussian_blurred = cv2.GaussianBlur(img, (9, 9), 10.0)
# Apply unsharp mask
unsharp_image = cv2.addWeighted(img, 1.5, gaussian_blurred, -0.5, 0)

4.3. 전체 소스코드

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

def apply_sharpening(image):
    kernel = np.array([[-1, -1, -1],
                       [-1,  9, -1],
                       [-1, -1, -1]])
    return cv2.filter2D(image, -1, kernel)

def apply_unsharpening_mask(image):
    gaussian = cv2.GaussianBlur(image, (5,5), 2)
    return cv2.addWeighted(image, 1.5, gaussian, -0.5, 0)

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

# Apply filters
sharpened = apply_sharpening(image)
unsharpened = apply_unsharpening_mask(image)

# Display the results
cv2.imshow('Sharpened', sharpened)
cv2.imshow('Unsharp Mask', unsharpened)
cv2.waitKey(0)
cv2.destroyAllWindows()

sharpening and unsharp mask

 

5. 결론

이번 글에서는 OpenCV와 Python을 사용하여 다양한 이미지 필터링 기법을 살펴보았습니다. 필터링은 이미지 처리에서 매우 중요한 역할을 하며, 노이즈 제거, 가장자리 강조, 이미지 디테일 보존 등 여러 목적에 맞게 적용될 수 있습니다. 평균 필터와 가우시안 필터는 이미지에서 노이즈를 제거하면서 부드럽게 만들어주지만, 디테일이 손실될 수 있습니다. 미디언 필터는 소금-후추 노이즈와 같은 임펄스 노이즈 제거에 탁월하며, 바이레터럴 필터는 노이즈 제거와 엣지 보존 모두에서 뛰어난 성능을 보입니다. 또한, 샤프닝 필터와 언샤프 마스크를 통해 이미지의 가장자리를 선명하게 만들어 세부 사항을 강조할 수 있었습니다. 샤프닝은 직접적으로 이미지를 선명하게 만드는 반면, 언샤프 마스킹은 블러 처리된 이미지와의 차이를 이용하여 세밀한 조정이 가능했습니다. 이미지 처리에서 필터의 선택은 이미지의 특성과 처리 목적에 따라 달라지며, 이와 같은 필터링 기법을 적절히 활용하면 다양한 상황에서 이미지 품질을 크게 향상시킬 수 있습니다. 앞으로도 이러한 필터링 기술을 프로젝트에 적용하여 더 나은 이미지를 만들 수 있기를 바랍니다.

 

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

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
반응형