메뉴 닫기

파이썬 OpenCV 드로잉 마스터: 선, 도형, 텍스트, 투명 오버레이 완벽 가이드

파이썬 OpenCV 드로잉 마스터: 선, 도형, 텍스트, 투명 오버레이 완벽 가이드

🎨 이미지 분석 결과를 시각적으로 표현하는 OpenCV 그리기 함수 총정리

이미지나 영상을 처리하는 과정에서, 특정 영역을 강조하거나 분석 결과를 시각적으로 보여줘야 할 때가 많습니다.
단순히 처리된 결과 이미지만 보여주는 것보다, 사용자에게 핵심 정보를 명확하게 전달하려면 ‘그리기(Drawing)’ 기능이 필수적입니다.
특히 파이썬 OpenCV는 이미지에 다양한 도형, 선, 텍스트를 쉽고 빠르게 추가할 수 있는 강력한 함수들을 제공합니다.
하지만 막상 사용하려고 하면 좌표계, 색상 지정, 두께, 폰트 종류 등 신경 쓸 부분이 한두 가지가 아닙니다.
복잡한 옵션 때문에 시간을 허비하거나 원하는 결과물을 얻지 못했던 경험이 있다면, 이 글이 완벽한 해결책이 될 것입니다.

이 글에서는 컴퓨터 비전 분야에서 가장 기본이 되면서도 핵심적인 기술인 파이썬 OpenCV의 그리기 및 주석(Annotation) 함수들을 A부터 Z까지 상세하게 다룹니다.
직선, 사각형, 원과 같은 기본 도형 그리기부터, 이미지 위에 정보를 표시하는 putText 함수 사용법, 그리고 고급 기법인 투명 오버레이를 구현하는 addWeighted 함수까지 모두 다룰 예정입니다.
객체 검출(Object Detection) 결과를 시각화하거나, 이미지에 간단한 UI 요소를 추가해야 하는 모든 분들에게 실질적인 도움이 될 수 있도록 핵심 기능과 코드 예시를 중심으로 설명합니다.
OpenCV 드로잉 기능을 마스터하고, 여러분의 이미지 처리 애플리케이션의 시각적 완성도를 한 단계 높여보시기 바랍니다.



📐 기본 도형 그리기: cv2.line, rectangle, circle 함수

OpenCV에서 가장 기본적인 시각화 작업은 이미지 위에 선, 사각형, 원을 그리는 것입니다.
이 함수들은 객체 검출(Bounding Box), 중심점 표시, 추적 경로 시각화 등 활용도가 매우 높습니다.
기본 인자들을 정확히 이해하고 사용하면 원하는 모양을 쉽게 표현할 수 있습니다.

📏 직선 그리기: cv2.line()

두 점을 연결하여 직선을 그릴 때 사용합니다.
시작점과 끝점, 그리고 선의 색상과 두께를 필수로 지정해야 합니다.

  • 🖼️함수 형식: cv2.line(img, pt1, pt2, color, thickness, lineType)
  • 🟢pt1, pt2: 시작점과 끝점 좌표 (튜플 형태, 예: (100, 100))
  • 🎨color: BGR 색상 (튜플 형태, 예: (255, 0, 0)은 파란색)

⏹️ 사각형 그리기: cv2.rectangle()

사각형의 좌측 상단 모서리와 우측 하단 모서리 두 점만 알면 사각형을 그릴 수 있습니다.
객체 검출의 바운딩 박스를 표시할 때 가장 흔하게 사용됩니다.

  • 🖼️함수 형식: cv2.rectangle(img, pt1, pt2, color, thickness, lineType)
  • 🔴pt1, pt2: 좌상단 모서리와 우하단 모서리 좌표
  • 💡채우기: 두께(thickness) 인자에 -1을 입력하면 사각형 내부가 색상으로 채워집니다.

⚫ 원 그리기: cv2.circle()

