이미지와 영상처리

🎨 마우스로 영상 위에 그림 그리기 – OpenCV 마우스 이벤트 실습 정리 (2-6 ~ 2-9)📅 작성일: 2025년 4월 20일

EasyHanAI 2025. 4. 20. 20:29

 

✍️ 작성 목적: OpenCV 마우스 이벤트를 활용해 직사각형 그리기, 텍스트 쓰기, 붓으로 그리기 등의 실습을 정리했습니다. 단순히 코드 실행이 아닌 코드의 흐름과 원리, 그리고 제가 느낀 부족했던 점과 개선 방향까지 담았습니다.


📌 학습 내용 요약

  • OpenCV로 이미지 불러오기
  • 마우스 클릭 이벤트 감지
  • 마우스 위치에 도형 및 글씨 그리기
  • 드래그로 사각형 그리기
  • 좌클릭/우클릭에 따라 색상 변경하기

📁 예제 1 – [2-6] 이미지에 도형과 글씨 그리기

🔧 사용 기능:

  • cv.rectangle(): 사각형 그리기
  • cv.putText(): 글씨 쓰기

💡 코드:

import cv2 as cv
import sys

img = cv.imread('girl_laughing.jpg')  # 이미지 불러오기

if img is None:
    sys.exit('파일을 찾을 수 없습니다.')

# 직사각형 그리기 (좌측 상단 830,30 ~ 우측 하단 1000,200), 빨간색
cv.rectangle(img, (830, 30), (1000, 200), (0, 0, 255), 2)

# 텍스트 추가 (위치: 830,24), 파란색
cv.putText(img, 'laugh', (830, 24), cv.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)

cv.imshow('Draw', img)
cv.waitKey()
cv.destroyAllWindows()

🧠 배운 점:

  • 단순한 이미지 출력만 하는 게 아니라, 그 위에 원하는 위치에 그림과 글씨를 그릴 수 있음
  • 텍스트와 도형이 겹치지 않게 위치 조절이 중요함

📁 예제 2 – [2-7] 마우스로 클릭한 곳에 사각형 그리기

import cv2 as cv
import sys

img = cv.imread('girl_laughing.jpg')
if img is None:
    sys.exit('파일을 찾을 수 없습니다.')

def draw(event, x, y, flags, param):
    if event == cv.EVENT_LBUTTONDOWN:
        # 좌클릭: 큰 사각형 (파란색)
        cv.rectangle(img, (x, y), (x + 200, y + 200), (0, 0, 255), 2)
    elif event == cv.EVENT_RBUTTONDOWN:
        # 우클릭: 작은 사각형 (빨간색)
        cv.rectangle(img, (x, y), (x + 100, y + 100), (255, 0, 0), 2)

    cv.imshow('Drawing', img)

cv.namedWindow('Drawing')
cv.imshow('Drawing', img)
cv.setMouseCallback('Drawing', draw)

while True:
    if cv.waitKey(1) == ord('q'):
        cv.destroyAllWindows()
        break

🧠 배운 점:

  • 마우스 버튼 종류에 따라 동작을 달리하는 이벤트 처리
  • 직사각형 크기 조절도 가능함

📁 예제 3 – [2-8] 드래그로 사각형 그리기

import cv2 as cv
import sys

img = cv.imread('girl_laughing.jpg')
if img is None:
    sys.exit('파일을 찾을 수 없습니다.')

def draw(event, x, y, flags, param):
    global ix, iy

    if event == cv.EVENT_LBUTTONDOWN:
        ix, iy = x, y  # 시작 좌표 저장
    elif event == cv.EVENT_LBUTTONUP:
        # 드래그 끝 지점에서 사각형 그리기
        cv.rectangle(img, (ix, iy), (x, y), (0, 0, 255), 2)

    cv.imshow('Drawing', img)

cv.namedWindow('Drawing')
cv.imshow('Drawing', img)
cv.setMouseCallback('Drawing', draw)

while True:
    if cv.waitKey(1) == ord('q'):
        cv.destroyAllWindows()
        break

🧠 배운 점:

  • 마우스 눌렀을 때 시작 좌표, 뗐을 때 끝 좌표로 사각형 생성
  • 마치 그림판처럼 드래그로 영역 지정 가능

📁 예제 4 – [2-9] 좌클릭은 파란 붓, 우클릭은 빨간 붓

import cv2 as cv
import sys

img = cv.imread('soccer.jpg')
if img is None:
    sys.exit('파일을 찾을 수 없습니다.')

BrushSiz = 5
LColor, RColor = (255, 0, 0), (0, 0, 255)  # 파란색, 빨간색

def painting(event, x, y, flags, param):
    if event == cv.EVENT_LBUTTONDOWN:
        cv.circle(img, (x, y), BrushSiz, LColor, -1)
    elif event == cv.EVENT_RBUTTONDOWN:
        cv.circle(img, (x, y), BrushSiz, RColor, -1)
    elif event == cv.EVENT_MOUSEMOVE and flags == cv.EVENT_FLAG_LBUTTON:
        cv.circle(img, (x, y), BrushSiz, LColor, -1)
    elif event == cv.EVENT_MOUSEMOVE and flags == cv.EVENT_FLAG_RBUTTON:
        cv.circle(img, (x, y), BrushSiz, RColor, -1)

    cv.imshow('Painting', img)

cv.namedWindow('Painting')
cv.imshow('Painting', img)
cv.setMouseCallback('Painting', painting)

while True:
    if cv.waitKey(1) == ord('q'):
        cv.destroyAllWindows()
        break

🧠 배운 점:

  • 마우스를 움직이면서 색칠하는 기능까지 가능
  • 클릭 여부와 움직임을 동시에 판단해야 함 (flags 사용)

😓 부족했던 점

  • 처음엔 setMouseCallback()의 사용법이 어려웠습니다.
  • 마우스 이벤트 종류가 많아 혼동이 있었고, 좌표 설정도 헷갈렸습니다.

🔧 개선할 부분

  • 사각형 그릴 때, 실시간으로 미리보기 형태로 보이게 구현하고 싶었습니다.
  • 브러시 색상이나 크기를 키보드로 바꿀 수 있도록 확장해보면 실전 그림판과 가까워질 것 같습니다.
  • 코드 재사용성을 높이기 위해 콜백 함수 안에 너무 많은 동작을 넣지 않고, 함수 분리도 고민하고 있습니다.

✅ 마무리 정리

오늘 배운 OpenCV 마우스 이벤트 실습은 단순한 이미지 출력에서 벗어나, 인터랙티브한 프로그램을 만드는 데 필수적인 기능이었습니다.
마우스 클릭 → 도형 → 색칠 → 글씨까지 직접 반응하는 프로그램을 만든다는 재미가 컸고,
무엇보다 사용자 이벤트 처리에 대한 감각을 익히는 데 큰 도움이 되었습니다.