把opencv3自带的camshiftdemo删删改改,就实现了meanshift的目标追踪,比起camshift没有什么实际应用价值。
运行效果和代码:
#include <iostream>
#include "opencv2/opencv.hpp"
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
using namespace cv;
using namespace std;
Mat image;
bool selectObject = false;
int trackObject = 0;
Point origin;
Rect selection;
//鼠标选择函数
static void onMouse(int event, int x, int y, int, void*)
{
if (selectObject)
{
selection.x = MIN(x, origin.x);//选择区域的x坐标选起点与当前点的最小值,保证鼠标不管向右下角还是左上角拉动都正确选择
selection.y = MIN(y, origin.y);
selection.width = std::abs(x - origin.x);
selection.height = std::abs(y - origin.y);
selection &= Rect(0, 0, image.cols, image.rows);//确保所选矩形在图片范围内
}
switch (event)
{
case EVENT_LBUTTONDOWN: //按下鼠标左键,进行赋初值
origin = Point(x, y);
selection = Rect(x, y, 0, 0);
selectObject = true;
break;
case EVENT_LBUTTONUP: //鼠标左键抬起
selectObject = false;
if (selection.width > 0 && selection.height > 0)
trackObject = -1; // 置-1,主程序开始进行meanshift
break;
}
}
int main(int argc, const char** argv) {
VideoCapture cap(0);
Rect trackWindow;
int hsize = 16; //直方图特征子区间bin的数目,分成16个区间
float hranges[] = { 0,180 };//色度 hue 范围
const float* phranges = hranges;
//摄像头未打开的处理方式
if (!cap.isOpened())
{
cout << "***Could not initialize capturing...***\n";
}
namedWindow("meanShift", 0);
namedWindow("Histogram", 0);
setMouseCallback("meanShift", onMouse, 0);
Mat frame,hsv, hue, hist, histimg = Mat::zeros(200, 320, CV_8UC3), backproj;
bool paused = false;
while (true)
{
if (!paused)
{
cap >> frame;
frame.copyTo(image);
cvtColor(image, hsv, COLOR_BGR2HSV);
if (trackObject)
{
int from_to[] = { 0, 0 };
hue.create(hsv.size(), hsv.depth());
mixChannels(&hsv, 1, &hue, 1, from_to, 1);//提取h分量
//画直方图
if (trackObject < 0)
{
Mat roi(hue, selection);
calcHist(&roi, 1, 0, Mat(), hist, 1, &hsize, &phranges);
normalize(hist, hist, 0, 255, NORM_MINMAX); //直方图归一化到0-255
trackWindow = selection;
trackObject = 1; //置1,除非重新框选目标,否则只执行一次
histimg = Scalar::all(0);
int binW = histimg.cols / hsize;//320/16;每个区间可以占用histimg20个列(column)
Mat buf(1, hsize, CV_8UC3);//定义一个缓冲单bin矩阵,1行16列
for (int i = 0; i < hsize; i++)
buf.at<Vec3b>(i) = Vec3b(saturate_cast<uchar>(i*180. / hsize), 255, 255);//Vec3b为3个char值的向量,存放颜色数据
cvtColor(buf, buf, COLOR_HSV2BGR);
for (int i = 0; i < hsize; i++)
{
int val = saturate_cast<int>(hist.at<float>(i)*histimg.rows / 255);//获取直方图高度,根据histimg图像的高换算成0到histimg.rows的值
rectangle(histimg, Point(i*binW, histimg.rows),//画出直方图,左上角坐标,右下角坐标,高度,颜色,大小,线型
Point((i + 1)*binW, histimg.rows - val),//rows-va1是因为矩阵是左上角开始数的,y轴向下,而要画的图是y轴向上
Scalar(buf.at<Vec3b>(i)), -1, 8);
}
}
//进行meanshift
calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
TermCriteria criteria(TermCriteria::EPS | TermCriteria::COUNT, 10, 1);
meanShift(backproj, trackWindow, criteria);
rectangle(image, trackWindow, Scalar(255, 0, 0), 3);
}
}
if (selectObject && selection.width>0 && selection.height > 0)
{
Mat roi(image, selection);
bitwise_not(roi, roi);
}
imshow("meanShift", image);
imshow("Histogram", histimg);
char c = (char)waitKey(10);//等待用户按键
if (c == 27)
break;
}
return 0;
}