首页 > 代码库 > OpenCV2马拉松第11圈——meanshift与直方图反向投影
OpenCV2马拉松第11圈——meanshift与直方图反向投影
收入囊中
- meanshift图像聚类
- meanshift object detect
葵花宝典
今天有点累,理论就讲少点吧T_T
meanshift中文是均值飘逸,就是给定一个点,然后会移动到概率密度最大的地方。
对于图像,什么是概率密度最大?
我们可以定义很多要素:
距离
RGB
HSV
下面我有个例子,就是用距离(x,y)和HSV(h,s,v)作图像聚类的。
于是我们有5个要素,当前点与其他点的距离,HSV越接近,则概率密度越高。
假定我们有一点(m,n),如何选择下一个点呢,如何在一个矩形中找到概率密度最高的那个点?
top,down,left,right是我们选的矩形,(m,n)是中心
for(s=top;s<=down;s++){ for(t=left;t<=right;t++) { ws=(s-m)*(s-m)+(t-n)*(t-n);//spatial information ws/=(hs*hs); ws=exp(-ws); wr=(data[s*step+t*channels]-data[m*step+n*channels])*(data[s*step+t*channels]-data[m*step+n*channels]); wr+=(data[s*step+t*channels+1]-data[m*step+n*channels+1])*(data[s*step+t*channels+1]-data[m*step+n*channels+1]); wr+=(data[s*step+t*channels+2]-data[m*step+n*channels+2])*(data[s*step+t*channels+2]-data[m*step+n*channels+2]); wr/=(hr*hr); if(wr>1) wr=0.; else wr=exp(-wr); sumw+=wr*ws; for(k=0;k<5;k++)//try y[1][k]+=oridata[s*width+t][k]*wr*ws; } } for(k=0;k<5;k++) //try y[1][k]/=sumw; //下一个要到的点 m=(int)(y[1][0]+0.5); n=(int)(y[1][1]+0.5);假设我们有了反向投影图,再用meanshift,不就能找到图像中最接近当前区域的位置了么~~
图像聚类
用meanshift可以实现图像聚类,因为本次重点是mean shift与back project的结合,所以关于聚类我就直接贴上代码了
用meanshift可以实现图像聚类,因为本次重点是mean shift与back project的结合,所以关于聚类我就直接贴上代码了
算法超级easy,就是循环图像,对点作mean shift,每个点最大迭代100次,一直到点不动(收敛)为止,然后用vector记录下移动过程,将收敛点的颜色赋值给这些点,并记录哪些点已经赋值过了,下次就不用循环直接continue.
hs,hr是寻找的矩形大小,比EPSLON小就收敛。
note:是用x,y和HSV
//#include <stdafx.h> #include <cxcore.h> #include <cv.h> #include <highgui.h> #include <stdio.h> #include <vector> #include <utility> using namespace cv; using namespace std; #define hs 25 #define hr 25 #define maxstep 100 #define EPSLON 0.01 #define width 1920 #define height 1080 float oridata[height*width][5];//try int visited[height][width]; int main(int argc,char **argv) { IplImage *oriImg,*luvImg,*fltImg,*afterImg; char *filename = argv[1]; oriImg=cvLoadImage(filename,1); if(!oriImg){ printf("cannot load the file.\n"); return -1; } luvImg=cvCreateImage(cvSize(width,height),oriImg->depth,oriImg->nChannels); fltImg=cvCreateImage(cvSize(width,height),oriImg->depth,oriImg->nChannels); afterImg=cvCreateImage(cvSize(width,height),oriImg->depth,oriImg->nChannels); cvCvtColor(oriImg,luvImg,CV_RGB2Luv); uchar *data,*newdata; int channels, step,depth; depth=luvImg->depth; step=luvImg->widthStep; channels=luvImg->nChannels; data=http://www.mamicode.com/(uchar *) luvImg->imageData;>
初识API
- C++: int meanShift(InputArray probImage, Rect& window, TermCriteria criteria)
- probImage – 反向投影矩阵
- window – 一开始的窗口,就是自己用矩形圈起来的地方
- criteria – Stop criteria for the iterative search algorithm.
TermCriteria::TermCriteria
The constructors.
- C++: TermCriteria::TermCriteria()
- C++: TermCriteria::TermCriteria(int type, int maxCount, double epsilon)
- C++: TermCriteria::TermCriteria(const CvTermCriteria& criteria)
- type – The type of termination criteria: TermCriteria::COUNT, TermCriteria::EPS or TermCriteria::COUNT +TermCriteria::EPS.
- maxCount – The maximum number of iterations or elements to compute.
- epsilon – The desired accuracy or change in parameters at which the iterative algorithm stops.
- criteria – Termination criteria in the deprecated CvTermCriteria format.
举个例子:假设我们对(110,260)坐标处宽35长40的方框感兴趣,最大迭代10次,差值(精确度)为0.01
result是我们的反向投影矩阵,那就可以如下调用
Rect rect(110,260,35,40);
TermCriteria criteria(TermCriteria::MAX_ITER,10,0.01);
meanShift(result,rect,criteria);
TermCriteria criteria(TermCriteria::MAX_ITER,10,0.01);
meanShift(result,rect,criteria);
荷枪实弹
下面我附上完整代码,并有详细注释
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/video/tracking.hpp" #include <iostream> using namespace cv; using namespace std; class ColorHistogram { private: int histSize[3]; float hranges[2]; const float* ranges[3]; int channels[3]; public: ColorHistogram() { // Prepare arguments for a color histogram histSize[0]= histSize[1]= histSize[2]= 256; hranges[0]= 0.0; // BRG range hranges[1]= 255.0; ranges[0]= hranges; // all channels have the same range ranges[1]= hranges; ranges[2]= hranges; channels[0]= 0; // the three channels channels[1]= 1; channels[2]= 2; } //这里获取HSV的第一个通道的直方图 Mat getHueHistogram(const cv::Mat &image,int minSaturation=0) { Mat hist; //色彩空间转换 Mat hsv; cvtColor(image, hsv, CV_BGR2HSV); // mask,要注意哦 Mat mask; if (minSaturation>0) { // 三通道分开 vector<Mat> v; split(hsv,v); // 去除低饱和的值 threshold(v[1],mask,minSaturation,255,THRESH_BINARY); } hranges[0]= 0.0; //hue的range是[0,180] hranges[1]= 180.0; channels[0]= 0;calcHist(&hsv,1,channels,mask,hist,1,histSize,ranges);//注意,mask不为0的地方计算在内,也就是高饱和的Hue计算在内 return hist; } }; class ContentFinder { private: float hranges[2]; const float* ranges[3]; int channels[3]; float threshold; Mat histogram; public: ContentFinder() : threshold(-1.0f) { hranges[0]= 0.0; // range [0,255] hranges[1]= 255.0; channels[0]= 0; // the three channels channels[1]= 1; channels[2]= 2; ranges[0]= hranges; // all channels have same range ranges[1]= hranges; ranges[2]= hranges; } // Sets the reference histogram void setHistogram(const Mat& h) { histogram= h; normalize(histogram,histogram,1.0); } cv::Mat find(const cv::Mat& image, float minValue, float maxValue, int *channels, int dim) { cv::Mat result; hranges[0]= minValue; hranges[1]= maxValue; ranges[0]= hranges; // all channels have same range ranges[1]= hranges; ranges[2]= hranges; calcBackProject(&image,1,channels,histogram,result,ranges,255.0); return result; } }; int main( int, char** argv ) { Mat image= cv::imread("baboon1.jpg"); // Baboon‘s face ROI Mat imageROI= image(cv::Rect(110,260,35,40)); // 获得Hue直方图 int minSat=65; ColorHistogram hc; Mat colorhist = hc.getHueHistogram(imageROI,minSat); ContentFinder finder; finder.setHistogram(colorhist); image= cv::imread("baboon3.jpg"); // 色彩空间转换 Mat hsv; cvtColor(image, hsv, CV_BGR2HSV); vector<Mat> v; split(hsv,v); //除去低饱和度 threshold(v[1],v[1],minSat,255,cv::THRESH_BINARY); // 获得反向投影 int ch[1]={0}; Mat result= finder.find(hsv,0.0f,180.0f,ch,1); // 除去低饱和度的点 bitwise_and(result,v[1],result); Rect rect(110,260,35,40); rectangle(image, rect, Scalar(0,0,255)); TermCriteria criteria(TermCriteria::MAX_ITER,10,0.01); meanShift(result,rect,criteria); rectangle(image, rect, cv::Scalar(0,255,0)); namedWindow("result"); imshow("result",image); waitKey(0); return 0; }
看下效果
举一反三
camshift算法是对meanshift算法的改进,它先用mean shift找到物体,再调整窗的大小,然后可以旋转窗找到最合适的旋转角度
计算机视觉讨论群:162501053
转载请注明:http://blog.csdn.net/abcd1992719g
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。