외곽선 검출
외곽선 검출이란 객체의 외곽선 좌표를 모두 추출하는 작업이다.
바깥선 외곽선뿐 아니라 옵션을 적용함으로써 안쪽 외곽선도 검출할 수 있다.
외곽선 간의 상관관계도 알 수 있으며, 외곽선의 계층 구조도 표현할 수 있다.
외곽선 객체 하나의 표현 방법
- numpy.ndarray
- shape=(K, 1, 2) (K는 외곽선 좌표 개수)
- dtype=numpy.int32
여러 외곽선 표현 방법
- "객체 하나의 외곽선(numpy.ndarray)"을 원소로 갖는 리스트
- len(리스트) = 전체 외곽선 개수(N)
✔︎ 외곽선 검출 함수 - cv2.findContours
contours, hierarchy = cv2.findContours(
image, mode, method, contours=None, hierarchy=None, offset=None)
- image : 입력 영상. non-zero 픽셀을 객체로 간주함.
- mode : 외곽선 검출 모드. cv2.RETR_로 시작하는 상수.
- method : 외곽선 근사화 방법. cv2.CHAIN_APPROX_로 시작하는 상수.
- contours : 검출된 외곽선 좌표. numpy.ndarray로 구성된 리스트. len(contours)=전체 외곽선 개수(N).
- contours[i].shape=(K, 1, 2)
- contours[i].dtype=numpy.int32
- hierarchy : 외곽선 계층 정보.
- numpy.ndarray.shape=(1, N, 4), dtype=numpy.int32
- hierrarchy[0, i, 0] ~ hierarchy[0, i, 3]이 순서대로 next, prev, child, paraent 외곽선 인덱스를 가리킴. 해당 외곽선이 없으면 -1.
- offset : 좌표 값 이동 옵셋. 기본값은 (0, 0)
mode
- cv2.RETR_EXTERNAL
- 검정색 배경에서 만나게 되는 첫번째 흰색 객체 검출
- 위 예시에서는 0과 4가 해당
- 바깥쪽 외곽선만 검출한다.
- cv2.RETR_LIST
- 모든 외곽선을 다 찾는다.
- 순서없이 무작위로 찾음
- cv2.RETR_CCOMP
- 2단계로 만드는 계층구조
- 위 예시에서 6을 보면 형태를 알 수 있음 (하단 TREE와 다르게 6을 상위 단계로 본다)
- cv2.RETR_TREE
- 계층구조를 형성함
method
외곽선을 근사화하거나 단순화한다. 주로 기본값을 사용한다.
SIMPLE은 수직선, 수평선, 대각선에 대해 끝점만 저장한다.
✔︎ 외곽선 그리기 함수 - cv2.drawContours
image = cv2.drawContours(image, contours, contourIdx, color, thickness=None,
lineType=None, hierarchy=None, maxLevel=None, offset=None)
- image : 입출력 영상
- contours : (cv2.findContours() 함수로 구현) 외곽선 좌표 정보
- contourIdx : 외곽선 인덱스. 음수(-1)를 지정하면 모든 외곽선을 그린다.
- color : 외곽선 색상
- thickness : 외곽선 두께. thickness < 0이면 내부를 채운다.
- lineType : LINE_4, LINE_8, LINE_AA 중 하나 지정
- hierarchy : 외곽선 계층 정보
- maxLevel : 그리기를 수행할 최대 외곽선 레벨. maxLevel=0이면 contourIdx로 지정된 외곽선만 그린다.
💬 계층 정보를 사용하는 외곽선 검출 예제
dimport sys
import random
import numpy as np
import cv2
src = cv2.imread('contours.bmp', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
sys.exit()
contours, hier = cv2.findContours(src, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
dst = cv2.cvtColor(src, cv2.COLOR_GRAY2BGR)
idx = 0
while idx >= 0:
c = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
cv2.drawContours(dst, contours, idx, c, 2, cv2.LINE_8, hier)
idx = hier[0, idx, 0]
cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
💬 계층 정보를 사용하지 않는 외곽선 검출 예제
import sys
import random
import numpy as np
import cv2
src = cv2.imread('milkdrop.bmp', cv2.IMREAD_GRAYSCALE)
_, src_bin = cv2.threshold(src, 0, 255, cv2.THRESH_OTSU)
contours, _ = cv2.findContours(src_bin, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
h, w = src.shape[:2]
dst = np.zeros((h, w, 3), np.uint8)
for i in range(len(contours)):
c = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
cv2.drawContours(dst, contours, i, c, 1, cv2.LINE_AA)
cv2.imshow('src', src)
cv2.imshow('src_bin', src_bin)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
'OpenCV' 카테고리의 다른 글
[OpenCV with Python] 영상 분할과 객체 검출 : 그랩컷 - cv2.grabCut (0) | 2022.02.04 |
---|---|
[OpenCV with Python] 이진 영상 처리 : 다양한 외곽선 함수 (0) | 2022.02.04 |
[OpenCV with Python] 이진 영상 처리 : 레이블링 (0) | 2022.02.04 |
[OpenCV with Python] 이진 영상 처리 : 모폴로지(Morphology) - 열기와 닫기 (0) | 2022.02.04 |
[OpenCV with Python] 이진 영상 처리 : 모폴로지(Morphology) - 침식과 팽창 (0) | 2022.02.04 |