반응형

 

 

간단히 Meanshift  이론을 설명하고 webcam과 video 영상에 ROI를 지정하여 동작하도록 C++로 작성된 Meanshift 예제 코드를 동작시켜 봅니다. 

  

2019. 7. 2

2019. 7. 29 히스토그램생성시 Hue만 사용하도록 수정

 

 

 

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;


// 아래 줄을 주석처리하면 비디오 영상에 대해 동작 
//#define WEBCAM 



bool mouse_is_pressing = false;
int start_x, start_y, end_x, end_y;
int step = 0;
Mat img_color;
Rect roi;


void swap(int* v1, int* v2) {
	int temp = *v1;
	*v1 = *v2;
	*v2 = temp;
}


void mouse_callback(int event, int x, int y, int flags, void* userdata)
{
	Mat img_result = img_color.clone();


	if (event == EVENT_LBUTTONDOWN) {
		step = 1;

		mouse_is_pressing = true;
		start_x = x;
		start_y = y;



	}
	else if (event == EVENT_MOUSEMOVE) {

		if (mouse_is_pressing) {

			end_x = x;
			end_y = y;

			step = 2;
		}

	}
	else if (event == EVENT_LBUTTONUP) {

		mouse_is_pressing = false;

		end_x = x;
		end_y = y;

		step = 3;
	}
}


int main()
{
	Mat img_hsv, img_mask, img_ROI;
	Mat objectHistogram;


	int channels[] = { 0 };
	int hsize[] = { 64};
	float range1[] = { 0, 180 };
	const float* histRange[] = { range1 };


#ifdef WEBCAM 
	VideoCapture cap(0);
#else
	VideoCapture cap("note.mp4");
#endif

	if (!cap.isOpened()) {
		cerr << "video 에러 - 카메라 또는 영상을 열 수 없습니다.\n";
		return -1;
	}

	namedWindow("Color", 1);
	setMouseCallback("Color", mouse_callback);

#ifndef WEBCAM
	Mat img_sceen;
	cap.read(img_sceen);
#endif


	while (1)
	{

#ifdef WEBCAM
		cap.read(img_color);
#else
		if (step == 4)
			cap.read(img_color);
		else
			img_sceen.copyTo(img_color);
#endif

		if (img_color.empty()) {
			cerr << "빈 영상이 캡쳐되었습니다.\n";
			break;
		}

		switch (step)
		{

		case 1:
			circle(img_color, Point(start_x, start_y), 10, Scalar(0, 255, 0), -1);

			break;

		case 2:
			rectangle(img_color, Point(start_x, start_y), Point(end_x, end_y), Scalar(0, 255, 0), 3);

			break;

		case 3:

			if (start_x > end_x) {
				swap(&start_x, &end_x);
				swap(&start_y, &end_y);
			}

			roi = Rect(start_x, start_y, end_x - start_x, end_y - start_y);
			cvtColor(img_color, img_hsv, COLOR_BGR2HSV);
			img_ROI = Mat(img_hsv, roi);

			inRange(img_ROI, Scalar(0., 60., 60.), Scalar(180., 255., 255.), img_mask);

			imshow("ROI", img_ROI);

			calcHist(&img_ROI, 1, channels, img_mask, objectHistogram, 1, hsize, histRange);
			normalize(objectHistogram, objectHistogram, 0, 255, NORM_MINMAX);

			step++;

			break;

		case 4:

			Mat bp;
			cvtColor(img_color, img_hsv, COLOR_BGR2HSV);
			calcBackProject(&img_hsv, 1, channels, objectHistogram, bp, histRange);

			// Tracking
			meanShift(bp, roi, TermCriteria(TermCriteria::EPS | TermCriteria::COUNT, 10, 1));

			rectangle(img_color, roi, Scalar(0, 0, 255), 2);
			break;

		}


		//if (step < 4)
		cout << step << endl;

		imshow("Color", img_color);


		if (waitKey(25) >= 0)
			break;
	}


	return 0;
}

 

반응형

포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
댓글로 알려주시면 빠른 시일내에 답변을 드리겠습니다.

여러분의 응원으로 좋은 컨텐츠가 만들어집니다.
지금 본 내용이 도움이 되었다면 유튜브 구독 부탁드립니다. 감사합니다 : )

유튜브 구독하기


