Skip to content

OpenCV란?

OpenCV(Open Source Computer Vision Library)는 이미지와 영상 처리·분석을 위한 오픈소스 라이브러리입니다.
카메라로부터 입력된 화면을 분석하여 사물을 인식하고 판단하는 역할을 수행합니다.

OpenCV를 사용하는 이유

OpenCV를 사용하는 이유는 다음과 같습니다.

기능설명로봇 적용 예시
이미지 분석색, 윤곽선, 객체 형태 인식공/사람 인식
영상 처리실시간 카메라 프레임 처리라인 추적 로봇
위치 계산객체 중심점, 거리 추정목표 추적 및 장애물 회피
제어 연결분석 결과를 ROS 등으로 전달로봇 속도 제어

즉, 로봇에게 눈(vision)을 제공하는 핵심 기술입니다.

OpenCV 영상 처리 흐름

OpenCV 영상 처리 단계

카메라 영상 취득 -> 이미지 데이터 변환 -> 이미지 전처리 -> 이미지에서 데이터 추출

  1. 카메라에서 영상 취득 : 시스템에 연결된 카메라를 선택하고 해상도나 밝기 등의 설정을 한 후 영상을 캡쳐합니다.
  2. 이미지 전처리 : BGR -> RGB -> HSV 등으로 형식을 변환하고 이미지의 밝기, 대비, 색온도 등의 항목을 수정해 데이터 추출이 용이하게 합니다.
  3. 이미지에서 데이터 추출 : 이미지에서 색상, 엣지, 도형, 마커 등의 의미있는 데이터를 등을 추출합니다.

주의사항

OpenCV는 일반적인 RGB 순서가 아닌 BGR (Blue, Green, Red) 순서를 기본으로 사용합니다. (CV_8UC3일 때 0번 채널이 Blue입니다.)

특정 색상 찾기 예제

import cv2
import numpy as np

# 1. 카메라 설정
cap = cv2.VideoCapture(0)

# 파란색 범위 설정 (이전 시간 복습)
lower_blue = np.array([100, 30, 30])
upper_blue = np.array([140, 255, 255])

# ★ 핵심 변수: 인식할 최소 면적 (픽셀 수)
# 이 값보다 작은 덩어리는 무시합니다. (값을 조절해보세요)
MIN_AREA = 500 

print("파란색 물체를 찾아 박스를 그립니다. (종료: q)")

while True:
    ret, frame = cap.read()
    if not ret:
        break

    # 2. 색상 추출 (HSV 변환 및 마스크 생성)
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    mask = cv2.inRange(hsv, lower_blue, upper_blue)

    # (옵션) 모폴로지 연산: 노이즈를 제거하여 마스크를 깔끔하게 만듦
    # 파란색 영역의 구멍을 메우거나 자잘한 점을 없앰
    kernel = np.ones((5, 5), np.uint8)
    mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
    mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)

    # 3. 외곽선(Contour) 검출
    # cv2.RETR_EXTERNAL: 가장 바깥쪽 라인만 찾음 (구멍 뚫린 내부 라인 무시)
    # cv2.CHAIN_APPROX_SIMPLE: 직선 구간은 끝점만 저장해 메모리 절약
    contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # 4. 발견된 모든 외곽선 순회
    for cnt in contours:
        # 면적 계산
        area = cv2.contourArea(cnt)

        # ★ 크기 필터링: 면적이 설정값보다 클 때만 박스 그리기
        if area > MIN_AREA:
            # 외곽선을 감싸는 정사각 박스 좌표 구하기
            # x, y: 시작점 좌표 / w, h: 폭과 높이
            x, y, w, h = cv2.boundingRect(cnt)

            # 원본 화면에 녹색 박스 그리기 (두께 2)
            cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
            
            # 박스 위에 "Blue Object" 글자 쓰기
            cv2.putText(frame, "Blue", (x, y - 10), 
                        cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)

    # 결과 출력
    cv2.imshow('Camera', frame)       # 박스가 그려진 원본
    cv2.imshow('Mask', mask)          # 흑백 마스크 (디버깅용)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

카메라에서 영상 취득 (Capture)

OpenCV에서 동영상 파일이나 카메라 스트림을 다룰 때는 VideoCapture 클래스를 사용합니다.

원본

주요 함수 설명

  1. cv2.VideoCapture(index) : VideoCapture 클래스 생성

index

카메라 장치 번호를 지정합니다.

0: 보통 노트북의 내장 웹캠 혹은 첫 번째 연결된 카메라.

1, 2...: 추가로 연결된 USB 카메라.

"video.mp4": 파일 경로를 넣으면 동영상을 재생합니다.

  1. cap.read() : 영상을 한 프레임(한 장의 사진)씩 가져옵니다.

리턴값

