OpenCV란?
OpenCV(Open Source Computer Vision Library)는 이미지와 영상 처리·분석을 위한 오픈소스 라이브러리입니다.
카메라로부터 입력된 화면을 분석하여 사물을 인식하고 판단하는 역할을 수행합니다.
OpenCV를 사용하는 이유
OpenCV를 사용하는 이유는 다음과 같습니다.
| 기능 | 설명 | 로봇 적용 예시 |
|---|---|---|
| 이미지 분석 | 색, 윤곽선, 객체 형태 인식 | 공/사람 인식 |
| 영상 처리 | 실시간 카메라 프레임 처리 | 라인 추적 로봇 |
| 위치 계산 | 객체 중심점, 거리 추정 | 목표 추적 및 장애물 회피 |
| 제어 연결 | 분석 결과를 ROS 등으로 전달 | 로봇 속도 제어 |
즉, 로봇에게 눈(vision)을 제공하는 핵심 기술입니다.
OpenCV 영상 처리 흐름
OpenCV 영상 처리 단계
카메라 영상 취득 -> 이미지 데이터 변환 -> 이미지 전처리 -> 이미지에서 데이터 추출
- 카메라에서 영상 취득 : 시스템에 연결된 카메라를 선택하고 해상도나 밝기 등의 설정을 한 후 영상을 캡쳐합니다.
- 이미지 전처리 : BGR -> RGB -> HSV 등으로 형식을 변환하고 이미지의 밝기, 대비, 색온도 등의 항목을 수정해 데이터 추출이 용이하게 합니다.
- 이미지에서 데이터 추출 : 이미지에서 색상, 엣지, 도형, 마커 등의 의미있는 데이터를 등을 추출합니다.
주의사항
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 클래스를 사용합니다.

주요 함수 설명
- cv2.VideoCapture(index) : VideoCapture 클래스 생성
index
카메라 장치 번호를 지정합니다.
0: 보통 노트북의 내장 웹캠 혹은 첫 번째 연결된 카메라.
1, 2...: 추가로 연결된 USB 카메라.
"video.mp4": 파일 경로를 넣으면 동영상을 재생합니다.
- cap.read() : 영상을 한 프레임(한 장의 사진)씩 가져옵니다.
리턴값
(성공여부 Bool, 이미지배열 Numpy) 튜플을 반환하므로 반드시 두 변수로 받아야 합니다.
- cv2.waitKey(delay) : 이 함수가 없으면 창이 뜨지 않거나 멈춥니다.
delay
밀리초(ms) 단위 대기 시간입니다.
1: 1ms만 대기하고 다음 코드로 넘어감 (동영상/카메라용).
0: 키를 누를 때까지 무한 대기 (정지 영상용).
리턴값
눌린 키의 아스키 코드 값입니다.
- cap.release() : 프로그램이 끝날 때 카메라 장치 사용 권한을 운영체제에 반환해야 합니다. 그렇지 않으면 다른 프로그램(Zoom, Skype 등)에서 카메라를 쓰지 못할 수 있습니다.
실습 과제
- 기초: 위 코드를 실행하여 자기 얼굴 띄우기.
- 응용 1 (좌우 반전): 거울처럼 보이게 cv2.flip(frame, 1) 적용해보기.
- 응용 2 (필터 적용): cv2.cvtColor를 이용해 흑백(Grayscale) 영상으로 송출하기.
- 응용 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)주요 함수 설명
cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) : 사람의 눈이 색을 인지하는 방식과 비슷하게 데이터를 바꾸는 과정입니다. 이 줄이 없으면 파란색 인식이 매우 불안정해집니다.
cv2.inRange(src, lower, upper) : 이미지를 이진화(Binarization) 합니다.
lower ~ upper
사이의 값은 255(흰색), 범위 밖은 0(검은색)으로 바꿉니다. 결과물인 mask는 흑백 이미지가 됩니다. 흰색 영역이 우리가 찾은 "파란색 물체"의 위치입니다.
- 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)

주요 함수 설명
- cv2.findContours(image, mode, method) : 마스크 이미지(흑백)에서 흰색 영역의 경계선을 찾습니다.
파라미터 설명
image: 반드시 이진화(흑백)된 이미지여야 합니다. (mask)mode: cv2.RETR_EXTERNAL을 쓰면 물체 안에 있는 구멍(도넛 모양의 내부)은 무시하고, 가장 바깥 테두리만 찾습니다.
리턴값
contours는 외곽선 좌표들의 리스트(List)입니다.
- cv2.contourArea(cnt) : 찾아낸 외곽선이 차지하는 면적(픽셀 수)을 계산합니다.
왜 필요한가요?
화면에 먼지 같은 파란색 점이 찍혀도 컴퓨터는 인식합니다. 이런 노이즈를 제거하기 위해 "면적이 500 이상인 것만 그려라"라는 조건문(if area > MIN_AREA)을 사용합니다.
- cv2.boundingRect(cnt) : 외곽선(cnt)을 감싸는 가장 작은 똑바른 사각형을 구합니다.
리턴값
x (왼쪽 위 가로), y (왼쪽 위 세로), w (폭), h (높이)
- cv2.rectangle(img, pt1, pt2, color, thickness) : 이미지에 사각형을 그립니다.
파라미터 설명
img: 사각형을 그릴 이미지입니다.pt1: 시작점 (x, y)pt2: 끝점 (x + w, y + h)color: 사각형의 색상입니다. (B, G, R) 형식의 튜플이나 스칼라 값으로 지정할 수 있습니다.thickness: 선택적으로 사각형의 선 두께를 지정합니다. 음수 값을 전달하면 내부를 채웁니다.
실습 과제
기초: 가장 큰 물체 하나만 잡기 지금 코드는 파란색 물체가 3개 있으면 박스도 3개가 생깁니다. 화면에 파란색이 여러 개 있어도, 가장 큰 물체 1개에만 박스를 그리도록 코드를 수정해보세요. 힌트: contours 리스트를 반복문 돌기 전에 max() 함수나 정렬을 이용해 면적이 제일 큰 녀석을 찾으세요.
응용 1: 물체의 중심점 찍기 박스 중심에 빨간 점을 찍어보세요. 중심 좌표 공식: center_x = x + w // 2, center_y = y + h // 2
응용 2: 컵/펜 추적하기 파란색 컵이나 파란색 뚜껑 펜을 준비해서 카메라 앞에서 흔들어보며 박스가 잘 따라오는지 테스트해보세요. MIN_AREA 값을 조절해가며 최적의 값을 찾아보세요.