본문 바로가기

etc/FastCampus 챌린지

[패스트캠퍼스 수강 후기] 컴퓨터비전인강 100% 환급 챌린지 48 회차

728x90
반응형

황선규 박사님의 'OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝' 을 공부하면서 정리해 보았습니다.

OpenCV 명령어 출처 : docs.opencv.org/4.3.0/dd/d49/tutorial_py_contour_features.html

 

예제 코드 출처 :  황선규 박사님 github홈페이지

 

『OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝』

예제 소스 코드는 아래 링크를 참고하세요

sunkyoo.github.io

다양한 외곽선 함수

 외곽선 함수에 대한 자세한 정보는 docs.opencv.org/4.3.0/dd/d49/tutorial_py_contour_features.html 에서 확인하실 수 있습니다.

 

(1) cv.arcLength()

 외곽선 길이를 반환합니다.

 

(2) cv2.contourArea()

 외곽선이 감싸는 영역의 면적을 반환합니다.

 

(3) cv2.boundingRect()

 주어진 점을 감싸는 최소 크기 사각형(바운딩 박스)를 반환합니다.

 

(4) cv2.minEnclosingCircle()

 주어진 점을 감싸는 최소 크기 원을 반환합니다.

 

 

(5) cv2.minAreaRect()

 주어진 점을 감싸는 최소 크기 회전된 사각형을 반환합니다.

 

 

(6) cv2.minEnclosingTriangle()

 주어진 점을 감싸는 최소 크기 삼각형을 반환합니다.

 

(7) cv2.approxPolyDP()

 외곽선을 근사화(단순화) 합니다.

 

 

(8) cv2.fitEllipse()

 주어진 점에 적합한 타원을 반환합니다.

 

 

(9) cv2.fitLine()

 주어진 점에 적합한 직선을 반환합니다.

 

 

(10) cv2.isContourConvex()

 컨벡스 인지를 검사합니다.

 

(11) cv2.convexHull()

 주어진 점으로부터 컨벡스 헐을 반환합니다.

 

 

(12) cv2.convexityDefects()

 주어진 점과 컨벡스 헐로부터 컨벡스 디펙트를 반환합니다.

 

 

자주 쓰이는 외곽선 함수 설명

1. 외곽선 길이 구하기 - cv2.arcLength()

cv2.arcLength(curve, closed) -> retval

• curve: 외곽선 좌표. numpy.ndarray. shape=(K, 1, 2)
• closed: True이면 폐곡선으로 간주
• retval: 외곽선 길이

2. 면적 구하기 - cv2.contourArea()

cv2.contourArea(contour, oriented=None) -> retval

• contour: 외곽선 좌표. numpy.ndarray. shape=(K, 1, 2)
• oriented: True이면 외곽선 진행 방향에 따라 부호 있는 면적을 반환. 기본값은 False.
• retval: 외곽선으로 구성된 영역의 면적

3. 바운딩 박스(외곽선을 외접하여 둘러싸는 가장 작은 사각형) 구하기 - cv2.boundingRect()

cv2.boundingRect(array) -> retval

• array: 외곽선 좌표. numpy.ndarray. shape=(K, 1, 2)
• retval: 사각형 정보. (x, y, w, h) 튜플.

4. 바운딩 서클(외곽선을 외접하여 둘러싸는 가장 작은 원) 구하기

cv2.minEnclosingCircle(points) -> center, radius

• points: 외곽선 좌표. numpy.ndarray. shape=(K, 1, 2)
• center: 바운딩 서클 중심 좌표. (x, y) 튜플.
• radius: 바운딩 서클 반지름. 실수

5. 외곽선 근사화 - cv2.approxPolyDP

cv2.approxPolyDP(curve, epsilon, closed, approxCurve=None) -> approxCurve

• curve: 입력 곡선 좌표. numpy.ndarray. shape=(K, 1, 2)
• epsilon: 근사화 정밀도 조절. 입력 곡선과 근사화 곡선 간의 최대 거리. e.g) cv2.arcLength(curve) * 0.02
• closed: True를 전달하면 폐곡선으로 인식
• approxCurve: 근사화된 곡선 좌표. numpy.ndarray. shape=(K', 1, 2)

더글라스-포이커 알고리즘6. Convex 검사 - cv2.isContourConvex

cv2.isContourConvex(contour) -> retval

• contour: 입력 곡선 좌표. numpy.ndarray. shape=(K, 1, 2)
• retval: 컨벡스이면 True, 아니면 False

다각형 판별 프로그램 예제

 황선규 박사님의 깃허브에 있는 다각형 판별 프로그램 입니다.

 

 원을 판별하는 방법은 도형의 넓이와 도형을 감싸고 있는 외곽선 길이의 비율을 검사합니다.

 하나의 끈으로 만든 가장 면적이 큰 도형은 원입니다.

 분모는 외곽선 길이, 분자는 도형의 넓이를 이용합니다.

 

 A/P를 구하면 미지수 r이 남게 되므로 P를 제곱하여 구합니다.

 

 

 값이 1에 가까울수록 원으로 판단합니다.

 

# 사각형을 그리는 함수
def setLabel(img, pts, label):
    # 사각형 좌표 받아오기
    (x, y, w, h) = cv2.boundingRect(pts)
    pt1 = (x, y)
    pt2 = (x + w, y + h)
    cv2.rectangle(img, pt1, pt2, (0, 0, 255), 1)
    cv2.putText(img, label, pt1, cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 255))
    
def main():
    img = cv2.imread('polygon.bmp', cv2.IMREAD_COLOR)
    
    if img is None:
        print('Image load failed!')
        return
    
    # 그레이스케일 영상으로 변환
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 이진화, INV 이유는 배경이 흰색, 객체가 어두운 영상이므로
    _, img_bin = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
    
    # 외곽선 검출, EXTERNAL로 바깥 외곽선만 도출
    contours, _ = cv2.findContours(img_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    
    # 외곽선 좌표 받아오기
    for pts in contours:
        if cv2.contourArea(pts) < 400: # 노이즈 제거, 너무 작으면 무시
            continue
        
        # 근사화
        approx = cv2.approxPolyDP(pts, cv2.arcLength(pts, True)*0.02, True)
        
        # 근사화 결과 점 갯수
        vtc = len(approx)
        
        # 3이면 삼각형
        if vtc == 3:
            setLabel(img, pts, 'TRI')
        # 4면 사각형
        elif vtc == 4:
            setLabel(img, pts, 'RECT')
        else:
            length = cv2.arcLength(pts, True)
            area = cv2.contourArea(pts)
            ratio = 4. * math.pi * area / (length * length)

            if ratio > 0.85:
                setLabel(img, pts, 'CIR')

    cv2.imshow('img', img)
    cv2.waitKey()
    cv2.destroyAllWindows()
    
if __name__ == '__main__':
    main()

 

 

728x90
반응형