OpenCV 강좌, 외곽선 활용한 도형 인식과 라벨링

OpenCV(Open Source Computer Vision Library)는 컴퓨터 비전 관련 작업을 용이하게 수행하기 위해 설계된 라이브러리입니다. 본 강좌에서는 OpenCV를 사용하여 이미지를 처리하고 도형을 인식하며 이를 라벨링하는 방법에 대해 다루겠습니다. 외곽선 추출 방법과 도형 인식 기술을 통해 다양한 도형을 자동으로 식별할 수 있습니다. 이 글에서는 주로 Python을 사용하여 설명하겠습니다.

목차

1. OpenCV 소개

OpenCV는 2000년에 인텔에서 처음 개발된 라이브러리로, 오늘날 데이터 분석과 머신러닝을 포함한 다양한 분야에서 널리 사용되고 있습니다. 이미지와 비디오 처리 작업을 수행하는 데 강력한 도구를 제공하여 연구 및 상용 제품에 활용되고 있습니다. OpenCV는 C++, Python, Java 등 여러 프로그래밍 언어를 지원합니다.

2. 환경 설정

OpenCV를 사용하기 위해서는 먼저 Python 환경을 설정해야 합니다. 다음은 필요한 패키지 설치 방법입니다.

pip install opencv-python
pip install opencv-python-headless
pip install numpy

설치가 완료되면, 기본적인 OpenCV 기능을 사용할 준비가 완료됩니다.

3. 기본 개념

도형 인식 및 라벨링을 설명하기 위해, 몇 가지 기본 알고리즘과 개념을 이해해야 합니다. 우리는 외곽선 추출(contour extraction), 도형의 형태(circular, rectangular), 그리고 라벨링(Labeling) 과정에 대해 다룰 것입니다.

3.1 외곽선 (Contour)

외곽선이란 2D 이미지에서 피사체를 정의하는 경계선입니다. OpenCV에서는 cv2.findContours() 함수를 통해 처리할 수 있습니다.

3.2 도형 인식

도형 인식은 특히 면적과 외곽선을 기반으로 도형을 분류하는 작업입니다. 일반적으로 원, 사각형, 다각형 등을 인식하는 데 사용됩니다.

3.3 라벨링

라벨링이란 인식된 도형에 이름을 붙이는 과정입니다. 생성된 외곽선 정보를 바탕으로 각 도형에 의해 이름 붙여지는 프로세스입니다.

4. 외곽선 추출

이제 OpenCV를 활용하여 이미지를 불러오고 외곽선을 추출하는 방법을 알아보겠습니다. 함수를 사용하여 이미지를 전처리한 후 외곽선을 찾을 수 있습니다. 예제 코드입니다.

import cv2
import numpy as np

# 이미지 읽기
image = cv2.imread('shapes.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 경계 검출을 위한 바이너리 이미지로 변환
_, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# 외곽선 찾기
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 외곽선 그리기
cv2.drawContours(image, contours, -1, (0, 255, 0), 2)

# 결과 표시
cv2.imshow('Contours', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

이 코드는 입력 이미지에서 외곽선을 검출하고 이를 녹색으로 강조하여 표시합니다. cv2.threshold() 를 사용하여 이미지를 이진화한 후, cv2.findContours()를 호출하여 외곽선을 찾습니다.

5. 도형 인식

외곽선이 추출된 후, 각 도형의 형태를 분석하여 인식할 수 있습니다. 아래 코드는 각 외곽선의 형태를 식별하고 이에 따라 도형의 이름을 출력하는 방법을 보여줍니다.

for contour in contours:
    # 외곽선의 면적
    area = cv2.contourArea(contour)

    # 작은 외곽선 무시
    if area < 100:
        continue

    # 외곽선을 근사하여 도형의 꼭짓점 수 계산
    epsilon = 0.02 * cv2.arcLength(contour, True)
    approx = cv2.approxPolyDP(contour, epsilon, True)

    # 도형 인식
    if len(approx) == 3:
        cv2.putText(image, 'Triangle', tuple(approx[0][0]), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
    elif len(approx) == 4:
        # 면적비율로 사각형인지 확인
        x, y, w, h = cv2.boundingRect(contour)
        aspectRatio = float(w) / h
        if aspectRatio >= 0.95 and aspectRatio <= 1.05:
            cv2.putText(image, 'Square', (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
        else:
            cv2.putText(image, 'Rectangle', (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
    elif len(approx) == 5:
        cv2.putText(image, 'Pentagon', tuple(approx[0][0]), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
    elif len(approx) == 6:
        cv2.putText(image, 'Hexagon', tuple(approx[0][0]), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
    else:
        cv2.putText(image, 'Circle', (int(contour[0][0][0]), int(contour[0][0][1])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)

이 코드는 각 도형을 외곽선의 꼭짓점 수와 면적 비율을 바탕으로 식별합니다. 삼각형, 사각형, 원 등의 도형을 인식하고 해당 이름을 이미지에 추가하여 표시합니다.

6. 라벨링

라벨링 작업은 인식된 도형에 대한 정보를 사용자가 이해할 수 있는 형태로 표현하는 것입니다. 우리는 각 도형의 위치와 형태를 기반으로 이름을 붙였습니다. 위의 코드에서도 이미지를 표시할 때 도형 이름을 적어줌으로써 라벨링을 수행했습니다.

7. 실제 코드 예제

전체 코드를 하나로 묶으면 다음과 같습니다. 주어진 이미지에서 도형을 인식하고 라벨링하는 전체적인 프로세스를 구현하였습니다.

import cv2
import numpy as np

# 이미지 읽기
image = cv2.imread('shapes.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 이진화
_, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

for contour in contours:
    area = cv2.contourArea(contour)
    if area < 100:
        continue
    epsilon = 0.02 * cv2.arcLength(contour, True)
    approx = cv2.approxPolyDP(contour, epsilon, True)
    
    # 도형 인식 및 라벨링
    if len(approx) == 3:
        cv2.putText(image, 'Triangle', tuple(approx[0][0]), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
    elif len(approx) == 4:
        x, y, w, h = cv2.boundingRect(contour)
        aspectRatio = float(w) / h
        if aspectRatio >= 0.95 and aspectRatio <= 1.05:
            cv2.putText(image, 'Square', (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
        else:
            cv2.putText(image, 'Rectangle', (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
    elif len(approx) == 5:
        cv2.putText(image, 'Pentagon', tuple(approx[0][0]), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
    elif len(approx) == 6:
        cv2.putText(image, 'Hexagon', tuple(approx[0][0]), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
    else:
        cv2.putText(image, 'Circle', (int(contour[0][0][0]), int(contour[0][0][1])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)

# 결과 표시
cv2.imshow('Shapes', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

8. 결론

이번 강좌에서는 OpenCV를 이용하여 외곽선을 추출하고 도형을 인식하며 라벨링하는 방법을 살펴보았습니다. OpenCV의 다양한 기능을 활용하여 더욱 복잡한 이미지 처리와 분석 작업을 수행할 수 있습니다. 앞으로 더 많은 예제와 기술을 통해 여러분의 컴퓨터 비전 지식을 확장해 나가기를 바랍니다.

자세한 내용은 OpenCV의 공식 문서 및 커뮤니티 자료를 참조하시기 바랍니다.

감사합니다.