本文主要是介绍均值漂移(meanshift)算法查找物体,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
均值漂移算法以迭代的方式锁定概率函数的局部最大值,它的原理是寻找预定义窗口中数据点的重心,或者说加权平均值。将窗口重心移动到数据点的重心处,并重复这个过程直到窗口重心收敛到一个稳定点。
反投影直方图的结果是一个概率映射,作用在于替换一个输入图像中的每个像素值,使其变成归一化直方图中对应的概率值,体现了已知图像的特定内容出现在图像中特定位置的概率。
下面一个简单的例子演示如何利用meanshift算法查找物体。
主要步骤:选定ROI,计算并归一化ROI的直方图,根据得到的直方图计算出ROI在色调通道的反投影直方图,代入meanshift算法更新ROI的位置。整个过程使用HSV颜色空间的Hue通道来描述物体。
-
#include"cv.h" -
#include"highgui.h" -
#include <iostream> -
using namespace std; -
using namespace cv; -
Mat image;//最终显示图像 -
Mat histimg = Mat(200, 300, CV_8UC3,Scalar::all(0));//最终显示直方图 -
const char* keys = { -
"{camera|camera num|0|The PC'camera number}" -
}; -
string err_cp = "\n\t\topen camera failed\n\t\t"; -
Point origin;//用于保存鼠标选择第一次单击时点的位置 -
Rect selection;//用于保存鼠标选择的矩形框 -
Rect trackWindow;//追踪的选择区域 -
int trackObject = 0; //代表跟踪目标数目 -
bool selectObject = false;//代表是否在选要跟踪的初始目标,true表示正在用鼠标选择 -
bool showHist = true; -
bool pause = false; -
int * channels = { 0 }; -
float range[2] = { 0, 180 }; -
const float * hranges = range; -
void mousecallback(int event,int x,int y,int flags,void* param){ -
if (selectObject)//只有当鼠标左键按下去时才有效,然后通过if里面代码就可以确定所选择的矩形区域selection了 -
{ -
selection.x = MIN(x, origin.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 CV_EVENT_LBUTTONDOWN: -
origin = Point(x, y); -
selection = Rect(x, y, 0, 0);//鼠标刚按下去时初始化了一个矩形区域 -
selectObject = true; -
break; -
case CV_EVENT_LBUTTONUP: -
selectObject = false; -
trackObject = 0; //代表跟踪目标数目 -
if (selection.width > 0 && selection.height > 0) -
trackObject = -1; -
break; -
} -
} -
void direct(){ -
cout << "\n\n\t图像跟踪程序\n" -
<< "\t\t鼠标左键选择ROI进行跟踪\n" -
<< "\t\tq--退出程序\n" -
<< "\t\th--显示/关闭直方图\n" -
<< "\t\tp--程序暂停\n" -
<< "\t\tc--清除ROI\n"; -
} -
int main(int argc, char** argv){ -
system("color 5E"); -
direct(); -
VideoCapture cp; -
Mat hsv, hue,mask, hist, backproj; -
CommandLineParser parser(argc, argv, keys);//命令解析器函数 -
int cpnum = parser.get<int>("camera"); -
cp.open(cpnum); -
if (!cp.isOpened()){ -
cout << err_cp; -
parser.printParams(); -
system("pause"); -
return -1; -
} -
namedWindow("摄像头扑捉",1); -
Mat frame; -
setMouseCallback("摄像头扑捉",mousecallback); -
int histsize = 16; -
while (1){ -
if (!pause) -
cp >> frame; -
if (frame.empty()) break; -
//rectangle(frame,selection,Scalar(0,0,255),2);//测试鼠标 -
frame.copyTo(image); -
cvtColor(frame,hsv,CV_BGR2HSV); -
//开始追踪处理 -
if (trackObject&&!pause){ -
inRange(hsv,Scalar(0,10,30),Scalar(180,256,256),mask); -
hue.create(hsv.size(),hsv.depth()); -
int ch[] = {0,0}; -
mixChannels(&hsv,1,&hue,1,ch,1); -
//对selection的处理 -
if (trackObject<0){ -
Mat roi(hue, selection), maskroi(mask, selection); -
calcHist(&roi,1,channels,maskroi,hist,1,&histsize,&hranges); -
normalize(hist,hist,0,255,CV_MINMAX); -
histimg = Scalar::all(0); -
Mat color(1,histsize,CV_8UC3);//设定颜色板,显示ROI的Hist -
for (int i = 0; i < histsize; i++){ -
color.at<Vec3b>(i) = Vec3b(saturate_cast<int>(hist.at<float>(i)*180/255), 255, 255);//HSV -
} -
cvtColor(color,color,CV_HSV2BGR); -
//显示ROI的直方图 -
for (int i = 0; i < histsize; i++){ -
int val = saturate_cast<int>( hist.at<float>(i)*histimg.cols/180); -
int w = histimg.rows / histsize; -
rectangle(histimg,Point(i*w,histimg.cols-val),Point((i+1)*w,histimg.cols),Scalar(color.at<Vec3b>(i)),-1); -
} -
trackWindow = selection; -
trackObject = 1; -
} -
calcBackProject(&hue,1,channels,hist,backproj,&hranges); -
backproj &= mask; -
meanShift(backproj,trackWindow,TermCriteria(CV_TERMCRIT_EPS|CV_TERMCRIT_ITER,10,1)); -
rectangle(image, trackWindow, Scalar(0, 0, 255), 2); -
} -
//没有选定矩形区域,只显示视频 -
if (selectObject && selection.width > 0 && selection.height > 0)//鼠标选取时的阴影 -
{ -
//Mat roi(image, selection); -
//bitwise_not(roi, roi);//bitwise_not为将每一个bit位取反 -
rectangle(image, selection, Scalar(0, 0, 255), 2); -
} -
imshow("摄像头扑捉",image); -
if (showHist) { -
namedWindow("ROI直方图", 1); -
imshow("ROI直方图", histimg); -
} -
else -
destroyWindow("ROI直方图"); -
char c=waitKey(33); -
switch (c){ -
case 'q': -
return 0; -
break; -
case 'h': -
showHist = !showHist; -
break; -
case 'p': -
pause = !pause; -
case 'c': -
trackObject = 0; -
histimg = Scalar::all(0); -
break; -
} -
} -
}
运行截图
这篇关于均值漂移(meanshift)算法查找物体的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!