OpenCV 비전 실무7장 · Median 과 Bilateral 필터, 필터 비교9 / 21← 이전목차다음 →MetaContents

7장. Median 과 Bilateral 필터, 필터 비교

Bilateral 의 인자와 비용

사진 앱의 "피부 보정" 막대를 끝까지 올리면 잡티는 사라지지만 얼굴이 밀랍 인형처럼 매끈해집니다. Bilateral 필터의 sigmaColor 가 그 막대와 비슷합니다. 키울수록 더 다른 밝기까지 섞어 매끈해지고, 지나치면 경계도 섞여 만화처럼 납작해집니다.

가우시안 노이즈 낀 표지판 일부와, sigmaColor 10, 40, 150 으로 Bilateral 필터를 건 결과

왼쪽이 가우시안 노이즈(표준편차 20)를 더한 그림입니다. sigmaColor 10 은 노이즈의 흔들림(20 안팎)보다 작아서 거의 섞지 않아 자글자글함이 남습니다. 40 이면 초록 바탕이 매끈해지고 글자 테두리도 또렷합니다. 150 이면 바탕은 더 매끈하지만 글자와 바탕의 차이(160 쯤)까지 섞기 시작해 테두리가 조금 무릅니다. 여기서 보정 막대가 sigmaColor 이고, 밀랍 인형 같은 얼굴이 sigmaColor 를 지나치게 키운 결과입니다.

인자를 키우면

인자작게 주면크게 주면
sigmaColor비슷한 칸만 섞어 노이즈가 남는다다른 밝기도 섞어 경계까지 흐려진다
sigmaSpace바로 옆 칸만 섞는다먼 칸까지 섞는다(d 를 0 으로 주면 커널도 커진다)
d빠르지만 덜 매끈하다매끈하지만 아주 느려진다

OpenCV 공식 문서는 두 sigma 를 같은 값으로 두면 간단하다고 하고, 10 보다 작으면 효과가 거의 없고 150 보다 크면 만화처럼 보인다고 안내합니다. d 는 실시간 처리에 5, 노이즈가 심한 사진을 따로 처리할 때 9 정도를 권합니다.

비용: 시간 재기

Bilateral 필터는 칸마다 이웃의 밝기 차이를 보고 무게를 새로 계산하므로, 같은 크기의 평균 필터나 Gaussian 필터보다 훨씬 느립니다. time.perf_counter 로 재어 봅니다.

Python
import time
import cv2

gray = cv2.imread("ch07_sign.png", cv2.IMREAD_GRAYSCALE)

def time_ms(func, repeat=20):
    """func 를 repeat 번 돌려 한 번에 걸린 평균 시간(밀리초)을 돌려준다."""
    # perf_counter: 시간을 아주 잘게 재는 시계. 시작과 끝의 차이가 걸린 초다
    start = time.perf_counter()
    for _ in range(repeat):
        func()
    return (time.perf_counter() - start) / repeat * 1000   # 초 → 밀리초(1초 = 1000밀리초)

blur_ms = time_ms(lambda: cv2.blur(gray, (5, 5)))
bil_ms = time_ms(lambda: cv2.bilateralFilter(gray, 9, 75, 75))
print(f"Bilateral 은 평균 필터의 {bil_ms / blur_ms:.0f}배 걸렸다")

걸린 시간은 컴퓨터의 성능, 그때 돌던 다른 프로그램에 따라 달라집니다. 그래서 숫자 자체보다 "몇 배 차이"로 읽습니다. 교안 PC 에서 이 그림(320×240)을 재면 Bilateral 이 평균 필터보다 열 배 넘게 걸렸고, 실습 5에서 네 필터를 함께 재면 가장 빠른 Gaussian 필터보다 서른 배 넘게 걸렸습니다. 한 번 재면 들쭉날쭉하니 여러 번 돌려 평균을 냅니다.

주의할 점

  • lambda: ... 는 "부르면 이 줄을 실행하는 작은 함수"입니다. 필터를 바로 실행하지 않고 time_ms 안에서 여러 번 부르게 하려고 씁니다.
  • 그림이 커지면 Bilateral 의 시간은 칸 수에 맞춰 늘어납니다. 사진 수천 장을 처리할 때는 몇 장으로 먼저 시간을 재어 보고 d 를 정합니다.
← 이전 절7장 · Bilateral 필터다음 절 →7장 · 필터를 견주는 방법