공간 영역 필터링은 연산 대상 픽셀과 그 주변 픽셀들을 활용하여 새로운 픽셀 값을 얻는 방법
이때 주변 픽셀을 어느 범위까지 활용할지 그리고 연산은 어떻게 할지를 결정해야 한다. 이런 역할을 하는 것이 바로 커널(kernel)이며 윈도(window), 필터(filter), 마스크(mask)라고도 부른다. 아래 그림에서 가운데 있는 3 x 3 짜리 행렬이 바로 커널이다.
컨볼루션 연산은 공간 영역 필터링을 위한 핵심 연산 방법입니다. 아래와 같은 방식으로 kernel을 source 이미지에 연산을 하게되고, 한 픽셀 씩 kernel을 이동하여 연산하는 방식이다.
출처 : https://www.slipp.net/wiki/pages/viewpage.action?pageId=26641520
공간 영역 필터링을 통해 아래와 같은 영상처리 결과물을 얻을 수 있다.
영상 bluring, smoothing
영상 noise 제거
예제 코드
import cv2
from ipykernel import kernel_protocol_version
import numpy as np
lena_img = "D:/dev/wego-project/erp_udp/opencv-examples/img/lena512.bmp"
medical_img = "D:/dev/wego-project/erp_udp/opencv-examples/img/medical.jpeg"
# 영상 불러오기
lena_color = cv2.imread(lena_img,1)
medical_color = cv2.imread(medical_img,1)
gray = cv2.cvtColor(lena_color,cv2.COLOR_BGR2GRAY)
### filter 2d
# 필터 마스크 생성
kernel = np.ones((5,5),np.float32) /25
f2d = cv2.filter2D(lena_color,-1,kernel) # -1은 입력 영상과 동일한 데이터의 출력 영상 생성
### gaussian filtering
gau_lena = cv2.GaussianBlur(lena_color,(5,5),0)
gau_comp = cv2.hconcat([lena_color,cv2.hconcat([f2d,gau_lena])])
cv2.imshow("compare gaussian filtering result",gau_comp)
### medain filtering
median_medical = cv2.medianBlur(medical_color,5)
gau_medical = cv2.GaussianBlur(medical_color,(5,5),0)
median_comp = cv2.hconcat([medical_color,cv2.hconcat([gau_medical,median_medical])])
cv2.imshow("compare medain filtering result", median_comp)
### bilateral filtering
bilateral_lena = cv2.bilateralFilter(lena_color,15,40,100)
gau_lena = cv2.GaussianBlur(lena_color,(5,5),0)
bilateral_comp = cv2.hconcat([lena_color,cv2.hconcat([gau_lena,bilateral_lena])])
cv2.imshow("compare bilateral filter result",bilateral_comp)
cv2.waitKey()
cv2.destroyAllWindows()
💡 영상을 부드럽게 만들어주는 대표적인 필터. 영상 내의 가장자리가 무뎌지는 효과를 갖는다.주변 픽셀들의 평균값을 적용하면 픽셀 간 차이가 적어져 선명도가 떨어져 전체적으로 흐릿해진다.
아래는 평균 값 필터 마스크 3x3 , 5x5 를 나타낸 그림이다.
아래의 kernel을 cv2.filter2d의 인자로 넣어 filtering을 진행한다.
커널 크기 별 결과 영상
원본 영상
3x3 kernel 적용 결과 영상
5x5 kernel 적용 결과 영상
커널의 크기가 커질 수록 더 많은 픽셀에 대하여 평균을 구하여 블러링이 강해짐을 보인다.
💡 평균값 필터 블러링의 단점은 필터링 대상 위치에서 가까이 있는 픽셀과 멀리 있는 픽셀이 모두 같은 가중치를 사용하여 평균을 계산합니다. 멀리 있는 픽셀의 영향을 많이 받아 필터 결과의 퀄리티가 낮아지게 됩니다. 이를 보안하기위해 가우시안 필터링을 사용한다.
아래와 같은 가우시안 분포를 사용하여 가까운 픽셀에는 큰 가중치를 멀리 있는 픽셀에는 작은 가중치를 부여하여 필터링을 진행한다.
cv2.GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None)
src: 입력 영상. 각 채널 별로 처리됨.
dst: 출력 영상. src와 같은 크기, 같은 타입.
ksize: 가우시안 커널 크기. (0, 0)을 지정하면 sigma 값에 의해 자동으로 결정됨
(ksize =8*sigma+1)
sigmaX: x방향 sigma.
sigmaY: y방향 sigma. 0이면 sigmaX와 같게 설정.
borderType: 가장자리 픽셀 확장 방식.
sigma 별 가우시안 필터 적용 결과
sigma = 1
sigma = 2
sigma = 3
시그마가 커질 수록 블러링의 강도가 세짐을 확인 할 수 있다.
💡 아래와 같이 흑점과 흰점이 무작위로 나타나는 노이즈를 salt and pepper noise라고 한다. 이러한 노이즈를 제거하기 위해 픽셀의 중앙값을 사용하는 Median filter를 사용한다.
kernel을 사용하여 이미지와 컨볼루션 연산을 진행한 위의 filtering과는 다르게 아래의 그림처럼 주변 픽셀들의 값들을 정렬하여 그 중앙값(median)으로 픽셀 값을 대체한다.
💡 가우시안 filtering을 하게 되면 영상의 엣지가 손상되는 단점이 있다. 이를 해결하기 위해 기준 픽셀과 이웃 픽셀과의 거리, 그리고 픽셀 값의 차이를 함께 고려하여 블러링 정도를 조절하는 방식을 사용하여 필터링을 진행하는 방식을 사용한다.
아래의 그림과 같이 하늘 부분은 엣지가 없으므로 가우시안 필터링을 그대로 진행하고 나머지 부분을 보게 되면 엣지 부분이면 가우시안 필터의 일부분만을 가져와 필터링을 진행하여 엣지를 보존하게 된다.
cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace, dst=None, borderType=None)
bilateral filter 적용 결과 비교 영상
원본 영상
왼쪽 : gaussian filtering 영상, 오른쪽 : bilateral filter 영상
bilateral filter를 사용한 영상의 엣지가 보존됨을 볼 수있다.