使用均值漂移算法查找物体
#include <opencv2/opencv.hpp> using namespace cv; using namespace std; #include "Histogram1D.h" #include <iostream> #include <vector> #include "ContentFinder.h" #include "colorhistogram.h" int main() { //读取參考图像 cv::Mat image= cv::imread("f:\\img\\ball.jpg"); if (!image.data) return 0; //定义查找物体 cv::Mat imageROI= image(cv::Rect(85,200,64,64)); cv::rectangle(image, cv::Rect(85,200,64,64),cv::Scalar(0,0,255)); //显示參考图像 cv::namedWindow("第一张图片,标记篮球位置"); cv::imshow("第一张图片,标记篮球位置",image); //获得色度直方图 ColorHistogram hc; cv::MatND colorhist= hc.getHueHistogram(imageROI); //读入目标图像 image= cv::imread("f:\\img\\ball2.jpg"); //显示目标图像 cv::namedWindow("第二张图片"); cv::imshow("第二张图片",image); //将RGB图像图像转换为HSV图像 cv::Mat hsv; cv::cvtColor(image, hsv, CV_BGR2HSV); //分离图像通道 vector<cv::Mat> v; cv::split(hsv,v); //消除饱和度较低的像素点 int minSat=65; cv::threshold(v[1],v[1],minSat,255,cv::THRESH_BINARY); cv::namedWindow("第二张图片消除饱和度较低的像素点"); cv::imshow("第二张图片消除饱和度较低的像素点",v[1]); //进行直方图反投影 ContentFinder finder; finder.setHistogram(colorhist); finder.setThreshold(0.3f); int ch[1]={0}; cv::Mat result= finder.find(hsv,0.0f,180.0f,ch,1); cv::namedWindow("第二张图片进行直方图反投影"); cv::imshow("第二张图片进行直方图反投影",result); //利用位运算消除低饱和度像素 cv::bitwise_and(result,v[1],result); cv::namedWindow("第二张图片利用位运算进一步消除低饱和度像素点"); cv::imshow("第二张图片利用位运算进一步消除低饱和度像素点",result); // 得到反投影直方图概率图像 finder.setThreshold(-1.0f); result= finder.find(hsv,0.0f,180.0f,ch,1); cv::bitwise_and(result,v[1],result); cv::namedWindow("第二张图片处理后的二值图像"); cv::imshow("第二张图片处理后的二值图像",result); cv::Rect rect(85,200,64,64); cv::rectangle(image, rect, cv::Scalar(0,0,255)); cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER,10,0.01); cout << "均值漂移迭代次数 = " << cv::meanShift(result,rect,criteria) << endl; cv::rectangle(image, rect, cv::Scalar(0,255,0)); //展示结果图 cv::namedWindow("查找结果,红框为第一幅图中篮球位置,绿框为现位置"); cv::imshow("查找结果,红框为第一幅图中篮球位置,绿框为现位置",image); cv::waitKey(); return 0; }
#if!defined CONTENTFINDER #define CONTENTFINDER #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> using namespace cv; class ContentFinder { private: float hranges[2]; const float* ranges[3]; int channels[3]; float threshold; Mat histogram; public: ContentFinder():threshold(-1.0f) { //所有通道的范围相同 ranges[0] = hranges; ranges[1] = hranges; ranges[2] = hranges; } //设置门限参数[0,1] void setThreshold(float t) { threshold = t; } //获取门限参数 float getThreshold() { return threshold; } //设置参考的直方图 void setHistogram(const Mat& h) { histogram = h; normalize(histogram,histogram,1.0); } //简单的利用反向投影直方图寻找 Mat find(const Mat& image) { Mat result; hranges[0] = 0.0; hranges[1] = 255.0; channels[0] = 0; channels[1] = 1; channels[2] = 2; calcBackProject(&image,1,channels,histogram,result,ranges,255.0); if (threshold>0.0) { cv::threshold(result, result, 255*threshold, 255, cv::THRESH_BINARY); } return result; } //复杂的利用反向投影直方图,增加了一些参数 Mat find(const Mat &image,float minValue,float maxValue,int *channels,int dim) { Mat result; hranges[0] = minValue; hranges[1] = maxValue; for(int i = 0;i < dim;i++) { this->channels[i] = channels[i]; } calcBackProject(&image,1,channels,histogram,result,ranges,255.0); if(threshold >0.0) cv::threshold(result,result, 255*threshold,255,THRESH_BINARY); return result; } }; #endif
#if!defined COLORHISTOGRAM #define COLORHISTOGRAM #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> using namespace cv; class ColorHistogram { private: int histSize[3]; float hranges[2]; const float* ranges[3]; int channels[3]; public: //构造函数 ColorHistogram() { histSize[0]= histSize[1]= histSize[2]= 256; hranges[0] = 0.0; hranges[1] = 255.0; ranges[0] = hranges; ranges[1] = hranges; ranges[2] = hranges; channels[0] = 0; channels[1] = 1; channels[2] = 2; } //计算彩色图像直方图 Mat getHistogram(const Mat& image) { Mat hist; //BGR直方图 hranges[0]= 0.0; hranges[1]= 255.0; channels[0]= 0; channels[1]= 1; channels[2]= 2; //计算 calcHist(&image,1,channels,Mat(),hist,3,histSize,ranges); return hist; } //计算颜色的直方图 Mat getHueHistogram(const Mat &image) { Mat hist; Mat hue; //转换到HSV空间 cvtColor(image,hue,CV_BGR2HSV); //设置1维直方图使用的参数 hranges[0] = 0.0; hranges[1] = 180.0; channels[0] = 0; //计算直方图 calcHist(&hue,1,channels,Mat(),hist,1,histSize,ranges); return hist; } //减少颜色 Mat colorReduce(const Mat &image,int div = 64) { int n = static_cast<int>(log(static_cast<double>(div))/log(2.0)); uchar mask = 0xFF<<n; Mat_<Vec3b>::const_iterator it = image.begin<Vec3b>(); Mat_<Vec3b>::const_iterator itend = image.end<Vec3b>(); //设置输出图像 Mat result(image.rows,image.cols,image.type()); Mat_<Vec3b>::iterator itr = result.begin<Vec3b>(); for(;it != itend;++it,++itr) { (*itr)[0] = ((*it)[0]&mask) + div/2; (*itr)[1] = ((*it)[1]&mask) + div/2; (*itr)[2] = ((*it)[2]&mask) + div/2; } return result; } }; #endif
#if !defined HISTOGRAM #define HISTOGRAM #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <iostream> using namespace std; using namespace cv; class Histogram1D { private: //直方图的点数 int histSize[1]; //直方图的范围 float hranges[2]; //指向该范围的指针 const float* ranges[1]; //通道 int channels[1]; public: //构造函数 Histogram1D() { histSize[0] = 256; hranges[0] = 0.0; hranges[1] = 255.0; ranges[0] = hranges; channels[0] = 0; } Mat getHistogram(const Mat &image) { Mat hist; //计算直方图函数 //参数为:源图像(序列)地址,输入图像的个数,通道数,掩码,输出结果,直方图维数,每一维的大小,每一维的取值范围 calcHist(&image,1,channels,Mat(),hist,1,histSize,ranges); //这个函数虽然有很多参数,但是大多数时候,只会用于灰度图像或者彩色图像 //但是,允许通过指明一个多通道图像使用多幅图像 //第6个参数指明了直方图的维数 return hist; } Mat getHistogramImage(const Mat &image) { //首先计算直方图 Mat hist = getHistogram(image); //获取最大值和最小值 double maxVal = 0; double minVal = 0; //minMaxLoc用来获得最大值和最小值,后面两个参数为最小值和最大值的位置,0代表不需要获取 minMaxLoc(hist,&minVal,&maxVal,0,0); //展示直方图的画板:底色为白色 Mat histImg(histSize[0],histSize[0],CV_8U,Scalar(255)); //将最高点设为bin总数的90% //int hpt = static_cast<int>(0.9*histSize[0]); int hpt = static_cast<int>(histSize[0]); //为每一个bin画一条线 for(int h = 0; h < histSize[0];h++) { float binVal = hist.at<float>(h); int intensity = static_cast<int>(binVal*hpt/maxVal); //int intensity = static_cast<int>(binVal); line(histImg,Point(h,histSize[0]),Point(h,histSize[0]-intensity),Scalar::all(0)); } return histImg; } Mat applyLookUp(const Mat& image,const Mat& lookup) { Mat result; LUT(image,lookup,result); return result; } Mat strech(const Mat &image,int minValue = 0) { //首先计算直方图 Mat hist = getHistogram(image); //左边入口 int imin = 0; for(;imin< histSize[0];imin++) { cout<<hist.at<float>(imin)<<endl; if(hist.at<float>(imin) > minValue) break; } //右边入口 int imax = histSize[0]-1; for(;imax >= 0; imax--) { if(hist.at<float>(imax) > minValue) break; } //创建查找表 int dim(256); Mat lookup(1,&dim,CV_8U); for(int i = 0; i < 256; i++) { if(i < imin) { lookup.at<uchar>(i) = 0; } else if(i > imax) { lookup.at<uchar>(i) = 255; } else { lookup.at<uchar>(i) = static_cast<uchar>(255.0*(i-imin)/(imax-imin)+0.5); } } Mat result; result = applyLookUp(image,lookup); return result; } Mat equalize(const Mat &image) { Mat result; equalizeHist(image,result); return result; } }; #endif
通过直方图比较检索相似图片
CompareHist(),是比较两个统计直方图的分布,总共有四个方法,被定义如下:
#define CV_COMP_CORREL 0
#define CV_COMP_CHISQR 1
#define CV_COMP_INTERSECT2
#define CV_COMP_BHATTACHARYYA3
而这些方法分别为相关系数,卡方,交集法以及在做常态分布比对的Bhattacharyya距离,这些方法都是用来做统计直方图的相似度比较的方法,而且,都是根据统计学的概念,这边就简单的拿来用灰阶统计直方图来比较,而这部份的比较方式,是由图形的色彩结构来着手,下面就简单的用三种情况来分析它们距离比较的方式
#include "opencv2/highgui/highgui.hpp" #include "opencv/cv.hpp" //画直方图用 int HistogramBins = 256; float HistogramRange1[2]={0,255}; float *HistogramRange[1]={&HistogramRange1[0]}; /* * imagefile1: * imagefile2: * method: could be CV_COMP_CHISQR, CV_COMP_BHATTACHARYYA, CV_COMP_CORREL, CV_COMP_INTERSECT */ int CompareHist(const char* imagefile1, const char* imagefile2) { IplImage *image1=cvLoadImage(imagefile1, 0); IplImage *image2=cvLoadImage(imagefile2, 0); CvHistogram *Histogram1 = cvCreateHist(1, &HistogramBins, CV_HIST_ARRAY,HistogramRange); CvHistogram *Histogram2 = cvCreateHist(1, &HistogramBins, CV_HIST_ARRAY,HistogramRange); cvCalcHist(&image1, Histogram1); cvCalcHist(&image2, Histogram2); cvNormalizeHist(Histogram1, 1); cvNormalizeHist(Histogram2, 1); // CV_COMP_CHISQR,CV_COMP_BHATTACHARYYA这两种都可以用来做直方图的比较,值越小,说明图形越相似 printf("CV_COMP_CHISQR : %.4f\n", cvCompareHist(Histogram1, Histogram2, CV_COMP_CHISQR)); printf("CV_COMP_BHATTACHARYYA : %.4f\n", cvCompareHist(Histogram1, Histogram2, CV_COMP_BHATTACHARYYA)); // CV_COMP_CORREL, CV_COMP_INTERSECT这两种直方图的比较,值越大,说明图形越相似 printf("CV_COMP_CORREL : %.4f\n", cvCompareHist(Histogram1, Histogram2, CV_COMP_CORREL)); printf("CV_COMP_INTERSECT : %.4f\n", cvCompareHist(Histogram1, Histogram2, CV_COMP_INTERSECT)); cvReleaseImage(&image1); cvReleaseImage(&image2); cvReleaseHist(&Histogram1); cvReleaseHist(&Histogram2); return 0; } int main(int argc, char* argv[]) { CompareHist(argv[1], argv[2]); //CompareHist("d:\\camera.jpg", "d:\\camera1.jpg"); system("pause"); return 0; }
图1
图2
结果
亮度变换
#include "opencv\\cv.h" #include "opencv\\highgui.h" /* src and dst are grayscale, 8-bit images; Default input value: [low, high] = [0,1]; X-Direction [bottom, top] = [0,1]; Y-Direction gamma ; if adjust successfully, return 0, otherwise, return non-zero. */ int ImageAdjust(IplImage* src, IplImage* dst, double low, double high, // X方向:low and high are the intensities of src double bottom, double top, // Y方向:mapped to bottom and top of dst double gamma ) { if( low<0 && low>1 && high <0 && high>1&& bottom<0 && bottom>1 && top<0 && top>1 && low>high) return -1; double low2 = low*255; double high2 = high*255; double bottom2 = bottom*255; double top2 = top*255; double err_in = high2 - low2; double err_out = top2 - bottom2; int x,y; double val; // intensity transform for( y = 0; y < src->height; y++) { for (x = 0; x < src->width; x++) { val = ((uchar*)(src->imageData + src->widthStep*y))[x]; val = pow((val - low2)/err_in, gamma) * err_out + bottom2; if(val>255) val=255; if(val<0) val=0; // Make sure src is in the range [low,high] ((uchar*)(dst->imageData + dst->widthStep*y))[x] = (uchar) val; } } return 0; } int main( int argc, char** argv ) { IplImage *src = 0, *dst = 0; src=cvLoadImage("f:\\img\\c2.jpg", 0); // force to gray image if(src==0)return 0; cvNamedWindow( "src", 1 ); cvNamedWindow( "result", 1 ); // Image adjust dst = cvCloneImage(src); // 输入参数 [0,0.5] 和 [0.5,1], gamma=1 if( ImageAdjust( src, dst, 0, 0.5, 0.5, 1, 1)!=0) return -1; cvShowImage( "src", src ); cvShowImage( "result", dst ); cvWaitKey(0); cvDestroyWindow("src"); cvDestroyWindow("result"); cvReleaseImage( &src ); cvReleaseImage( &dst ); return 0; }
时间: 2024-11-07 17:47:17