(성공여부 Bool, 이미지배열 Numpy) 튜플을 반환하므로 반드시 두 변수로 받아야 합니다.

  1. cv2.waitKey(delay) : 이 함수가 없으면 창이 뜨지 않거나 멈춥니다.

delay

밀리초(ms) 단위 대기 시간입니다.

1: 1ms만 대기하고 다음 코드로 넘어감 (동영상/카메라용).

0: 키를 누를 때까지 무한 대기 (정지 영상용).

리턴값

눌린 키의 아스키 코드 값입니다.

  1. cap.release() : 프로그램이 끝날 때 카메라 장치 사용 권한을 운영체제에 반환해야 합니다. 그렇지 않으면 다른 프로그램(Zoom, Skype 등)에서 카메라를 쓰지 못할 수 있습니다.

실습 과제

  1. 기초: 위 코드를 실행하여 자기 얼굴 띄우기.
  2. 응용 1 (좌우 반전): 거울처럼 보이게 cv2.flip(frame, 1) 적용해보기.
  3. 응용 2 (필터 적용): cv2.cvtColor를 이용해 흑백(Grayscale) 영상으로 송출하기.
  4. 응용 3 (캡처): 's' 키를 누르면 현재 화면을 이미지 파일(my_photo.jpg)로 저장하기. (cv2.imwrite 사용)

이미지 전처리

  • BGR → HSV 변환
  • 파란색만 추출(Mask 생성)
# 2. 색상 추출 (HSV 변환 및 마스크 생성)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower_blue, upper_blue)

# (옵션) 모폴로지 연산: 노이즈를 제거하여 마스크를 깔끔하게 만듦
# 파란색 영역의 구멍을 메우거나 자잘한 점을 없앰
kernel = np.ones((5, 5), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)

주요 함수 설명

  1. cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) : 사람의 눈이 색을 인지하는 방식과 비슷하게 데이터를 바꾸는 과정입니다. 이 줄이 없으면 파란색 인식이 매우 불안정해집니다.

  2. cv2.inRange(src, lower, upper) : 이미지를 이진화(Binarization) 합니다.

lower ~ upper

사이의 값은 255(흰색), 범위 밖은 0(검은색)으로 바꿉니다. 결과물인 mask는 흑백 이미지가 됩니다. 흰색 영역이 우리가 찾은 "파란색 물체"의 위치입니다.

  1. cv2.morphologyEx(src, op, kernel, iterations=1) : OpenCV에서 고급 모폴로지(Morphology) 연산을 수행하는 범용 함수입니다. 한마디로 요약하면: "이미지의 잡음(작은 흰색 점)을 제거하면서, 원래 물체의 크기는 보존하는 연산"입니다.

파라미터 설명

  • src: 입력 이미지 (주로 흑백 바이너리 이미지 또는 그레이스케일 이미지)
  • op: 수행할 연산의 종류 (가장 중요한 파라미터, 아래 3번 항목 참조)
  • kernel: 구조 요소(Structuring Element). cv2.getStructuringElement()np.ones()로 생성한 커널 행렬.
  • iterations (선택): 연산 반복 횟수 (기본값은 1)

주요 연산 종류 (op 옵션)

이 함수는 두 번째 인자(op)에 무엇을 넣느냐에 따라 기능이 완전히 달라집니다.

옵션 상수 (op)이름동작 원리주요 용도
cv2.MORPH_OPEN열기 (Opening)침식 후 팽창
(Erosion → Dilation)
노이즈 제거, 작은 돌기 제거, 서로 붙은 물체 떼어내기
cv2.MORPH_CLOSE닫기 (Closing)팽창 후 침식
(Dilation → Erosion)
구멍 메우기, 끊어진 물체 이어 붙이기
cv2.MORPH_GRADIENT그라디언트팽창 - 침식
(Dilation - Erosion)
경계선(Edge) 검출, 물체의 외곽선 찾기
cv2.MORPH_TOPHAT탑햇 (Top Hat)원본 - 열기
(Src - Opening)
밝은 부분 강조, 배경이 어두울 때 국소적으로 밝은 미세한 부분 검출
cv2.MORPH_BLACKHAT블랙햇 (Black Hat)닫기 - 원본
(Closing - Src)
어두운 부분 강조, 배경이 밝을 때 국소적으로 어두운 미세한 부분 검출

아래 사진은 모폴로지(Morphology) 처리를 하기 전과 후이다.

원본 마스크모폴로지 연산 후

HSV를 왜 쓰는가?

카메라에서 들어오는 원본 이미지는 보통 BGR형식입니다.
하지만 BGR에서는 밝기 변화(조명)에 따라 같은 물체도 값이 크게 바뀌어서 색으로 물체를 찾기 까다롭습니다.
그래서 색 추적에는 보통 HSV(Hue, Saturation, Value) 색공간을 사용합니다.

  • H(Hue) : 색상(빨강, 초록, 파랑 등), OpenCV에서 H의 범위: 0 ~ 179
  • S(Saturation) : 색의 진함 정도 (원색에 가까운지)
  • V(Value) : 색의 밝기

