공간 필터링
공간 주파수
- 공간 주파수: 공간상에서 화소 밝기의 변화율
- 고주파 영역: 화소 밝기가 급변하는 영역(주로 경계)
- 저주파 영역: 화소 밝기의 변화가 거의 없거나 점진적으로 변화하는 영역(주로 배경)
src = cv.imread('temple.webp')
공간 필터링 spacial filtering
- 인접화소들의 값을 참조하여 화소의 값을 변경하는 처리
- 컨볼루션(convolution)을 이용하여 구현
- 중심 화소의 값을 인접 화소값들의 가중 합으로 대체하는 연산
- 가중치 2차원 배열: 커널(kernel), 필터(filter), 또는 마스크(mask)라고 함
평균값 필터링
- 주변 3x3 픽셀의 평균으로 채워서 흐리게(blur) 만듦
kernel = np.array([
[1/9, 1/9, 1/9],
[1/9, 1/9, 1/9],
[1/9, 1/9, 1/9]], dtype=np.float32)
dst = cv.filter2D(src, -1, kernel)
show(dst)
가우시안 블러링 Gaussian Blurring
- 이미지를 흐리게(blur) 만드는 방법
- 가우시안 함수(=통계의 정규 분포)를 이용 → 가운데는 많이, 주변은 적게 반영
- 커널 내 (예: 5x5 범위)에서만 적용
blur = cv.GaussianBlur(src, (5, 5), 0)
show(blur) - 커널을 직접 구하려면 아래 처럼
kernel = cv.getGaussianKernel(5, 0)
kernel = kernel * kernel.T
kernel = kernel / np.sum(kernel)
dst = cv.filter2D(src, -1, kernel)
수직 성분의 추출
- 왼쪽의 픽셀들과 오른쪽의 픽셀들의 차이를 구함
- 수평 방향으로 밝기가 변할 때 결과값이 커짐
- 오른쪽이 밝고 왼쪽은 어두울 때 결과값이 가장 큼
kernel = np.array([
[-1, 0, 1],
[-1, 0, 1],
[-1, 0, 1]], dtype=np.float32)
dst = cv.filter2D(src, -1, kernel)
show(dst)
수평 성분의 추출
- 위쪽의 픽셀들과 아래쪽의 픽셀들의 차이를 구함
- 수직 방향으로 밝기가 변할 때 결과값이 커짐
- 위는 밝고 아래는 어두울 때 결과값이 가장 큼
kernel = np.array([
[1, 1, 1],
[0, 0, 0],
[-1, -1, -1]], dtype=np.float32)
dst = cv.filter2D(src, -1, kernel)
show(dst)
Sharpening
- 주변 픽셀들과의 밝기 차이를 과장해서 날카롭게 만듦(blur의 반대)
- 초점이 맞지 않은 사진을 선명하게 만들 수 있지만, 노이즈도 증가
kernel = np.array([
[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1]], dtype=np.float32)
dst = cv.filter2D(src, -1, kernel)
소벨 커널 Sobel kernel
- 경계선(edge) 검출을 위한 커널
sobelx = cv.Sobel(src, cv.CV_64F, 1, 0, ksize=3) # x 방향의 경계선 검출
sobely = cv.Sobel(src, cv.CV_64F, 0, 1, ksize=3) # y 방향의 경계선 검출
sobel_magnitude = cv.magnitude(sobelx, sobely) # 두 방향의 경계선을 하나로 결합
sobel_result = cv.normalize(sobel_magnitude, None, 0, 255, cv.NORM_MINMAX, cv.CV_8U) # 정규화
show(sobel_result) # 시각화
케니 에지 검출 Canny edge detection
- 소벨 커널을 바탕으로 만든 경계선 검출 알고리즘
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY) # 그레이스케일로 변환
# Otsu의 이진화로 상한값 계산
upper, ret = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
lower = upper / 2 # 하한값은 보통 상한값의 1/2 또는 1/3 사용
blur = cv.GaussianBlur(gray, (9, 9), 0) # 가우시안 블러 적용
edges = cv.Canny(blur, upper, lower)
show(edges) # Canny 엣지 검출 결과 출력