Python Opencv - #18, 영상 잡음 제거
▶ 영상의 잡음
영상의 잡음(Noisr)는 영상의 픽셀 값에 추가되는 원치 않는 형태의 신호를 의미합니다.
f(x,y) = s(x,y) + n(x,y)
여기서 f(x,y)는 획득된 영상, s(x,y)는 원본 신호, n(x,y)는 잡음을 의미합니다.
대부분의 경우 센서에서 잡음이 추가됩니다.
→ 잡음의 종류
두 가지 잡음을 알아보겠습니다.
(1) 가우시안 잡음(Gaussian noise)
대부분의 잡음 형태는 가우시안 형태입니다.
잡음이 가우시한 형태로 추가되는데 픽셀값에서 조금 더 어두워지거나 밝아지게 됩니다.
(2) 소금$후추 잡음(Salt&Pepper)
요즘 소금 후추 잡음은 거의 없습니다.
→ 잡음 제거(1) - 미디언 필터 - cv2.medianBlur
미디언 필터(Median filter)는 주변 픽셀들의 값들을 정렬하여 그 중앙값(median)으로 픽셀 값을 대체합니다.
소금-후추 잡음 제거에 효과적 입니다. 많이 사용하지 않지만 아이디어가 기발하여 배워보겠습니다.
미디언 필터는 마스크 모양만 지정합니다.
사각형 행렬을 1열로 나열하고 sort합니다.
중앙값에 있는 값을 이용해서 셋팅합니다.
특징은 기존의 필터들과 다르게 입력값에 있는 값을 결과값으로 반환한다는 것 입니다.
→ 미디언 필터링 함수 - cv2.medianBlur
OpenCV에서는 미디언 필터링 함수로 cv2.medianBlur 명령어를 제공하고 있습니다.
약간 블러링 되는 효과가 있으며 픽셀들이 뭉치는 형태를 띄어 보기 좋은 결과가 아닙니다.
화질의 퀄리티면에서 좋은 결과가 아닙니다.
[함수 설명]
cv2.medianBlur(src, ksize, dst=None) -> dst
src : 입력 영상. 각 채널 별로 처리됨
ksize : 커널 크기. 1보다 큰 홀수를 지정. 숫자 하나를 집어주면 됌
dst : 출력 영상, src와 같은 크기, 같은 타입
[미디언 필터링 예제]
src = cv2.imread('noise.bmp', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
sys.exit()
dst = cv2.medianBlur(src, 3)
cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
원본영상
미디언 필터 적용 (잡음은 제거 되나, 영상의 화질이 낮아질 수 있음)
→ 영상 잡음 제거, 양방향 필터 - cv2.bilateralFIlter
가우시안 잡음 제거에는 가우시안 필터가 효과적입니다.
이처럼 잡음이 있는 지글지글한 부분을 가우시안 필터로 완만하게 수정할 수 있습니다.
하지만 가우시안 블러를 심하게 적용하면 영상에 있는 엣지 부분에 훼손이 생깁니다.
이 단점을 극복하기 위해 양방향 필터라는 기법이 생겼습니다.
→ 양방향 필터 - Bilateral filter
가우시안 필터를 양쪽 방향으로 두번 한다고해서 이름이 붙여졌습니다.
평균 값 필터 또는 가우시안 필터는 에지 부근에서도 픽셀 값을 평탄하게 만드는 단점이 있습니다.
양방향 필터는 기준 픽셀과 이웃 픽셀과의 거리, 그리고 픽셀 값의 차이를 함께 고려하여 블러링 정도를 조절합니다.
양방향 필터 수식
수식을 보면 가우시안 필터 함수 G가 2개 있습니다.
▶ 양방향 필터의 작동 원리
양방향 필터는 에지가 아닌 부분에서만 블러링을 합니다.
평탄한 부분은 가우시안 필터르 이용하고, 엣지 부분이면 가우시안의 일부분만 가져와 필터링을 합니다.
따라서 에지를 보존할 수 있습니다.
이처럼 에지 부근 에서는 가우시안의 일부분만을 가져와 필터링을 합니다.
픽셀 값의 차이가 크면 0으로 채워넣고, 가우시안 필터의 고정점과 픽셀차이가 비슷하면 필터값을 가져옵니다.
▶ 양방향 필터링 함수 - cv2.bilaterFilter
OpenCV에서 제공하는 cv2.bilaterFIlter를 이용해서 양방향 필터링을 적용할 수 있습니다.
함수를 보면 sigma가 두개 있습니다.
sigmaColor는 엣지냐 아니냐를 판단하는 기준입니다.
sigmaColor을 100으로 주어주면 가우시안 필터를 적용하는 것과 동일합니다.
또 d는 -1을 권장합니다.
[함수 설명]
cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace, dst=None, borderType=None) -> dst
• src: 입력 영상. 8비트 또는 실수형, 1채널 또는 3채널.
• d: 필터링에 사용될 이웃 픽셀의 거리(지름), 음수(-1)를 입력하면 sigmaSpace 값에 의해 자동 결정(권장)
• sigmaColor: 색 공간에서 필터의 표준 편차
• sigmaSpace: 좌표 공간에서 필터의 표준 편차
• dst: 출력 영상. src와 같은 크기, 같은 타입.
• borderType: 가장자리 픽셀 처리 방식
[양방향 필터링 예제]
src = cv2.imread('lenna.bmp')
if src is None:
print('Image load failed!')
sys.exit()
dst = cv2.bilateralFilter(src, -1, 10, 5)
cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
원본 영상
양방향 필터 영상
결과 영상을 보면 머리부분의 에지가 훼손되지 않았습니다.
가우시안 필터를 적용했었더라면 에지가 훼손되었을 것입니다.