OpenCV 비전 실무10장 · Sobel 과 Laplacian 경계 검출8 / 21← 이전목차다음 →MetaContents

10장. Sobel 과 Laplacian 경계 검출

기울기의 크기와 방향

지하철역에서 동쪽으로 3블록, 북쪽으로 4블록 떨어진 식당이 있다고 해 봅시다. 블록을 따라 걸으면 7블록이지만, 하늘을 나는 새는 비스듬히 곧장 5블록만 날아갑니다. 가로 기울기와 세로 기울기도 이렇게 합칩니다. 가로 변화 3 과 세로 변화 4 는 "가장 가파른 쪽으로 5 만큼 변한다"는 뜻입니다.

가로 변화 3 과 세로 변화 4 를 두 변으로, 크기 5 를 빗변으로 하는 직각삼각형 그림

초록 화살표가 가로 기울기(gx = 3), 보라 화살표가 세로 기울기(gy = 4), 다홍 화살표가 둘을 합친 크기(5)입니다. 다홍 화살표가 가리키는 쪽이 기울기의 방향, 곧 밝기가 가장 가파르게 밝아지는 쪽입니다. 여기서 동쪽 3블록이 gx, 북쪽 4블록이 gy, 새가 날아간 거리가 크기입니다.

크기를 손으로 계산하기

피타고라스 정리는 "빗변의 제곱 = 두 변의 제곱의 합"입니다. 그래서 크기 = √(gx² + gy²) 입니다.

칸gxgygx² + gy²크기 √
손계산 예349 + 16 = 255
네모의 왼쪽 변 (세로 80, 가로 59)6000360,000 + 0 = 360,000600
네모의 왼쪽 위 모서리 (세로 40, 가로 60)450450202,500 + 202,500 = 405,000약 636.4

곧은 변에서는 한쪽 기울기가 0 이라 크기가 다른 쪽 기울기의 절댓값과 같습니다. 모서리처럼 두 방향이 함께 바뀌는 곳에서는 두 값이 합쳐져 더 커집니다.

두 가지 합치는 법

cv2.magnitude 로 피타고라스대로 합치는 법과 cv2.addWeighted 로 절반씩 더해 어림하는 법을 견준 비교 그림

왼쪽 cv2.magnitude 는 피타고라스 정리를 그대로 계산합니다. 오른쪽 cv2.addWeighted 는 두 기울기의 절댓값을 절반씩 더하는 어림값으로, 인터넷 예제에 자주 나옵니다. 어림값은 경계가 가로나 세로로 곧을 때는 실제 크기의 절반, 비스듬할 때는 그보다 크게 나와서, 같은 높이의 경계라도 방향에 따라 밝기가 달라집니다.

견줄 것cv2.magnitude(gx, gy)cv2.addWeighted(|gx|, 0.5, |gy|, 0.5, 0)
계산√(gx² + gy²)0.5 × |gx| + 0.5 × |gy|
gx 3, gy 4 일 때53.5
곧은 변 (600, 0)600300
같은 높이의 경계방향과 관계없이 같은 크기비스듬할수록 상대적으로 크다
쓸 곳크기로 임계값을 정할 때빠르게 대충 볼 때

방향

방향은 "어느 쪽으로 가장 가파르게 밝아지나"입니다. cv2.phase(gx, gy, angleInDegrees=True) 가 칸마다 각도를 0~360 도로 돌려줍니다. 그림의 세로축은 아래로 갈수록 숫자가 커지므로, 0 도는 오른쪽, 90 도는 아래쪽, 180 도는 왼쪽, 270 도는 위쪽입니다.

경계gxgy방향 (도)뜻
네모의 왼쪽 변+00오른쪽으로 갈수록 밝아진다
네모의 위 변0+90아래로 갈수록 밝아진다
네모의 오른쪽 변−0180왼쪽으로 갈수록 밝아진다

짧은 예시

Python
import cv2
import numpy as np

img = cv2.imread("ch10_shapes.png", cv2.IMREAD_GRAYSCALE)
gx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
gy = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)

# magnitude: 칸마다 √(gx² + gy²). 두 그림은 크기와 자료형이 같아야 한다
mag = cv2.magnitude(gx, gy)
print(round(float(mag[40, 60]), 1))                          # 결과: 636.4 → 모서리
print(round(float(np.sqrt(450 ** 2 + 450 ** 2)), 1))         # 결과: 636.4 → 손계산과 같다

# phase: 칸마다 방향(각도). angleInDegrees=True 면 0~360 도
ang = cv2.phase(gx, gy, angleInDegrees=True)
print([round(float(ang[80, x])) for x in (59, 140)])         # 결과: [0, 180] → 왼쪽 변, 오른쪽 변

주의할 점

  • 방향은 경계 선 자체가 아니라 경계를 가로지르는 쪽입니다. 세로로 선 변의 방향은 0 도나 180 도(가로)입니다.
  • 기울기가 0 인 고른 면에서도 cv2.phase 는 각도를 돌려주지만 뜻이 없습니다. 방향은 크기가 큰 칸에서만 읽습니다.
← 이전 절10장 · 음수와 자료형다음 절 →10장 · 커널 크기와 Scharr