Computer Vision/opencv(python)

[45] 7) 외곽선 검출

jwjwvison 2021. 3. 23. 17:11
  • 외곽선 검출이란?
    • 객체의 외곽선 좌표를 모두 추출하는 작업. Boundary tracking. Contour tracing.
    • 바깥쪽 & 안쪽(홀) 외곽선 -> 외곽선의 계층 구조도 표현 가능

 

  • 외곽선 객체 하나의 표현 방법
    • numpy.ndarray
    • shape=(K,1,2) (K는 외곽선 좌표 개수)
    • dtype=numpy.int32

 

  • 여러 외곽선 표현 방법
    • "객체 하나의 외곽선(numpy.ndarray)"을 원소로 갖는 리스트
    • len(리스트)=전체 외곽선 개수(N)

 

  • 외곽선 검출 함수
cv2.findContours(image,mode,method,contours=None,hierarchy=None,offset=None) -> contours,hierachy

 • 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
                hierarchy[0,i ,0] ~ hierarchy[0,i,3] 이 순서대로 next, prev , child, parent
                외곽선 인덱스를 가리킴 . 해당 외곽선이 없으면 -1.
 • offset:  좌표 값 이동 옵셋 . 기본값은 (0,0)

 

 

  • 외곽선 그리기
cv2.drawContours(image,contours,contourIdx,color,thickness=None,
                 LineType=None,hirarchy=None,maxLevel=None,offset=None) -> image

 • image: 입출력 영상
 • contours:contours: (cv2.findContours() 함수로 구한) 외곽선 좌표 정보
 • contourIdx: 외곽선 인덱스 . 음수 (-1) 를 지정하면 모든 외곽선을 그린다
 • color: 외곽선 색상
 • thickness: 외곽선 두께 . thinkness < 0 이면 내부를 채운다
 • lineType : LINE_4, LINE_8, LINE_AA 중 하나 지정
 • hierarchy: 외곽선 계층 정보 .
 • maxLevel : 그리기를 수행할 최대 외곽선 레벨 . maxLevel = 0 이면 contourIdx 로
                 지정된 외곽선만 그린다 .

 

  • 계층 정보를 사용하는 외곽선 검출 예제
import 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)   
    #hier 는 외각선 계층 정보로 이것을 지우면 제일 바깥부분만 색이 칠해진다
    #그런데 findContours에서 cv2.RETR_LIST를 사용하면 계층정보가 없으므로 hier인자가 있든 없든 상관이 없다
    idx=hier[0,idx,0]        #hier[0,i,0]~hier[0,i,3]이 순서대로 next,prev,child,parent
    
cv2.imshow('src',src)
cv2.imshow('dst',dst)
cv2.waitKey()
cv2.destroyAllWindows()

 

  • 계층 정보를 사용하지 않는 외곽선 검출 예제
'''
1,2 방법 모두 알아놓는게 좋다
2번방법이 더 쉬울수도 있다.
'''


import sys
import random
import numpy as np
import cv2


src = cv2.imread('milkdrop.bmp', cv2.IMREAD_GRAYSCALE)

if src is None:
    print('Image load failed!')
    sys.exit()
_,src_bin=cv2.threshold(src,0,255,cv2.THRESH_OTSU)

contours,_=cv2.findContours(src_bin,cv2.RETR_LIST,cv2.CHAIN_APPROX_NONE)
#list 로 받았기 때문에 hier받을 필요 없음
#contours의 길이가 외각선 객체의 갯수가 된다

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()