▪Example code
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
struct CallbackParam{
Mat frame; // 프레임을 저장할 구조체
Point pt1, pt2; // 마우스로 클릭한 좌표
Rect roi; // 관심 영역을 나타내는 직사각형
bool drag; // 드래그 중인지 나타내는 플래그
bool updated; // 업데이트가 필요한지 나타내는 플래그
};
// 마우스 이벤트 처리 함수
void onMouse(int event, int x, int y, int flags, void* param){
CallbackParam* p = (CallbackParam*)param;
// 마우스 왼쪽 버튼 클릭 시
if (event == EVENT_LBUTTONDOWN){
p->pt1.x = x;
p->pt1.y = y;
p->pt2 = p->pt1;
p->drag = true;
}
// 마우스 왼쪽 버튼 떼기 시
if (event == EVENT_LBUTTONUP){
int w = x - p->pt1.x;
int h = y - p->pt1.y;
p->roi.x = p->pt1.x;
p->roi.y = p->pt1.y;
p->roi.width = w;
p->roi.height = h;
p->drag = false;
// 너비와 높이가 일정 크기 이상인 경우에만 업데이트
if (w >= 10 && h >= 10){
p->updated = true;
}
}
// 마우스 드래그 중일 때
if (p->drag && event == EVENT_MOUSEMOVE){
if (p->pt2.x != x || p->pt2.y != y){
Mat img = p->frame.clone(); // 정지된 이미지 복사
p->pt2.x = x; // 업데이트
p->pt2.y = y; // 목적 좌표
rectangle(img, p->pt1, p->pt2, Scalar(0, 255, 0), 1);
imshow("트래커", img);
}
}
}
int main(int argc, char *argv[]){
// 웹캠 열기
VideoCapture cap(0);
CallbackParam param;
Mat frame, m_backproj, hsv;
Mat m_model3d;
Rect m_rc;
// HSV 색 공간을 위한 범위 값 설정
float hrange[] = { 0,180 }; // 색상
float srange[] = { 0,255 }; // 채도
float vrange[] = { 0,255 }; // 명도
const float* ranges[] = { hrange, srange, vrange }; // 색상, 채도, 명도
int channels[] = { 0, 1, 2 };
int hist_sizes[] = { 16, 16, 16 };
// 영상 불러오기가 성공했는지 확인
if (!cap.isOpened()){
cout << "비디오 파일을 열 수 없습니다." << endl;
return 0;
}
// 이미지에서 클릭하여 관심 영역 설정
cap >> frame;
imshow("트래커", frame);
param.frame = frame;
param.drag = false;
param.updated = false;
// 마우스 이벤트가 발생하면 onMouse 함수 호출
setMouseCallback("트래커", onMouse, ¶m);
bool tracking = false;
while (true){
// 이미지 취득 및 대상 초기화
if (param.drag){
if (waitKey(33) == 27) break; // ESC 키
continue;
}
// RGB에서 HSV로 이미지 변환
cvtColor(frame, hsv, COLOR_BGR2HSV);
if (param.updated){
m_rc = param.roi;
Mat mask = Mat::zeros(m_rc.height, m_rc.width, CV_8U);
ellipse(mask, Point(m_rc.width/2, m_rc.height/2), Size(m_rc.width/2, m_rc.height/2), 0, 0, 360, 255, CV_FILLED);
Mat roi(hsv, m_rc);
// 히스토그램 계산
calcHist(&roi, 1, channels, mask, m_model3d, 3, hist_sizes, ranges);
}
m_rc = param.roi;
param.updated = false;
tracking = true;
// 웹캠에서 새로운 프레임 얻기
cap >> frame;
if (frame.empty()) break; // 읽을 프레임이 없으면 종료
// 이미지 처리
if (tracking){
// 히스토그램 역투영
// 사용된 인자들은 히스토그램을 계산한 것과 동일함
// 추가로 역투영 매트릭스(m_backproj)가 있음
calcBackProject(&hsv, 1, channels, m_model3d, m_backproj, ranges);
// 트래킹 (meanShift)
// 픽셀 분포가 최대인 창을 얻음
meanShift(m_backproj, m_rc, TermCriteria(TermCriteria::EPS | TermCriteria::COUNT, 10, 1)); // 종료 조건
rectangle(frame, m_rc, Scalar(0, 0, 255), 3);
}
// 이미지 표시
imshow("트래커", frame);
// 사용자 입력
char ch = waitKey(33);
if (ch == 27) break; // ESC 키 (종료)
else if (ch == 32){ // 스페이스바 키 (비디오 일시정지)
// 사용자 입력이 스페이스바 또는 ESC 키가 아니면 프로그램 종료
while ((ch = waitKey(33)) != 32 && ch != 27);
if (ch == 27) break;
}
}
return 0;
}