728x90
외곽선 검출
외곽선을 검출할 때는 findContours 를 사용하고 그릴때는 drawContours 를 사용합니다.
검은색 배경에 흰색 객체를 식별하여 검출합니다.
cv2.findContours(src, mode, method, contours=None, hierarchy=None, offset=None) -> contours, hierarchy
- src: 입력 이미지
- mode: 외곽선 검출 방식
- cv2.RETR_EXTERNAL
- 가장 바깥쪽의 영역만 추출
- 계층 정보 없음
- cv2.RETR_LIST
- 모든 영역을 추출
- 계층 정보 없음
- cv2.RETR_TREE
- 바깥 영역부터 계층적 구조를 추출
- method: 외곽선 근사 방법
- contours:
- 외곽선 좌표(np.ndarray)
- len(contours) : 외곽선 개수
- hierarchy
- 외곽선 계층 정보를 담고 있는 (1, n, 4) shape 의 list(n은 contour 개수)
- next, previous, child, parent 를 의미
- offset: 좌표 이동 offset(default=(0, 0)
cv2.drawContours(src, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None) -> src
- src: 입력 이미지
- contours: cv2.findContours 에서 찾은 외곽선 좌표
- contourIdx: 외곽선 인덱스(-1 이면 모든 외곽선을 그림)
- color: 외곽선 색상
- thickness: 외곽선 두께(음수이면 내부를 채움)
- lineType: LINE_$, LINE_8, LINE_AA 중 선택
- hierarchy: 외곽선 계층 정보
- maxLevel: 그리기를 수행할 때 최대 외곽선 레벨
cv2.RETR_EXTERNAL
계층정보는 없으며, 외부 영역만을 추출합니다.
import os
import cv2
import numpy as np
path = os.path.join('img', 'shape.png')
img = cv2.imread(path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
contours, hierarchy = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
img = cv2.drawContours(img, [contour], -1, (0, 0, 255), 2)
cv2.imshow('img', img)
cv2.imshow('gray', gray)
cv2.waitKey()
cv2.destroyAllWindows()
cv2.RETR_TREE
외부 영역부터 계층적 구조를 추출합니다.
import os
import cv2
path = os.path.join('img', 'shape2.png')
src = cv2.imread(path)
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
tree = src.copy()
contours, hierarchy = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
src = cv2.drawContours(src, [contour], -1, (0, 255, 0), 2)
contours, hierarchy = cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
for contour in contours:
tree = cv2.drawContours(tree, [contour], -1, (0, 255, 0), 2)
cv2.imshow('ext', src)
cv2.imshow('tree', tree)
cv2.waitKey()
cv2.destroyAllWindows()
cv.RETR_EXTERNAL 과는 달리 cv.RETR_TREE 는 안쪽 영역까지 검출하는 것을 볼 수 있습니다.
hierarchy 를 사용한 코드입니다.
# contour 예제
import os
import cv2
import numpy as np
path = os.path.join('img', 'shape.png')
img = cv2.imread(path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
contours, hierarchy = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
idx = 0
while idx >= 0:
cv2.drawContours(img, contours, idx, (255, 0, 0), 2, cv2.LINE_8, hierarchy)
idx = hierarchy[0, idx, 0]
cv2.imshow('img', img)
cv2.imshow('gray', gray)
cv2.waitKey()
cv2.destroyAllWindows()
검출된 hierarchy 배열을 보면
하나의 행은 [next, previous, child, parents] 의미를 가집니다.
contours, hierarchy = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
print(hierarchy)
[[[ 1 -1 -1 -1]
[ 2 0 -1 -1]
[ 3 1 -1 -1]
[ 4 2 -1 -1]
[ 5 3 -1 -1]
[ 6 4 -1 -1]
[-1 5 -1 -1]]]
검출된 요소를 선택하여 비교할 수 있게 해보았습니다. (쓰잘데기)
import os
import cv2
path = os.path.join('img', 'shape.png')
src = cv2.imread(path)
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
contours, hierarchy = cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
print(hierarchy)
idx = 0
while True:
sel = input(f'items 0 ~ {len(hierarchy[0])-1} >> (quit: q) ')
if sel == 'q':
break
if sel.isdigit() and int(sel) < len(hierarchy[0]):
print(hierarchy[0][int(sel)])
idx = hierarchy[0, int(sel), 0]
# idx = hierarchy[0][sel][0]
dst = src.copy()
cv2.drawContours(dst, contours, idx, (255, 0, 0), 2, cv2.LINE_8, hierarchy)
cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey(2000)
cv2.destroyAllWindows()
'OpenCV' 카테고리의 다른 글
파이썬 OpenCV 도형 검출하기 (4) | 2020.08.05 |
---|---|
파이썬 OpenCV 라벨링(Labeling) (0) | 2020.07.26 |
파이썬 OpenCV 이미지 이진화(Binarization) : threshold otsu adaptiveThreshold (0) | 2020.07.26 |
파이썬 OpenCV 모폴로지(Morphology) -2 : Gradient / Tophat / Blackhat (0) | 2020.07.26 |
파이썬 OpenCV 모폴로지(Morphology) -1: 침식(erode) / 팽창(dilate) /Opening & Closing (0) | 2020.07.26 |