OpenCV 윤곽선 검출 (cv2.findContours())
1. 윤곽선 검출이란?
윤곽선 검출은 이미지에서 객체의 경계를 찾아내는 과정입니다. 일반적으로 바이너리 이미지(흑백 이미지)에서 밝은 영역의 경계를 추출하여 분석할 때 사용됩니다. OpenCV에서는 cv2.findContours() 함수를 사용하여 윤곽선을 찾을 수 있습니다.
이 글에서는 cv2.findContours() 함수의 사용법을 자세히 살펴보고, 다양한 예제 코드와 함께 윤곽선 검출을 적용하는 방법을 설명하겠습니다.
2. cv2.findContours() 함수 소개
cv2.findContours() 함수는 바이너리 이미지에서 윤곽선을 검출하는 기능을 합니다. 함수의 기본적인 형식은 다음과 같습니다.
contours, hierarchy = cv2.findContours(image, mode, method)
매개변수 설명
image: 윤곽선을 검출할 이미지 (바이너리 이미지여야 함)mode: 윤곽선을 찾는 방법을 지정하는 인자cv2.RETR_EXTERNAL: 가장 바깥쪽 윤곽선만 검출cv2.RETR_LIST: 모든 윤곽선을 검출하되, 계층 정보는 무시cv2.RETR_CCOMP: 모든 윤곽선을 검출하고 2단계 계층으로 구분cv2.RETR_TREE: 모든 윤곽선을 검출하고, 전체 계층 구조를 유지
method: 윤곽선을 근사화하는 방법을 지정하는 인자cv2.CHAIN_APPROX_NONE: 모든 윤곽점을 저장cv2.CHAIN_APPROX_SIMPLE: 불필요한 중간점을 제거하여 메모리 사용량 감소
반환값
contours: 검출된 윤곽선 정보 (리스트 형태)hierarchy: 윤곽선의 계층 구조 정보
3. 윤곽선 검출 기본 예제
3.1. 기본적인 윤곽선 검출 코드
다음은 OpenCV를 사용하여 윤곽선을 검출하고 화면에 표시하는 코드입니다.
import cv2
import numpy as np
# 이미지 로드 및 그레이스케일 변환
image = cv2.imread('sample.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 이진화 처리
_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 윤곽선 검출
contours, _ = cv2.findContours(binary, 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()를 사용하여 윤곽선을 검출하였습니다. 마지막으로 cv2.drawContours() 함수를 사용하여 윤곽선을 초록색으로 표시하였습니다.
4. 다양한 윤곽선 검출 모드 비교
다음은 cv2.findContours()에서 사용되는 네 가지 모드(RETR_EXTERNAL, RETR_LIST, RETR_CCOMP, RETR_TREE)의 차이를 비교하는 코드입니다.
import cv2
import numpy as np
def find_and_draw_contours(mode):
image = cv2.imread('shapes.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, mode, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(image, contours, -1, (0, 255, 0), 2)
cv2.imshow(f'Mode: {mode}', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 각 모드에 대한 결과 확인
find_and_draw_contours(cv2.RETR_EXTERNAL)
find_and_draw_contours(cv2.RETR_LIST)
find_and_draw_contours(cv2.RETR_CCOMP)
find_and_draw_contours(cv2.RETR_TREE)
위 코드를 실행하면 같은 이미지에서 서로 다른 mode 값을 사용했을 때 윤곽선 검출 방식이 어떻게 달라지는지 확인할 수 있습니다.
5. 윤곽선 근사화 (cv2.CHAIN_APPROX_SIMPLE vs cv2.CHAIN_APPROX_NONE)
윤곽선 근사화 방법을 변경하면 윤곽선을 저장하는 방식이 달라집니다.
import cv2
import numpy as np
# 이미지 로드
image = cv2.imread('shapes.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# CHAIN_APPROX_NONE: 모든 점을 저장
contours_none, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# CHAIN_APPROX_SIMPLE: 불필요한 점 제거
contours_simple, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
print(f'CHAIN_APPROX_NONE: {len(contours_none[0])} points')
print(f'CHAIN_APPROX_SIMPLE: {len(contours_simple[0])} points')
위 코드에서 CHAIN_APPROX_NONE을 사용하면 모든 점을 저장하며, CHAIN_APPROX_SIMPLE을 사용하면 꼭짓점 정보만 저장하여 효율적으로 메모리를 사용할 수 있습니다.
6. 실전 예제: 윤곽선 기반 객체 개수 세기
윤곽선을 이용하여 이미지에서 특정 객체의 개수를 세는 예제입니다.
import cv2
import numpy as np
# 이미지 로드 및 처리
image = cv2.imread('coins.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
_, binary = cv2.threshold(blurred, 127, 255, cv2.THRESH_BINARY)
# 윤곽선 검출
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 객체 개수 출력
print(f'검출된 객체 개수: {len(contours)}')
7. 마무리
이번 글에서는 OpenCV의 cv2.findContours()를 활용하여 윤곽선을 검출하는 방법을 학습하였습니다. 다양한 모드와 근사화 방법을 비교해 보았으며, 실전 예제도 다뤄보았습니다. 이를 활용하면 이미지 내 객체 분석, 개수 세기 등의 다양한 작업을 수행할 수 있습니다.
'Python > OpenCV' 카테고리의 다른 글
| OpenCV 윤곽선 그리기 및 특징 분석 (cv2.boundingRect(), cv2.minAreaRect()) (0) | 2025.11.10 |
|---|---|
| Django에서 WebSocket과 채팅 기능 구현 (Django Channels) (0) | 2025.11.10 |
| OpenCV로 색상 히스토그램 평탄화 (cv2.equalizeHist()) (0) | 2025.11.08 |
| OpenCV 이미지 히스토그램 분석 (cv2.calcHist()) (0) | 2025.11.07 |
| OpenCV 이미지 위에 텍스트 추가하기 (cv2.putText()) (0) | 2025.11.06 |