소벨 (Sobel) filter 개념 및 적용 코드 실습

2022. 9. 1. 14:23IT/computer vision

SMALL

아래에 주어진 입력 영상에 소벨(Sobel) 필터를 적용해 보시오.

제로 패딩을 적용해서 필터링 된 결과 값을 작성하시오

  • 영상에서 경계선을 검출하는 방법은 영상의 1차 미분 값을 이용하는 방법이 대표적이다.
    • 미분 : 함수의 변화량 (보통 y값을 고정한 상태에서 x값의 변화에 따른 함수의 변화량을 보여줌)
    • 영상에서 경계선을 검출하기 위해서는 영상을 미분한 후, 미분 값이 특정 임계값 보다 큰 부분을 찾으면 된다.
    • 영상의 경계선(edge)를 검출하기 위해서는 다양한 경계선 검출 마스크가 존재한다.
    • 소벨 마스크는 영상에서 윤곽선을 검출하는 데 자주 쓰이는 마스크이며, 모든 방향의 윤곽선, 즉 엣지를 추출할 수 있다. 엣지를 추출할 때, 수직 마스크와 수평 마스크를 적용하여 엣지를 추출하는 과정을 거친다.
      • 수평이나 수직의 단일 방향 에지를 검출하고자 할 때가 종종 있다. 이 경우에 두 개의 마스크를 같이 적용하지 않고, 하나의 마스크만 적용한 것이다.

소벨 필터 적용 필터링 결과 영상

 

소벨 에지 검출

import numpy as np
import cv2
# 회선 수행 함수 - 행렬 처리 방식(속도 면에서 유리)
def filter(image, mask):
    rows, cols = image.shape[:2]
    dst = np.zeros((rows, cols), np.float32) # 회선 결과 저장 행렬
    ycenter, xcenter = mask.shape[1]//2, mask.shape[0]//2 # 마스크 중심 좌표
    for i in range(ycenter, rows-ycenter): # 입력 행렬 반복 순회
        for j in range(xcenter, cols-xcenter):
            y1, y2 = i - ycenter, i + ycenter + 1 # 관심 영역 높이 범위
            x1, x2 = j - xcenter, j + xcenter + 1 # 관심 영역 너비 범위
            roi = image[y1:y2, x1:x2].astype('float32') # 관심 영역 형변환
            tmp = cv2.multiply(roi, mask) # 회선 적용- 원소간 곱셈
            dst[i, j] = cv2.sumElems(tmp)[0] # 출력 화소 저장
    return dst # 자료형 변환하여 반환

def diffierential(image, data1, data2):
    mask1 = np.array(data1, np.float32).reshape(3,3)
    mask2 = np.array(data2, np.float32).reshape(3,3)
    dst1 = filter(image, mask1)
    dst2 = filter(image, mask2)
    dst = cv2.magnitude(dst1, dst2) # 두 행렬 크기 계산
    dst = cv2.convertScaleAbs(dst) # 절댓값 및 형변환
    dst1 = cv2.convertScaleAbs(dst1)
    dst2 = cv2.convertScaleAbs(dst2)
    return dst, dst1, dst2

image = cv2.imread("edge.jpg", cv2.IMREAD_GRAYSCALE)

## 수직 소벨 마스크
data1 = [-1, 0, 1, -2, 0, 2, -1, 0, 1]

## 수평 소벨 마스크
data2 = [-1, -2, -1, 0, 0, 0, 1, 2, 1]

dst, dst1, dst2 = diffierential(image, data1, data2) # 두 방향 회선 및 크기(에지 강도) 계산
## OpenCV 제공 소벨 에지 계산
dst3 = cv2.Sobel(np.float32(image), cv2.CV_32F, 1, 0, 3) # x 방향 미분 - 수직 마스크
dst4 = cv2.Sobel(np.float32(image), cv2.CV_32F, 0, 1, 3) # y 방향 미분 - 수평 마스크
dst3 = cv2.convertScaleAbs(dst3) # 절댓값 및 uint8(CV_8U) 형변환
dst4 = cv2.convertScaleAbs(dst4)

cv2.imshow("dst1- vertical_mask", dst1)
cv2.imshow("dst2- horizontal_mask", dst2)
cv2.imshow("dst3- vertical_OpenCV", dst3)
cv2.imshow("dst4- horizontal_OpenCV", dst4)
cv2.waitKey(0)

소벨 엣지 검출 코드 실습 결과

LIST