OpenCV-Python

OpenCV Python 필터링 - 부드러운 영상 만들기 : blur, GaussianBlur

rkftks22 2021. 8. 22. 20:28

영상에서의 필터링이란 영상에서 필요한 정보만 통과시키고 원치 않는 정보를 걸러내는 작업을 의미합니다.

영상에서의 필터링은 2 종류로 나눌 수 있는데

1. 주파수 공간에서의 필터링

저주파 : 주변 영역과 색의 차이가 적은 부분(픽셀 값의 차이가 별로 없는 부분 : 대체로 면)
고주파 : 주변 영역과 색의 차이가 크게 나는 부분(픽셀 값의 차이가 큰 부분 : 대체로 모서리)

신호 및 시스템을 배우신 분이라면 저주파 필터, 고주파 필터에 대해 들어보셨을 텐데 

저주파 필터의 경우 저주파 성분만을 통과시키는 것으로 이미지가 흐려지게 됩니다.

고주파 필터의 경우 고주파 성분만을 통과시키는 것으로 이미지의 선 같은 부분들이 강조됩니다.

 

2. 공간적 필터링 

영상의 픽셀 값을 직접 이용하는 필터링
마스크(작은 크기의 행렬)를 통한 연산 = 커널을 통한 연산
마스크(커널)와 이미지 간의 컨벌루션 연산을 통하여 처리

컨벌루션 연산(합성곱 연산)에 대해선 https://wikidocs.net/64066

이곳이 간단히 컨벌루션이 무엇이다라고 간단히 이해하기는 쉬울 것 같네요

 

1) 합성곱 신경망(Convolution Neural Network)

합성곱 신경망(Convolutional Neural Network)은 이미지 처리에 탁월한 성능을 보이는 신경망입니다. 이 책의 주제는 이미지 처리가 아니라 자연어 처리이기 ...

wikidocs.net


cv2.filter2D(src, ddepth, kernel [, dst [, anchor [, delta [, borderType]]]]) [] : 생략 가능

import cv2
import numpy as np

img = cv2.imread("imgs/Lenna.png") 
img2 = cv2.resize(img, dsize=(0, 0), fx=2, fy=2)  # 이미지 확대

kernel = np.ones((5, 5), dtype=np.float64) / 25.  # 5*5 커널 생성

kernel2 = np.ones((10, 10), dtype=np.float64) / 100.  # 5*5 커널 생성

filter_img = cv2.filter2D(img2, -1, kernel)
filter_img2 = cv2.filter2D(img2, -1, kernel2)

cv2.imshow("Lenna", img2)
cv2.imshow("filter_img", filter_img)
cv2.imshow("filter_img2", filter_img2)

cv2.waitKey() 
cv2.destroyAllWindows()

좌 : 원본 / 중 : 5*5 커널 사용 / 우 : 10*10 커널 사용

 

src : 입력 영상 

ddepth : 출력 영상 데이터 타입(-1 입력 시 입력 영상과 동일한 데이터 출력 영상 생성)

  • 입력 : CV_8U -> -1/CV_16S/CV_32F/CV_64F
  • 입력 : CV_16U, CV_16S -> -1/CV_32F/CV_64F
  • 입력 : CV_32F -> -1/CV_32F/CV_64F
  • 입력 : CV_64F -> -1/CV_64F

kernel : 필터 마스크 행렬(실수형) -> 커널의 총합: 1

           커널 사이즈가 클수록 효과가 큽니다.

kernel = np.ones((5, 5), dtype=np.float64) / 25.

 

0.04 * 25 = 1 / 0.01 * 100 = 1

anchor : 고정점 위치, (-1, -1)이면 필터 중앙을 고정점으로 사용

delta : 추가적으로 더할 값

borderType : 가장자리 픽셀 확장 방식


cv2.blur(src, ksize [, dst [, anchor [, borderType]]]) []: 생략 가능

blur : 평균값 필터(영상의 특정 좌표값을 주변 픽셀 값들의 산술 평균으로 설정)

import cv2

img = cv2.imread("imgs/Lenna.png")  
img2 = cv2.resize(img, dsize=(0, 0), fx=2, fy=2)  # 이미지 확대

filter_img = cv2.blur(img2, (5, 5)) # 5*5 커널 생성
filter_img2 = cv2.blur(img2, (10, 10)) # 10*10 커널 생성

cv2.imshow("Lenna", img2)
cv2.imshow("filter_img", filter_img)
cv2.imshow("filter_img2", filter_img2)

cv2.waitKey()
cv2.destroyAllWindows()

좌 : 원본 / 중 : 5*5 커널 사용 / 우 : 10*10 커널 사용

src : 입력 영상 

ksize : 커널 사이즈(width, height) 형태(위와 달리 커널 크기에 맞게 자동으로 나눠줍니다.)

dst : 결과 영상

anchor : 고정점 위치, (-1, -1)이면 필터 중앙을 고정점으로 사용

borderType : 가장자리 픽셀 확장 방식

 

filter2D보다는 blur 사용을 추천드립니다.

일반적인 필터를 사용할 경우(np.zeros 사용 후 같은 값으로 나눗셈) blur와 같고
다른 특별한 커널을 생성해서 하고 싶은 경우(커널을 만드는 것도 어렵기도 하고..) blur 외에도 커널의 가중치가 다양하게 반영되어있는 blur가 많기 때문에 필요한 것을 찾아 사용하시는 게 편리할 것 같습니다.

cv2.GaussianBlur(src, ksize, sigmaX [, dst [, sigmaY [, borderType]]]) []: 생략 가능

GaussianBlur : 가우시안 필터(가까이 있는 픽셀에 가중치를 매겨 가중치 평균값으로 대치)

                     가우시안 함수를 기반으로 한 필터입니다. 궁금하신 분은 찾아보시는 것도 좋겠네요

import cv2

img = cv2.imread("imgs/Lenna.png")
img2 = cv2.resize(img, dsize=(0, 0), fx=2, fy=2)  # 이미지 확대

filter_img = cv2.GaussianBlur(img2, (0, 0), 1)
filter_img2 = cv2.GaussianBlur(img2, (0, 0), 3)

cv2.imshow("Lenna", img2)
cv2.imshow("filter_img", filter_img)
cv2.imshow("filter_img2", filter_img2)

cv2.waitKey()
cv2.destroyAllWindows()

좌 : 원본 / 중 : 5*5 커널 사용 / 우 : 10*10 커널 사용

src : 입력 영상

ksize : 가우시안 커널 크기, (0,0)으로 설정(추천) 시 sigma 값에 의해 자동 결정

(0,0)으로 주는 이유는 sigmaX를 설정했을 때 ksize가 sigma 값에 맞게 알아서 조정됩니다.
커널 사이즈를 따로 지정해줄 경우 온전한 가우시안 필터 효과를 받지 못할 수 있습니다.
만약에 설정해서 확인해 보고 싶으신 경우 값은 홀수로 주셔야 합니다.
2*2(짝수)로 만들 경우 중앙점도 애매하고 가깝고 먼 픽셀 구분도 안돼서 에러가 발생합니다. 

sigmaX : x방향 sigma

            값을 설정해주었을 때 마스크 크기가 6 * sigma + 1 또는 8 * sigma +1 정도로 설정된다고 하네요.

sigma =1일 때 8 * sigma + 1

1~4 정도가 적당한 것 같습니다. 크게 하면 물체의 형태도 제대로 알아보기 힘들어요.

dst : 출력 영상

sigmaY : y방향 sigma, 0이면 sigmaX와 같게 설정

borderType : 가장자리 픽셀 확장 방식