영상 매체에서 선정적이거나 부정적인 의미를 담고 있는 물체를 가릴 때 흔히 사용하는 모자이크에는 어떤 원리가 들어있을까?
자세히 보면 알 수 있듯이 하나의 픽셀마다 각각 다른 색으로 보이는 것을 확인할 수 있다. 필터링도 유사한 의미를 갖고 있다.
정의를 보면, 필터링이란 영상에서 필요한 정보만 통과시키고 원하지 않는 정보는 걸러내는 작업을 의미한다.

여러가지 필터링 기법이 있고, 크게 두 가지로 나눌 수 있다.
- 주파수 공간에서의 필터링
- 공간적 필터링
- 영상의 픽셀 값을 직접 이용하는 필터링 방법
: 대상 좌표의 픽셀 값과 주변 픽셀 값을 동시에 사용 - 주로 마스크 연산을 이용한다
: Mask=kernel=window=template
마스크의 형태와 값에 따라 필터의 역할이 결정되므로 다음 4가지 작업이 중요하다.
1) 영상 부드럽게 만들기
2) 영상 날카롭게 만들기
3) edge 검출
4) 잡음 제거
- 영상의 픽셀 값을 직접 이용하는 필터링 방법


기본적인 2D 필터링
cv2.filter2D(src, ddepth, kernel, dst=None, anchor=None, delta=None,borderType=None) ->dst
- src : 입력 영상
- ddepth : 출력 영상 데이터 타입 −1을지정하면src와같은타입의dst영상을생성
- kernel : 필터 마스크 행렬. 실수형
- anchor : 고정점 위치 −1,−1이면 필터 중앙을 고정점으로 사용
- delta : 추가적으로 더할 값
- borderType : 가장자리 픽셀 확장 방식
- dst : 출력 영상
블러링
평균값 필터 MeanfilterMean filter
: 영상의 특정 좌표 값을 주변 픽셀 값들의 산술 평균으로 설정
- 픽셀들 간의 그레이스케일 값 변화가 줄어들어 날카로운 에지가 무뎌지고 영상에 있는 잡음의 영향이 사라지는 효과가 있다.