💡 핵심: HSV 모델에서는 밝기(V)가 변해도 색상(H) 값은 거의 변하지 않으므로 특정 색을 검출하기 훨씬 쉽습니다.

HSV 범위 지정은 다음과 같이 작성할 수 있습니다.

# 파란색 영역 마스크 생성 (Hue: 100~140)
lower_blue = np.array([100, 100, 50])
upper_blue = np.array([140, 255, 255])


# 빨간색은 Hue 값이 0 근처와 180 근처 두 군데에 존재함
lower_red1 = np.array([0, 50, 50])
upper_red1 = np.array([10, 255, 255])
lower_red2 = np.array([170, 50, 50])
upper_red2 = np.array([180, 255, 255])

mask1 = cv2.inRange(hsv, lower_red1, upper_red1)
mask2 = cv2.inRange(hsv, lower_red2, upper_red2)
mask = mask1 + mask2 # 두 마스크 합치기

각 값들 순서대로 H, S, V이며 현재 예시로 되어있는 코드는 파란색을 인식하도록 되어있습니다.

이미지에서 데이터 추출

  • 이진화된 이미지(Mask)에서 외곽선(Contour)을 찾을 수 있다.
  • contourArea를 사용하여 작은 노이즈(잡음)는 무시하고, 큰 물체만 골라낸다.
  • 물체의 위치를 계산하여 사각형 박스(Bounding Box)를 그릴 수 있다.
# 면적 계산
area = cv2.contourArea(cnt)

# ★ 크기 필터링: 면적이 설정값보다 클 때만 박스 그리기
if area > MIN_AREA:
    # 외곽선을 감싸는 정사각 박스 좌표 구하기
    # x, y: 시작점 좌표 / w, h: 폭과 높이
    x, y, w, h = cv2.boundingRect(cnt)

    # 원본 화면에 녹색 박스 그리기 (두께 2)
    cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
원본 마스크모폴로지 연산 후

주요 함수 설명

  1. cv2.findContours(image, mode, method) : 마스크 이미지(흑백)에서 흰색 영역의 경계선을 찾습니다.

파라미터 설명

  • image: 반드시 이진화(흑백)된 이미지여야 합니다. (mask)
  • mode: cv2.RETR_EXTERNAL을 쓰면 물체 안에 있는 구멍(도넛 모양의 내부)은 무시하고, 가장 바깥 테두리만 찾습니다.

리턴값

contours는 외곽선 좌표들의 리스트(List)입니다.

  1. cv2.contourArea(cnt) : 찾아낸 외곽선이 차지하는 면적(픽셀 수)을 계산합니다.

왜 필요한가요?

화면에 먼지 같은 파란색 점이 찍혀도 컴퓨터는 인식합니다. 이런 노이즈를 제거하기 위해 "면적이 500 이상인 것만 그려라"라는 조건문(if area > MIN_AREA)을 사용합니다.

  1. cv2.boundingRect(cnt) : 외곽선(cnt)을 감싸는 가장 작은 똑바른 사각형을 구합니다.

리턴값

x (왼쪽 위 가로), y (왼쪽 위 세로), w (폭), h (높이)

  1. cv2.rectangle(img, pt1, pt2, color, thickness) : 이미지에 사각형을 그립니다.

파라미터 설명

  • img: 사각형을 그릴 이미지입니다.
  • pt1: 시작점 (x, y)
  • pt2: 끝점 (x + w, y + h)
  • color: 사각형의 색상입니다. (B, G, R) 형식의 튜플이나 스칼라 값으로 지정할 수 있습니다.
  • thickness: 선택적으로 사각형의 선 두께를 지정합니다. 음수 값을 전달하면 내부를 채웁니다.

실습 과제

  1. 기초: 가장 큰 물체 하나만 잡기 지금 코드는 파란색 물체가 3개 있으면 박스도 3개가 생깁니다. 화면에 파란색이 여러 개 있어도, 가장 큰 물체 1개에만 박스를 그리도록 코드를 수정해보세요. 힌트: contours 리스트를 반복문 돌기 전에 max() 함수나 정렬을 이용해 면적이 제일 큰 녀석을 찾으세요.

  2. 응용 1: 물체의 중심점 찍기 박스 중심에 빨간 점을 찍어보세요. 중심 좌표 공식: center_x = x + w // 2, center_y = y + h // 2

  3. 응용 2: 컵/펜 추적하기 파란색 컵이나 파란색 뚜껑 펜을 준비해서 카메라 앞에서 흔들어보며 박스가 잘 따라오는지 테스트해보세요. MIN_AREA 값을 조절해가며 최적의 값을 찾아보세요.