본문 바로가기
AI & Data Analysis/Coding & Programming

[OpenCV] Filtering

by doraemin_dev 2025. 1. 22.

최댓값/최솟값 필터링

입력 영상의 해당 화소(중심 화소)에서 마스크로 씌워진 영역의 입력 화소들을 가져와서 그 중에 최댓값/최솟값을 출력 화소로 결정하는 방법
 
최댓값 필터링

  • 가장 큰 값인 밝은 색들로 출력 화소가 구성
  • 돌출되는 어두운 값이 제거 전체적으로 밝은 영상이 됨

최솟값 필터링

  • 가장 작은 값들인 어두운 색들로 출력 화소가 구성
  • 돌출되는 밝은 값들이 제거되며, 전체적으로 어두운 영상 됨

[실습]

import numpy as np, cv2

def minmax_filter(image, ksize, mode):
    rows, cols = image.shape[:2]
    dst = np.zeros((rows,cols), np.uint8)
    center = ksize//2
    for i in range(center, rows - center):
        for j in range(center, cols - center):
            # 마스크 영역 형렬 처리 방식
            y1, y2 = i - center, i+center+1
            x1, x2 = j - center, j+center+1
            mask = image[y1:y2, x1:x2]
            dst[i,j] = cv2.minMaxLoc(mask)[mode]
    return dst

image = cv2.imread("chap07/images/min_max.jpg", cv2.IMREAD_GRAYSCALE)
if image is None: raise Exception("영상파일 읽기 오류")
    
minfilter_img = minmax_filter(image, 3, 0) # 3*3 마스크 최솟값 필터링
maxfilter_img = minmax_filter(image, 3, 1)

cv2.imshow("image", image)
cv2.imshow("minfilter_img", minfilter_img)
cv2.imshow("maxfilter_img", maxfilter_img)
cv2.waitKey(0)

평균값 필터링

마스크 영역 입력 화소들의 평균을 구하여 출력 화소로 지정하는 방법
 
OpenCV에서 회선 수행시 경계 설정 방법 cv::filter2D(), cv::blur(), cv::boxFilter(), cv::sepFilter2D() 등의 함수에서 적용

[실습]

import numpy as np, cv2

image = cv2.imread("chap07/images/filter_avg.jpg", cv2.IMREAD_GRAYSCALE)
if image is None: raise Exception("영상파일 읽기 오류")

  
blur_img = cv2.blur(image, (5, 5), borderType=cv2.BORDER_CONSTANT) # OpenCV의 블러링 함수
box_img = cv2.boxFilter(image, ddepth=-1, ksize=(5, 5)) # OpenCV의 박스 필터 함수


cv2.imshow("image", image),
cv2.imshow("blur_img", blur_img)
cv2.imshow("box_img", box_img)
cv2.waitKey(0)

미디언 필터링

마스크 범위 원소 중 중간값 취하여 출력 화소로 결정하는 방식

  • 마스크 범위 내에 있는 화소 값 정렬 필요
  • 임펄스 잡음, 소금-후추 잡음 제거 (흰색-검은색 잡음 제거)

[실습] 이미지에 **Salt-and-Pepper 노이즈(소금-후추 노이즈)**를 추가하고, **미디언 필터(median filter)**를 사용하여 노이즈를 제거하는 예제

import numpy as np, cv2


def salt_pepper_noise(img, n):
    h, w = img.shape[:2]
    x, y = np.random.randint(0, w, n), np.random.randint(0, h, n)
    noise = img.copy()
    for (x,y) in zip(x,y):
        noise[y, x] = 0 if np.random.rand() < 0.5 else 255
    return noise

image = cv2.imread("chap07/images/median2.jpg", cv2.IMREAD_GRAYSCALE)
if image is None: raise Exception("영상파일 읽기 오류")
    
noise = salt_pepper_noise(image, 500)
med_img2 = cv2.medianBlur(noise, 3) # OpenCV 제공 함수


cv2.imwrite('chap07/images/noise.jpg', noise)

cv2.imshow("image", image),
cv2.imshow("noise", noise),
cv2.imshow("median - OpenCV", med_img2)
cv2.waitKey(0)

[연습문제] 캐니 에지 알고리즘에서 이중 임계값을 트랙바로 만들어서 두 개의 임계값을 조절하여 에지를 검출하도록 프로그램을 작성하시오.

import cv2
import numpy as np

# 트랙바 콜백 함수
def on_trackbar(val):
    # 트랙바에서 임계값 읽기
    low_threshold = cv2.getTrackbarPos('Low Threshold', 'Canny Edge Detection')
    high_threshold = cv2.getTrackbarPos('High Threshold', 'Canny Edge Detection')

    # 캐니 에지 검출 수행
    edges = cv2.Canny(img_gray, low_threshold, high_threshold)

    # 에지 결과 출력
    cv2.imshow('Canny Edge Detection', edges)

# 이미지 읽기
image_path = 'chap07/images/canny.jpg'  # 샘플 이미지 경로
img = cv2.imread(image_path)
if img is None:
    raise Exception("이미지를 읽을 수 없습니다.")

# 그레이스케일 변환
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 윈도우 생성
cv2.namedWindow('Canny Edge Detection')

# 트랙바 생성
cv2.createTrackbar('Low Threshold', 'Canny Edge Detection', 50, 255, on_trackbar)
cv2.createTrackbar('High Threshold', 'Canny Edge Detection', 150, 255, on_trackbar)

# 초기값으로 캐니 에지 검출 수행
on_trackbar(0)

# 키 입력 대기 및 종료
cv2.waitKey(0)
cv2.destroyAllWindows()