import sys
import numpy as np
import cv2
src=cv2.imread('rose.bmp',cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed')
sys.exit()
kernel=np.array([[1/9,1/9,1/9],
[1/9,1/9,1/9],
[1/9,1/9,1/9]],dtype=np.float64)
# kernel의 각 요소를 1/9로 하는 평균값 필터 적용
dst=cv2.filter2D(src,-1,kernel)
cv2.imshow('src',src)
cv2.imshow('dst',dst)
cv2.waitKey()
cv2.destroyAllWindows()

평균 값 필터링 함수
c2.blur(src, ksize, dst=None, anchor=None, brderType=None) -> dst
- src : 입력 영상
- ksize : 평균값 필터 크기. [width, height] 형태의 튜플
- dst : 결과 영상. 입력 영상과 같은 크기 & 같은 타입

import sys
import numpy as np
import cv2
src = cv2.imread('rose.bmp', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
sys.exit()
cv2.imshow('src', src)
for ksize in (3, 5, 7):
dst = cv2.blur(src, (ksize, ksize))
# ksize 만큼 blur 처리를 함
desc = 'Mean: {}x{}'.format(ksize, ksize)
cv2.putText(dst, desc, (10, 30), cv2.FONT_HERSHEY_SIMPLEX,
1.0, 255, 1, cv2.LINE_AA)
# 10,30 위치에 desc 문장을 SIMPLEX 폰트로 적음
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()

가우시안 필터
평균값 필터에 의한 블러링의 단점
- 필터링 대상 위치에서 가까이 있는 픽셀과 멀리 있는 픽셀이 모두 같은 가중치를 사용하여 평균을 계산
- 멀리 있는 픽셀의 영향을 많이 받을 수 있음

가우시안 함수

가우시안 함수의 특징

2차원 가우시안 함수

가우시안 필터링 함수
cv2.GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None) -> dst
- src : 입력 영상
- dst : 출력 영상. src와 같은 크기, 같은 타입
- ksize : 가우시안 커널 크기. [0,0]을 지정하면 sigma 값에 의해 자동으로 결정된다.
- sigmaX : x방향 sigma
- sigmaY : y방향 sigma
- borderType : 가장자리 픽셀 확장 방식
stc=cv2.imread('rose.bmp', cv2.IMREAD_GRAYSCALE)
cv2.imshow('src', src)
for sigma in range(1,6):
dst=cv2.GaussianBlur(src, (0,0), sigma)
desc='sigma={}'.format(sigma)
cv2.putText(dst, desc, (10,30), cv2.FONT_HERSHET_SIMPLEX, 1.0, 255, 1, cv2.LINE_AA)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()

: 부드러워진 영상을 이용하여 날카로운 영상을 생성

import sys
import numpy as np
import cv2
src = cv2.imread('rose.bmp', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
sys.exit()
blr = cv2.GaussianBlur(src, (0, 0), 2) # sigma를 2로 고정
dst = np.clip(2.0*src - blr, 0, 255).astype(np.uint8)
# clipping해서 일정 값을 넘지 못하도록 함
cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()

샤프닝 : 언샤프 마스크 필터
- 샤프닝 정도를 조절할 수 있도록 수식을 변경


src=cv2.imread('rose.bmp')
src_ycrcb=cv2.cvtColor(src, cv2.COLOR_BGR2YCrCb)
# BGR 형식의 이미지를 YCrCb 형식으로 변환
src_f=src_ycrcb[:,:,0].astype(np.float32)
blr=cv2.GaussianBlur(src_f,(0,0),2.0)
src_ycrcb[:,:,0]=np.clip(2.* src_f-blr,0,255).astype(np.uint8)
dst=cv2.cvtColor(src_ycrcb, cv2.COLOR_YCrCb2BGR)

잡음 제거
미디언 필터
잡음 Noise
: 영상의 픽셀 값에 추가되는 원치 않는 형태의 신호

종류
- Gaussian Noise
- Salt & Pepper
: impulse noise라고도 불리며 이미지에서 밝고 어두운 픽셀이 무작위로 발생하는 것으로 나타나는 이미지 노이즈이다. 소금이 매우 높은 강도의 노이즈, 후추가 매우 낮은 강도의 노이즈인데 아마도 입자의 굵기로 강도의 차이를 나타낸 것 같다.

Median Filter
: 주변 픽셀들의 값을 정렬하여 그 중앙 값으로 픽셀 값을 대체
→ 소금-후추 잡음 제거에 효과적 [소금-후추 잡음은 약간 극단적인 성격이 존재하기 때문에]

미디언 필터링 함수
cv2.medianBlur(src, ksize, dst=None) -> dst
- src : 입력 영상. 각 채널 별로 처리됨
- ksize : 커널 크기. 1보다 큰 홀수를 지정
- dst : 출력 영상. src와 같은 크기, 같은 타입
import sys
import numpy as np
import cv2
src = cv2.imread('noise.bmp', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
sys.exit()
dst = cv2.medianBlur(src, 3)
# 커널 크기 3의 blurring을 medianblurring으로 처리
cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()

양방향 필터
- 소금-후추 잡음 제거는 median filter가 효과적이고 가우시안 잡음 제거에는 Gaussian filter가 효과적이다.

- edge-preserving noise removal filter 중 하나
- 평균값 필터 또는 가우시안 필터는 edge 부근에서도 픽셀 값을 평탄하게 만드는 단점이 있는 반면, 양방향 필터는 edge를 보존하는 기법이기 때문에 edge 부근의 필터 값을 유지한다.
- 기준 픽셀과 이웃 픽셀과의 거리, 픽셀 값의 차이를 함께 고려하여 블러링 강도를 조절한다.


cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace, dst=None, borderType=None) -> dst
- src : 입력 영상. 8비트 또는 실수형, 1채널 또는 3채널
- d : 필터링에 사용될 이웃 픽셀의 거리 [지름]. 음수[-1]를 입력하면 sigmaSpace 값에 의해 자동으로 결정된다.
- sigmaColor : 색 공간에서 필터의 표준 편차
- sigmaSpace : 좌표 공간에서 필터의 표준 편차
- dst : 출력 영상. src와 같은 크기, 같은 타입이다.
- borderType : 가장자리 픽셀 처리 방식
import sys
import numpy as np
import cv2
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()

실습
카툰 필터 카메라
: 카메라 입력 영상에 실시간으로 필터링을 적용해서 만화풍의 그림처럼 보이게 하는 기능
- 구현할 기능
1) 카툰 필터
2) 스케치 필터
3) 스페이스바를 누를 때마다 모드 변경
# 카툰 필터 카메라
import sys
import numpy as np
import cv2
def cartoon_filter(img):
h, w = img.shape[:2]
img2 = cv2.resize(img, (w//2, h//2))
blr = cv2.bilateralFilter(img2, -1, 20, 7)
edge = 255 - cv2.Canny(img2, 80, 120)
edge = cv2.cvtColor(edge, cv2.COLOR_GRAY2BGR)
dst = cv2.bitwise_and(blr, edge)
dst = cv2.resize(dst, (w, h), interpolation=cv2.INTER_NEAREST)
return dst
def pencil_sketch(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blr = cv2.GaussianBlur(gray, (0, 0), 3)
dst = cv2.divide(gray, blr, scale=255)
return dst
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print('video open failed!')
sys.exit()
cam_mode = 0
while True:
ret, frame = cap.read()
if not ret:
break
if cam_mode == 1:
frame = cartoon_filter(frame)
elif cam_mode == 2:
frame = pencil_sketch(frame)
frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)
cv2.imshow('frame', frame)
key = cv2.waitKey(1)
if key == 27:
break
elif key == ord(' '):
cam_mode += 1
if cam_mode == 3:
cam_mode = 0
cap.release()
cv2.destroyAllWindows()
- Chapter4 끝! -

'OpenCV' 카테고리의 다른 글
[OpenCV] 영상의 특징 추출 0 | 2025.04.04 |
---|---|
[OpenCV] 기하학적 변환 0 | 2025.04.04 |
[OpenCV] 기본 영상 처리 0 | 2025.04.04 |
[OpenCV] OpenCV 기초 0 | 2025.04.04 |
[OpenCV] 컴퓨터비전의 시작 2 | 2025.04.04 |