[OpenCV] 필터링

메르센고수·2023년 12월 26일
0

OpenCV

목록 보기
4/9


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

여러가지 필터링 기법이 있고, 크게 두 가지로 나눌 수 있다.
1. 주파수 공간에서의 필터링

2. 공간적 필터링

  • 영상의 픽셀 값을 직접 이용하는 필터링 방법
    : 대상 좌표의 픽셀 값과 주변 픽셀 값을 동시에 사용
  • 주로 마스크 연산을 이용한다
    : 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

1) src : 입력 영상
2) ddepth : 출력 영상 데이터 타입 (-1을 지정하면 src와 같은 타입의 dst 영상을 생성)
3) kernel : 필터 마스크 행렬. 실수형
4) anchor : 고정점 위치 (-1,-1)이면 필터 중앙을 고정점으로 사용
5) delta : 추가적으로 더할 값
6) borderType : 가장자리 픽셀 확장 방식
7) dst : 출력 영상

블러링

평균값 필터 (Mean 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

1) src : 입력 영상
2) ksize : 평균값 필터 크기. (width, height) 형태의 튜플
3) 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()

가우시안 필터

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

가우시안 함수

가우시안 함수의 특징

2차원 가우시안 함수

  • 가우시안 필터링 함수
cv2.GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None) -> dst

1) src : 입력 영상
2) dst : 출력 영상. src와 같은 크기, 같은 타입
3) ksize : 가우시안 커널 크기. (0,0)을 지정하면 sigma 값에 의해 자동으로 결정된다.
4) sigmaX : x방향 sigma
5) sigmaY : y방향 sigma
6) 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)

: 영상의 픽셀 값에 추가되는 원치 않는 형태의 신호

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

Median Filter

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

  • 미디언 필터링 함수
cv2.medianBlur(src, ksize, dst=None) -> dst

1) src : 입력 영상. 각 채널 별로 처리됨
2) ksize : 커널 크기. 1보다 큰 홀수를 지정
3) 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

1) src : 입력 영상. 8비트 또는 실수형, 1채널 또는 3채널
2) d : 필터링에 사용될 이웃 픽셀의 거리 (지름). 음수(-1)를 입력하면 sigmaSpace 값에 의해 자동으로 결정된다.
3) sigmaColor : 색 공간에서 필터의 표준 편차
4) sigmaSpace : 좌표 공간에서 필터의 표준 편차
5) dst : 출력 영상. src와 같은 크기, 같은 타입이다.
6) 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()

사실 7강까지 들었는데 학기 중이라 바빠서 이제서야 몰아서 올리는 중이다..

profile
블로그 이전했습니다 (https://phj6724.tistory.com/)

0개의 댓글

관련 채용 정보