제가 쓴 책도 한번 검토해보세요.

  1. HJ 2019.07.04 23:54

    안녕하세요 항상 잘 보며 공부하고 있는 학생입니다!
    마우스로 관심영역을 정한후 추적하는데 목표가 1개가 아닌 다중으로 추적하려면 어떻게 해야되나요??
    감사합니다

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.07.05 00:30 신고

      상황에 따라 방법이 달라질듯합니다.

      아래 링크를 참고하세요
      https://www.pyimagesearch.com/2018/07/30/opencv-object-tracking/

    • hj 2019.07.05 10:19

      감사합니다~

  2. liberty67 2020.10.02 18:53

    정보 감사합니다!

    추적하고자 하는 물체를 마우스로 관심영역으로 정하고 중심점의 동선을 그리도록 동작하게 할 수도 있을까요??
    이전에 연습했던 https://webnautes.tistory.com/1403?category=756330 예제의 형태와 같습니다.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.10.02 18:56 신고

      중심점 구하는 방법만 다룰뿐 나머진 똑같을듯합니다. 원하는 물체를 정확하게 계속 추적하는 방법에 대한 고민이 필요하겠네요

    • BlogIcon liberty67 2020.10.02 19:03

      ROI의 중심점을 구하기 위해 제가 생각한 방법입니다.
      1. ROI이미지를 마스킹하여 mask 이미지를 구한다.
      2. 마스크 이미지를 모폴로지 연산하고 라벨링하여 중심점을 구한다.

      혹시 틀렸거나 다른 방법이 있나요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.10.02 19:51 신고

      ROI가 이미 구해졌다면 굳이 다른 연산할 필요없이 ROI의 중심점을 수학적 계산으로 구하는게 좋을듯합니다.

    • BlogIcon liberty67 2020.10.02 20:54

      감사합니다.
      중심점을 구하면 소수값이 나옵니다. 소수값을 Point에 넣으면 int형으로 바뀌는데 중심점을 그대로 사용해도 문제가 없을까요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.10.02 21:00 신고

      네 문제없습니다

    • BlogIcon liberty67 2020.10.02 21:51

      항상 빠르게 답변해주셔서 감사합니다.
      처음에 마우스로 roi를 설정하고 이 roi에 맞는 중심점을 구했습니다.
      영상이 재생됨에 따라 roi의 중심점도 계속해서 바뀔것 같습니다.
      roi의 중심점을 계속해서 업데이트 해줘야하는게 맞을까요??

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.10.03 19:31 신고

      meansift를 사용한다면 계산된 roi를 계속 얻을 수 있을 듯합니다.

    • BlogIcon liberty67 2020.10.04 09:14

      아 그런 방법이라면 위 예제에서 case 4에서 중심점을 구하면 될까요??

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.10.04 10:34 신고

    • BlogIcon liberty67 2020.10.04 10:49

      마우스로 처음으로 roi를 지정한 곳의 중심점에 원이 고정되네요. roi는 움직이는데 중심점은 고정된 상태로 움직이지 않는 상황입니다.

      case 4:
      Mat dst;
      cvtColor(img_color, img_hsv, COLOR_BGR2HSV);
      //HistogramBackProjection을 수행하여 img_hsv에서
      //objectHistogram 히스토그램을 갖는 영역을 찾는다.
      calcBackProject(&img_hsv, 1, channels, objectHistogram, dst, histRange);

      //ROI의 중심점
      roi_center_x = start_x + (end_x - start_x) / 2;
      roi_center_y = start_y + (end_y - start_y) / 2;

      //Tracking
      meanShift(dst, roi, TermCriteria(TermCriteria::EPS | TermCriteria::COUNT, 10, 1));

      rectangle(img_color, roi, Scalar(0, 0, 255), 2);
      circle(img_color, Point(roi_center_x, roi_center_y), 5, Scalar(0, 0, 255), 1);
      break;
      }

      이렇게 코드를 짜봤습니다.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.10.04 11:20 신고

      meanShift의 리턴값인 roi를 사용해야 합니다.

      아마 roi는 사각형의 왼쪽 위 포인트의 좌표와 사각형의 너비, 높이일겁니다.

    • BlogIcon liberty67 2020.10.04 11:41

      친절한 답변 감사합니다.

      찾아보니 meanShift 함수가 int형을 리턴한다고 나와있는데 이 값이 roi가 되는 건가요???? roi는 Rect 클래스의 객체인데 아닐 것 같아서 질문 드립니다.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.10.04 12:17 신고

      다음처럼 리턴되는 window 또는 두번째 아규먼트 window로 전달됩니다.

      retval, window = cv.meanShift( probImage, window, criteria )


      포스트에서도 두번째 인자인 roi를 사용하여 rectangle 함수에서 사각형을 그려줍니다.

      meanShift(bp, roi, TermCriteria(TermCriteria::EPS | TermCriteria::COUNT, 10, 1));

      rectangle(img_color, roi, Scalar(0, 0, 255), 2);


    • BlogIcon liberty67 2020.10.04 12:50

      그러면

      int c_x = roi.x;
      int c_y = roi.y;

      와 같이 메서드를 이용해서 roi의 x,y값을 받아올 수 있는 건가요????

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.10.04 13:02 신고

      다음 4가지를 얻을 수 있습니다.

      roi.x
      roi.y
      roi.height
      roi.width

    • BlogIcon liberty67 2020.10.04 16:10

      정말 감사합니다.

  3. jihoon 2020.10.05 17:21

    안녕하세요! 올리신 강의들 정말 잘 보고 있는 학생입니다.

    현재 올라와있는 예제 코드의 경우, 예제 동영상에서 Blue 계통의 무늬를 지닌 노트에 가중치를 주어 따라다니게 하기 위해서

    channel 배열이 {0} , 즉 Blue 로 설정되어있는 것이 맞는지요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.10.05 20:31 신고

      해보지 않아서 어찌 동작할지 모르겠지만
      다음 범위를 파란색 범위로 수정하면 어떨까 싶습니다.

      현재 hue가 0,180으로 되어 있는데(Scalar의 첫번째 항목입니다.)

      파란색 hue가 120이니깐 .. 다음처럼 100, 140으로 바꾸어 보세요.

      inRange(img_ROI, Scalar(100., 60., 60.), Scalar(140., 255., 255.), img_mask);

+ Recent posts