원의 중심점 좌표와 반지름을 사용하여 원을 그립니다.
객체의 중심점을 표시하거나 특정 영역을 강조할 때 유용합니다.

  • 🖼️함수 형식: cv2.circle(img, center, radius, color, thickness, lineType)
  • 📍center: 원의 중심 좌표 (예: (300, 300))
  • 📐radius: 원의 반지름 (정수 값)

💬 OpenCV는 BGR(파랑, 초록, 빨강) 순서로 색상을 지정합니다. 익숙한 RGB와 순서가 다르니 혼동하지 않도록 주의해야 합니다.

CODE BLOCK
import numpy as np
import cv2
 
# 512x512 크기의 검은색 이미지 생성 (BGR 3채널)
img = np.zeros((512, 512, 3), np.uint8)
 
# 1. 직선 그리기: 빨간색, 두께 5
cv2.line(img, (50, 50), (450, 50), (0, 0, 255), 5) 
 
# 2. 사각형 그리기: 초록색, 채우기 (-1)
cv2.rectangle(img, (50, 100), (450, 200), (0, 255, 0), -1) 
 
# 3. 원 그리기: 파란색, 두께 3
cv2.circle(img, (250, 350), 100, (255, 0, 0), 3) 
 
cv2.imshow('OpenCV Drawing Examples', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

이 기본적인 함수들만으로도 이미지에 필요한 거의 모든 시각적 주석을 추가할 수 있습니다.
선 두께와 색상을 조절하며 다양한 모양을 시도해보는 것이 중요합니다.

🔺 다각형 그리기 및 채우기: cv2.polylines, fillPoly

선분, 사각형, 원과는 달리, 복잡한 형태의 객체나 사용자 정의 영역을 표시해야 할 때는 다각형(Polygon)을 사용해야 합니다.
OpenCV에서는 cv2.polylines() 함수로 여러 선분을 연결한 다각형 윤곽선을 그리거나, cv2.fillPoly() 함수로 내부를 채울 수 있습니다.

🔗 다중 선분(다각형 윤곽선) 그리기: cv2.polylines()

다각형을 그릴 때는 여러 개의 꼭짓점 좌표를 NumPy 배열로 전달하는 것이 특징입니다.
이는 한 번의 함수 호출로 복잡한 모양을 그릴 수 있게 해줍니다.
특히, 꼭짓점 배열을 3차원 배열로 만드는 과정이 중요합니다.

  • 🖼️함수 형식: cv2.polylines(img, pts, isClosed, color, thickness)
  • 📍pts: 꼭짓점 배열 리스트 (NumPy 배열), 형태는 (1, N, 2) 또는 (N, 1, 2)여야 합니다.
  • ↔️isClosed: True로 설정하면 시작점과 끝점을 연결하여 닫힌 다각형을 만듭니다.

다각형 좌표를 정의할 때 중요한 것은 NumPy 배열의 차원입니다.
OpenCV가 요구하는 형태인 (꼭짓점 수, 1, 2)로 변환하기 위해 .reshape((-1, 1, 2))를 사용하는 것이 일반적입니다.

⚫ 다각형 내부 채우기: cv2.fillPoly()

영역 분할(Segmentation) 결과를 시각화하거나, 이미지의 특정 부분을 마스크 처리할 때 다각형 내부를 색상으로 채우는 작업이 필요합니다.
cv2.fillPoly() 함수는 cv2.polylines()와 거의 동일한 인자를 사용하지만, 두께(thickness) 옵션이 없고 내부를 완전히 채운다는 차이가 있습니다.

💡 TIP: 다각형을 정의하는 pts 인자는 NumPy 배열의 리스트 형태여야 합니다. 즉, 단일 다각형일지라도 [pts_array] 형태로 감싸서 전달해야 합니다.

CODE BLOCK
import numpy as np
import cv2
 
img = np.zeros((512, 512, 3), np.uint8)
 
# 1. 다각형 꼭짓점 정의
pts = np.array([[100, 100], [200, 250], [150, 400], [50, 300]], np.int32)
 
# 2. OpenCV 형식에 맞게 배열 변환 (N, 1, 2)
# reshape(-1, 1, 2)는 pts를 (4, 1, 2) 형태로 만듭니다.
pts = pts.reshape((-1, 1, 2)) 
 
# 3. 다각형 윤곽선 그리기: 흰색, 닫힌 다각형(True)
cv2.polylines(img, [pts], True, (255, 255, 255), 5) 
 
# 4. 다른 다각형을 정의하여 내부 채우기 (노란색)
pts_fill = np.array([[300, 100], [450, 100], [450, 400], [300, 400]], np.int32)
pts_fill = pts_fill.reshape((-1, 1, 2))
 
# 내부 채우기
cv2.fillPoly(img, [pts_fill], (0, 255, 255)) 
 
cv2.imshow('OpenCV Polygon Examples', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

특히 isClosed=True는 마지막 꼭짓점에서 첫 번째 꼭짓점으로 선을 자동으로 연결해 다각형을 닫아주기 때문에 유용하며, cv2.fillPoly는 내부를 완전히 채워 마스킹 효과를 줄 때 자주 활용됩니다.



✍️ 텍스트 주석 추가: cv2.putText 폰트 및 안티앨리어싱 설정

이미지 분석 결과(예: 객체 클래스, 정확도, 카운트)를 숫자나 문자열로 표시하는 것은 시각화의 가장 중요한 요소 중 하나입니다.
OpenCV에서는 cv2.putText() 함수를 사용하여 이미지에 텍스트 주석을 추가합니다.
이 함수는 사용하기 쉽지만, 글꼴(폰트) 선택과 안티앨리어싱(Anti-aliasing) 처리가 중요합니다.

🔡 cv2.putText() 함수의 핵심 인자

텍스트를 효과적으로 표시하기 위해 반드시 알아야 할 cv2.putText()의 주요 인자는 다음과 같습니다.
특히, 폰트 종류(fontFace)선의 종류(lineType)가 텍스트의 품질을 결정합니다.

  • 🖼️함수 형식: cv2.putText(img, text, org, fontFace, fontScale, color, thickness, lineType)
  • 📍org: 텍스트의 시작점 (좌측 하단 기준 좌표)
  • 🔤fontFace: OpenCV에서 제공하는 폰트 상수 (예: cv2.FONT_HERSHEY_SIMPLEX)
  • 🔍fontScale: 글자의 크기 배율 (float)

📝 OpenCV 기본 폰트 종류

OpenCV는 시스템 폰트를 직접 사용할 수 없고, 자체적으로 정의된 몇 가지 ‘Hershey Fonts’만 지원합니다.
대표적으로 FONT_HERSHEY_SIMPLEX(기본), FONT_HERSHEY_DUPLEX, FONT_HERSHEY_SCRIPT_COMPLEX 등이 있으며, 이들을 조합하여 기울임꼴이나 크기를 조절할 수 있습니다.

✨ 안티앨리어싱(Anti-aliasing) 적용의 중요성

텍스트나 도형을 그릴 때 계단 현상(Jaggies) 없이 부드러운 외곽선을 만들기 위해 안티앨리어싱이 필요합니다.
OpenCV에서는 lineType 인자에 cv2.LINE_AA 상수를 지정하여 안티앨리어싱을 적용할 수 있습니다.
이는 특히 작은 글씨나 해상도가 낮은 이미지에서 텍스트의 가독성을 크게 향상시킵니다.

⚠️ 주의: cv2.putText는 한글 같은 멀티바이트 문자를 기본적으로 지원하지 않습니다. 한글을 표시하려면 Pillow(PIL)와 같은 외부 라이브러리를 사용하여 텍스트를 그린 후 OpenCV 이미지와 합치는 복잡한 과정이 필요합니다.

CODE BLOCK
import numpy as np
import cv2
 
img = np.zeros((512, 512, 3), np.uint8)
 
text1 = "Line Type 8 (Jaggies)"
text2 = "Line Type AA (Anti-aliased)"
 
# 1. 안티앨리어싱 미적용 (기본값 lineType=8)
cv2.putText(img, text1, (50, 150), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2, cv2.LINE_8)
 
# 2. 안티앨리어싱 적용 (lineType=cv2.LINE_AA)
cv2.putText(img, text2, (50, 250), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2, cv2.LINE_AA) 
 
cv2.imshow('OpenCV putText Examples', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

코드 예시를 보면, cv2.LINE_AA를 적용한 텍스트가 훨씬 부드럽고 전문적인 느낌을 준다는 것을 알 수 있습니다.
따라서 가독성이 중요한 모든 시각화 작업에는 cv2.LINE_AA를 습관적으로 사용하는 것을 권장합니다.

이미지 투명 오버레이 구현: cv2.addWeighted 활용

단순히 도형을 그리는 것을 넘어, 이미지 위에 반투명한 마스크나 워터마크, 혹은 두 이미지를 부드럽게 합성하는 알파 블렌딩(Alpha Blending) 기법을 사용해야 할 때가 있습니다.
OpenCV에서는 cv2.addWeighted() 함수를 이용하여 이러한 투명 오버레이를 구현할 수 있습니다.

🧮 addWeighted 함수의 동작 원리와 수식

이 함수는 두 이미지(src1, src2)의 가중치 합을 계산하여 새로운 이미지(dst)를 생성합니다.
이 과정을 통해 한 이미지가 다른 이미지 위에 투명하게 겹쳐 보이는 효과를 만듭니다.

💬 가중치 합 수식: $dst = \alpha \cdot src1 + \beta \cdot src2 + \gamma$

여기서 $\alpha$와 $\beta$는 각각 src1src2에 적용되는 가중치(투명도)를 나타냅니다.
일반적으로 부드러운 전환을 위해 $\beta$는 $(1 – \alpha)$로 설정하고, $\gamma$ (감마)는 밝기 조절을 위한 상수값으로 0을 사용하는 경우가 많습니다.

  • 🖼️함수 형식: cv2.addWeighted(src1, alpha, src2, beta, gamma, dst)
  • ⚖️alpha, beta: 가중치 (0.0 ~ 1.0 사이의 float 값), 투명도를 결정합니다.
  • gamma: 결과에 더해지는 상수값 (대부분 0.0)

💻 투명 오버레이 구현 코드 예시

투명한 사각형을 만들어 이미지 위에 오버레이하는 방식으로 활용할 수 있습니다.
먼저 오버레이할 이미지를 원본 이미지와 동일한 크기로 생성하고, 거기에 도형을 그린 뒤, addWeighted를 사용하여 원본 이미지와 합성합니다.

CODE BLOCK
import numpy as np
import cv2
 
# 1. 원본 이미지 로드 (혹은 생성)
img = cv2.imread('sample_image.jpg') 
if img is None:
    img = np.zeros((500, 500, 3), np.uint8) + 150 # 테스트용 회색 배경
 
h, w, _ = img.shape
 
# 2. 오버레이할 투명 레이어 생성 (검은색)
overlay = np.zeros((h, w, 3), np.uint8) 
 
# 3. 오버레이 레이어에 도형 그리기 (노란색, 완전히 채움)
# 원본 이미지의 중간 부분을 덮을 사각형
cv2.rectangle(overlay, (w//4, h//4), (w*3//4, h*3//4), (0, 255, 255), -1) 
 
# 4. addWeighted를 사용하여 투명 오버레이 적용
# 원본 이미지 가중치: 0.7, 오버레이 가중치(투명도): 0.3
alpha = 0.7
beta = 1 - alpha
gamma = 0
 
blended = cv2.addWeighted(img, alpha, overlay, beta, gamma)
 
cv2.imshow('Transparent Overlay with addWeighted', blended)
cv2.waitKey(0)
cv2.destroyAllWindows()

위 예시에서 alpha 값을 조절함으로써 배경 이미지(img)와 오버레이 이미지(overlay)의 투명도를 조정할 수 있습니다.
$\alpha = 1.0$ 이면 오버레이 효과 없이 원본 이미지만 보이게 되며, $\alpha = 0.0$ 이면 오버레이 레이어만 보이게 됩니다.



💡 OpenCV 그리기 함수 공통 인자와 팁

OpenCV의 대부분의 그리기 함수들(cv2.line, cv2.rectangle, cv2.circle, cv2.putText 등)은 공통적으로 사용하는 인자들이 있습니다.
이 공통 인자들을 정확히 이해하면 어떤 함수를 사용하든 일관성 있는 시각화 작업을 수행할 수 있습니다.

🖼️ 이미지 좌표계와 색상 지정

OpenCV에서 좌표계는 컴퓨터 그래픽스에서 흔히 사용되는 방식인 좌측 상단이 원점 (0, 0)입니다.
x축은 오른쪽으로, y축은 아래쪽으로 증가합니다.
색상은 BGR 순서의 튜플로 지정해야 합니다.

인자 설명 주요 값/사용법
color 그릴 요소의 색상 B, G, R 순서의 튜플 (예: (255, 0, 0)은 파랑)
thickness 선 두께 또는 채우기 여부 양수(두께), -1(내부 채우기)
lineType 선의 연결 방식(품질) cv2.LINE_AA (안티앨리어싱, 권장)

🎨 이미지 복사와 Numpy 뷰(View)의 이해

OpenCV 함수는 인자로 전달된 이미지(NumPy 배열)를 직접 변경(In-place modification)하는 경우가 대부분입니다.
즉, 도형을 그리면 원본 이미지 데이터 자체가 수정됩니다.

💡 TIP: 원본 이미지를 훼손하지 않고 새로운 이미지에만 도형을 그리려면, 반드시 img.copy()를 사용하여 사본을 만들어 그리기 함수에 전달해야 합니다. NumPy 배열의 뷰(View)가 아닌 실제 데이터를 복사하는 것이 중요합니다.

CODE BLOCK
import cv2
 
img_original = cv2.imread('sample.jpg') # 원본 이미지 로드
 
# 1. 사본 생성: 원본을 유지하고 싶을 때 필수
img_copy = img_original.copy() 
 
# 2. 사본에 사각형 그리기
cv2.rectangle(img_copy, (10, 10), (100, 100), (0, 255, 0), 2, cv2.LINE_AA)
 
# img_original은 변경되지 않음
# img_copy에만 사각형이 그려짐
 
cv2.imshow('Original Image', img_original)
cv2.imshow('Copied and Drawn Image', img_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()

이처럼 사본을 사용하는 습관은 복잡한 이미지 처리 파이프라인에서 원본 데이터의 무결성을 유지하고 예상치 못한 오류를 방지하는 가장 기본적인 방법입니다.
또한, 모든 그리기 함수에 cv2.LINE_AA를 적용하는 것은 결과물의 품질을 결정하는 중요한 요소입니다.

자주 묻는 질문 (FAQ)

OpenCV 그리기 함수에서 한글 텍스트를 넣으려면 어떻게 해야 하나요?
cv2.putText는 기본적으로 아스키 기반의 Hershey 폰트만 지원하며 한글은 지원하지 않습니다. 한글을 사용하려면 Pillow(PIL)와 같은 외부 라이브러리를 사용하여 텍스트를 그린 후, 이를 NumPy 배열로 변환하여 OpenCV 이미지와 병합해야 합니다.
도형의 내부를 색상으로 채우고 싶을 때는 어떤 인자를 사용해야 하나요?
cv2.rectangle이나 cv2.circle 같은 도형 그리기 함수의 thickness(두께) 인자에 양수 대신 -1을 입력하면 도형의 내부를 지정된 color로 완전히 채울 수 있습니다.
투명한 오버레이 효과를 만들 때, cv2.addWeighted 대신 다른 방법이 있나요?
네, 4채널(BGRA) 이미지를 사용하는 방법도 있습니다. 오버레이 이미지에 알파 채널을 추가하여 투명도를 정의한 후, 이 마스크를 사용하여 원본 이미지와 오버레이 이미지를 합성하는 방식입니다. 다만 cv2.addWeighted가 가장 빠르고 간편한 방법으로 많이 사용됩니다.
OpenCV에서 색상을 지정할 때 왜 RGB 대신 BGR 순서를 사용하나요?
OpenCV는 원래 C++로 개발되었는데, 당시 Windows API나 몇몇 초기 이미지 처리 라이브러리가 BGR 순서를 기본으로 채택했기 때문입니다. 이 전통이 파이썬 바인딩에도 그대로 유지되어 현재까지 BGR을 사용하고 있습니다.
다각형을 그리는 cv2.polylines 함수에 좌표 배열을 전달할 때 유의할 점은 무엇인가요?
꼭짓점 좌표는 NumPy 배열로 전달해야 하며, 형태가 (N, 1, 2) 또는 (1, N, 2)의 3차원 배열이어야 합니다. 파이썬 리스트로 정의한 후 np.array로 변환하고 .reshape((-1, 1, 2))를 적용하는 것이 가장 일반적입니다.
안티앨리어싱을 적용하지 않으면 어떤 문제가 발생하나요?
안티앨리어싱(cv2.LINE_AA)을 적용하지 않으면 선이나 텍스트의 외곽선이 픽셀화되어 거칠게 보입니다. 특히 대각선이나 곡선에서 심한 계단 현상(Jaggies)이 나타나 시각적인 품질과 가독성이 크게 떨어집니다.
OpenCV 함수가 원본 이미지를 변경하지 않게 하려면 어떻게 해야 하나요?
OpenCV의 그리기 함수들은 대부분 In-place 연산을 수행하여 원본 배열을 직접 수정합니다. 원본을 보호하려면 그리기 함수를 호출하기 전에 반드시 img_original.copy()를 사용하여 이미지 배열의 사본을 만들어 작업해야 합니다.
addWeighted 함수에서 감마($\gamma$) 인자는 무엇을 의미하며 언제 사용하나요?
감마 인자는 두 이미지를 합친 결과에 더해지는 상수값입니다. 이 값은 결과 이미지의 전반적인 밝기(Brightness)를 조절하는 데 사용됩니다. 일반적으로 이미지 합성 시에는 0.0을 사용하지만, 합성된 이미지 전체를 더 밝거나 어둡게 하고 싶을 때 양수나 음수를 사용할 수 있습니다.

💾 파이썬 OpenCV 드로잉 기능 마스터의 핵심 요약

OpenCV의 그리기 및 주석 기능은 단순히 이미지를 꾸미는 것을 넘어, 컴퓨터 비전 애플리케이션의 분석 결과를 시각적으로 명확하게 전달하는 핵심 도구입니다.
지금까지 살펴본 cv2.line, cv2.rectangle, cv2.putText, cv2.addWeighted 등의 함수들을 숙달한다면, 객체 검출의 바운딩 박스 표시부터 복잡한 영역 분할 결과의 투명 오버레이까지 모든 시각화 요구사항을 충족시킬 수 있습니다.

가장 중요한 것은 OpenCV가 사용하는 BGR 색상 순서와 좌측 상단 원점의 좌표계에 익숙해지는 것입니다.
또한, 모든 시각화 결과물의 품질을 높이기 위해 안티앨리어싱 옵션인 cv2.LINE_AA를 습관처럼 사용하는 것이 중요합니다.
특히, 다각형 그리기 시에는 NumPy 배열의 차원(reshape((-1, 1, 2)))을 정확히 맞추는 디테일이 필요하며, 두 이미지를 합성하는 addWeighted 함수를 이용해 세련된 반투명 효과를 쉽게 구현할 수 있습니다.

OpenCV 드로잉 기능을 통해 여러분의 프로젝트에 생동감 있는 시각적 요소를 더하고, 사용자나 동료에게 분석 결과를 더욱 효과적으로 전달하시길 바랍니다.
이 가이드가 복잡한 인자들에 대한 혼란을 해소하고, 빠르고 정확하게 시각화 코드를 작성하는 데 도움이 되었기를 바랍니다.


🏷️ 관련 태그 : 파이썬, OpenCV, cv2.line, cv2.rectangle, cv2.circle, cv2.putText, cv2.addWeighted, 투명오버레이, 이미지주석, 컴퓨터비전