10장. Sobel 과 Laplacian 경계 검출
음수와 자료형
은행 통장에는 입금(+)과 출금(−)이 함께 적힙니다. 그런데 "0 원 아래는 적을 수 없는" 장부에 옮겨 적으면 출금 기록이 모두 0 원이 되어 사라집니다. 기울기도 밝아지는 경계는 +, 어두워지는 경계는 − 입니다. 0~255 만 담는 uint8 에 바로 담으면 − 값이 모두 0 이 되어 어두워지는 쪽 경계가 사라집니다.
그림의 네 단계가 기울기를 다루는 순서입니다. 먼저 소수(CV_64F)로 계산해 음수를 지키고, 그림으로 볼 때는 절댓값을 취해 모두 양수로 만든 뒤 0~255 에 담습니다. 여기서 통장의 입출금 기록이 CV_64F 의 기울기이고, "0 원 아래는 못 적는 장부"가 uint8 입니다.
가운데 그림은 결과 자료형을 uint8(cv2.CV_8U)로 받은 것입니다. 왼쪽에서 오른쪽으로 밝아지는 변(네모의 왼쪽 변, 원의 왼쪽 반)만 남고, 어두워지는 변(네모의 오른쪽 변, 원의 오른쪽 반)은 사라졌습니다. 오른쪽 그림은 CV_64F 로 받아 cv2.convertScaleAbs 로 절댓값을 취한 것으로, 양쪽 변이 모두 남았습니다.
결과 자료형 견주기
| 받는 법 | 600 인 칸 | −600 인 칸 | 쓸 곳 |
|---|---|---|---|
cv2.CV_8U (또는 -1) | 255 (넘쳐서 잘림) | 0 (음수라 잘림) | 쓰지 않는다 |
cv2.CV_64F | 600.0 | −600.0 | 계산(크기, 방향, 임계값) |
CV_64F → cv2.convertScaleAbs | 255 | 255 | 눈으로 보기, 저장 |
CV_64F → convertScaleAbs(alpha=0.25) | 150 | 150 | 255 를 넘는 값을 줄여서 보기 |
cv2.convertScaleAbs 는 칸마다 "배율(alpha)을 곱하고, 절댓값을 취하고, 0~255 로 잘라 정수로" 바꿉니다. 배율을 주지 않으면 1 이라 600 은 255 로 잘립니다. 0.25 를 주면 600 × 0.25 = 150 이 되어 잘리지 않습니다.
짧은 예시
import cv2
img = cv2.imread("ch10_shapes.png", cv2.IMREAD_GRAYSCALE)
# ddepth 로 CV_8U(uint8)를 주면 음수는 0, 255 넘는 값은 255 로 잘린다
as_u8 = cv2.Sobel(img, cv2.CV_8U, 1, 0, ksize=3)
print(int(as_u8[80, 59]), int(as_u8[80, 140])) # 결과: 255 0 → 오른쪽 변이 사라졌다
# CV_64F 로 계산한 뒤 convertScaleAbs: 절댓값을 취하고 0~255 로 담는다
gx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
shown = cv2.convertScaleAbs(gx)
print(int(shown[80, 59]), int(shown[80, 140])) # 결과: 255 255 → 양쪽 변이 모두 남았다
# alpha: 먼저 곱할 배율. 600 × 0.25 = 150
print(int(cv2.convertScaleAbs(gx, alpha=0.25)[80, 140])) # 결과: 150주의할 점
- 크기 합치기, 방향, 임계값 같은 계산은 `CV_64F` 그대로 합니다.
convertScaleAbs로 바꾼 그림은 255 에서 잘리고 부호도 잃었으므로, 보기와 저장에만 씁니다. - 5장에서 본 것처럼
cv2.convertScaleAbs는 음수를 절댓값으로 바꿉니다. 밝기 조절에서는 이것이 문제였지만, 기울기에서는 바로 이 성질이 필요합니다.