标签:
VS2010UltimTrial1.iso
http://pan.baidu.com/s/1dEL85kl
VS2010UltimTrialCHS版注册码 YCFHQ-9DWCY-DKV88-T2TMH-G7BHP
opencv-2.4.9.exe
http://pan.baidu.com/s/1kVaVwoR
图片地址: f:\img\
操作系统: xp sp3
运行在虚拟机中 VM10.0.3 build-1895310
http://pan.baidu.com/s/1dEQsno1
VMKEY 5F29M-48312-8ZDF9-A8A5K-2AM0Z
1Y0W5-0W205-7Z8J0-C8C5M-9A6MF
#include <opencv2\highgui\highgui.hpp> #include <iostream> using namespace cv; using namespace std; int main(int argc, const char** argv) { Mat img = imread("f:\\img\\lena.jpg"); if (img.empty()) { cout << "图像加载失败!" << endl; return -1; } //创建一个名字为MyWindow的窗口 namedWindow("MyWindow", CV_WINDOW_AUTOSIZE); //在MyWindow的窗中中显示存储在img中的图片 imshow("MyWindow", img); //等待直到有键按下 waitKey(0); //销毁MyWindow的窗口 destroyWindow("MyWindow"); return 0; }
#include <opencv2\opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main(int argc, char* argv[]) { Mat src = imread("f:\\img\\QQ.png"); Mat dst; //输入图像 //输出图像 //输入图像颜色通道数 //x方向阶数 //y方向阶数 Sobel(src,dst,src.depth(),1,1); imwrite("sobel.jpg",dst); imshow("sobel",dst); imshow("src",src); //输入图像 //输出图像 //输入图像颜色通道数 Laplacian(src,dst,src.depth()); imwrite("laplacian.jpg",dst); imshow("laplacian",dst); //输入图像 //输出图像 //彩色转灰度 cvtColor(src,src,CV_BGR2GRAY); //canny只处理灰度图 //输入图像 //输出图像 //低阈值 //高阈值,opencv建议是低阈值的3倍 //内部sobel滤波器大小 Canny(src,dst,50,150,3); imwrite("canny.jpg",dst); imshow("canny",dst); waitKey(); return 0; }
#include <opencv2\opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main() { const char* inputImage = "f:\\img\\circle.jpg"; Mat img; int threshval =100; img = imread(inputImage,0); if (img.empty()) { cout << "Could not read input image file: " << inputImage << endl; return -1; } img = img >110; //namedWindow("Img", 1); imshow("Img", img); vector<vector<Point> > contours; vector<Vec4i>hierarchy; Mat dst = Mat::zeros(img.rows, img.cols, CV_8UC3); findContours(img, contours,hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); if( !contours.empty() && !hierarchy.empty() ) { int idx = 0; for( ; idx >= 0; idx = hierarchy[idx][0] ) { Scalar color( (rand()&255), (rand()&255), (rand()&255) ); drawContours( dst, contours, idx, color, 1, 8, hierarchy ); } } //namedWindow("Connected Components", 1); imshow( "Connected Components", dst ); waitKey(0); return 0; }
findContours函数,这个函数的原型为:
void findContours(InputOutputArray image, OutputArrayOfArrayscontours, OutputArray hierar-
chy, int mode, int method, Point offset=Point())
参数说明
输入图像image必须为一个2值单通道图像
contours参数为检测的轮廓数组,每一个轮廓用一个point类型的vector表示
hiararchy参数和轮廓个数相同,每个轮廓contours[ i ]对应4个hierarchy元素hierarchy[ i ][0 ] ~hierarchy[ i ][ 3],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,该值设置为负数。
mode表示轮廓的检索模式
CV_RETR_EXTERNAL表示只检测外轮廓
CV_RETR_LIST检测的轮廓不建立等级关系
CV_RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
CV_RETR_TREE建立一个等级树结构的轮廓。具体参考contours.c这个demo
method为轮廓的近似办法
CV_CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
CV_CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain近似算法
offset表示代表轮廓点的偏移量,可以设置为任意值。对ROI图像中找出的轮廓,并要在整个图像中进行分析时,这个参数还是很有用的。
findContours后会对输入的2值图像改变,所以如果不想改变该2值图像,需创建新mat来存放,findContours后的轮廓信息contours可能过于复杂不平滑,可以用approxPolyDP函数对该多边形曲线做适当近似
contourArea函数可以得到当前轮廓包含区域的大小,方便轮廓的筛选
#include <opencv2\opencv.hpp> #include <iostream> using namespace cv; using namespace std; #include <math.h> #define PI 3.14159265358979 int main(int argc, char *argv[]) { cv::Mat image = cv::imread("f:\\img\\line.png"); //resize(image,image,Size(image.rows/2, image.cols/2),0,0,CV_INTER_LINEAR); cv::Mat contours; cv::cvtColor(image, contours, cv::COLOR_BGR2GRAY); cv::bitwise_not(contours, contours); //cv::Canny(image, contours, 155, 350); std::vector<cv::Vec2f> lines; cv::HoughLines(contours, lines, 1, PI/180, 180); //cv::imshow("cany",contours ); std::vector<cv::Vec2f>::const_iterator it= lines.begin(); Mat dst = Mat::zeros(image.rows, image.cols, CV_8UC3); while (it!=lines.end()) { float rho= (*it)[0]; // first element is distance rho float theta= (*it)[1]; // second element is angle theta if (theta < PI/4. || theta > 3.*PI/4.)// ~vertical line { // point of intersection of the line with first row cv::Point pt1(rho/cos(theta), 0); // point of intersection of the line with last row cv::Point pt2((rho - image.rows * sin(theta))/cos(theta), image.rows); // draw a white line cv::line( dst, pt1, pt2, cv::Scalar(255), 1); } else { // ~horizontal line // point of intersection of the // line with first column cv::Point pt1(0,rho/sin(theta)); // point of intersection of the line with last column cv::Point pt2(image.cols, (rho - image.cols * cos(theta))/sin(theta)); // draw a white line cv::line(dst, pt1, pt2, cv::Scalar(255), 1); } ++it; } cv::imshow("src", image); cv::imshow("dst", dst); waitKey(0); return 0; }
#include <opencv2\opencv.hpp> #include <iostream> using namespace cv; using namespace std; #include <math.h> #define PI 3.14159265358979 class LineFinder { private: cv::Mat img; // original image std::vector<cv::Vec4i> lines; double deltaRho; double deltaTheta; int minVote; double minLength; // min length for a line double maxGap; // max allowed gap along the line public: // Default accumulator resolution is 1 pixel by 1 degree // no gap, no mimimum length LineFinder() : deltaRho(1), deltaTheta(PI/180), minVote(10), minLength(0.), maxGap(0.) {} // Set the resolution of the accumulator void setAccResolution(double dRho, double dTheta) { deltaRho= dRho; deltaTheta= dTheta; } // Set the minimum number of votes void setMinVote(int minv) { minVote= minv; } // Set line length and gap void setLineLengthAndGap(double length, double gap) { minLength= length; maxGap= gap; } // Apply probabilistic Hough Transform std::vector<cv::Vec4i> findLines(cv::Mat& binary) { lines.clear(); cv::HoughLinesP(binary, lines, deltaRho, deltaTheta, minVote, minLength, maxGap); return lines; } // Draw the detected lines on an image void drawDetectedLines(cv::Mat &image, cv::Scalar color = cv::Scalar(255, 255, 255)) { // Draw the lines std::vector<cv::Vec4i>::const_iterator it2 = lines.begin(); while (it2 != lines.end()) { cv::Point pt1((*it2)[0],(*it2)[1]); cv::Point pt2((*it2)[2],(*it2)[3]); cv::line( image, pt1, pt2, color, 2); ++it2; } } }; int main(int argc, char *argv[]) { cv::Mat image = cv::imread("f:\\img\\line.png"); cv::Mat contours; cv::cvtColor(image, contours, cv::COLOR_BGR2GRAY); cv::bitwise_not(contours, contours); //cv::Canny(image, contours, 155, 350); LineFinder finder; // Set probabilistic Hough parameters finder.setLineLengthAndGap(100, 20); finder.setMinVote(80); // Detect lines and draw them std::vector<cv::Vec4i> lines = finder.findLines(contours); finder.drawDetectedLines(image, cv::Scalar(0, 0, 255)); //cv::namedWindow("Detected Lines with HoughP"); cv::imshow("Detected Lines with HoughP",image); waitKey(0); }
膨胀就是大了一圈 腐蚀就是小了一圈
#include <opencv2/opencv.hpp> using namespace cv; using namespace std; int main(int argc, char *argv[]) { Mat src, erode_dst, dilate_dst; src = imread("f:\\img\\erode.png"); if (!src.data) { cout<<"Read image failure."<<endl; return -1; } erode(src, erode_dst, cv::Mat()); dilate(src, dilate_dst, cv::Mat()); namedWindow("src"); namedWindow("erode"); namedWindow("dilate"); imshow("src",src); imshow("erode",erode_dst); imshow("dilate",dilate_dst); waitKey(0); return 0; }
//main文件 #include <opencv2/opencv.hpp> using namespace cv; using namespace std; #include "Histogram.h" int main(){ cv::Mat image = cv::imread("f:\\Img\\Lena.jpg"); Histogram h; cv::namedWindow("Red"); cv::namedWindow("Blue"); cv::namedWindow("Green"); cv::namedWindow("Original"); cv::imshow("Original",image); cv::imshow("Red",h.getHistogramImage(image,2)); cv::imshow("Green",h.getHistogramImage(image,1)); cv::imshow("Blue",h.getHistogramImage(image)); cv::waitKey(0); return 0; }
Histogram cpp文件
#include "Histogram.h" Histogram::Histogram() { histSize[0] = 256; hrangee[0] = 0.0; hrangee[1] = 255.0; ranges[0] = hrangee; channels[0] = 0; } cv::Mat Histogram::getHistogram(const cv::Mat& image){ cv::MatND hist; cv::calcHist(&image, 1, channels, cv::Mat(), hist, 1, histSize, ranges); return hist; } cv::Mat Histogram::getHistogramImage(const cv::Mat& image, int channel){ std::vector<cv::Mat> planes; cv::split(image,planes); cv::Scalar color; if(planes.size() == 1){ channel = 0; color = cv::Scalar(0,0,0); }else{ color = cv::Scalar(channel==0?255:0, channel==1?255:0, channel==2?255:0); } cv::MatND hist = getHistogram(planes[channel]); double maxVal = 0; double minVal = 0; cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0); cv::Mat histImg(histSize[0], histSize[0], CV_8UC3, cv::Scalar(255,255,255)); int hpt = static_cast<int>(0.9*histSize[0]); for(int h=0; h<histSize[0]-1; h++){ float binVal = hist.at<float>(h); float binVal2 = hist.at<float>(h+1); int intensity = static_cast<int>(binVal*hpt/maxVal); int intensity2 = static_cast<int>(binVal2*hpt/maxVal); cv::line(histImg, cv::Point(h,histSize[0]-intensity), cv::Point(h,histSize[0]-intensity2), color); } return histImg; }Histogram头文件
#ifndef HISTOGRAM_H_ #define HISTOGRAM_H_ #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <iostream> #include <vector> class Histogram { private: int histSize[1]; float hrangee[2]; const float* ranges[1]; int channels[1]; protected: cv::Mat getHistogram(const cv::Mat&); public: Histogram(); cv::Mat getHistogramImage(const cv::Mat&, int channel = 0); }; #endif /* HISTOGRAM_H_ */
#include <opencv2/opencv.hpp> using namespace cv; using namespace std; int main(){ Mat mat = imread("f:\\img\\changhong.jpg"); Mat mergeImg;//合并后的图像 //用来存储各通道图片的向量 vector<Mat> splitBGR(mat.channels()); //分割通道,存储到splitBGR中 split(mat,splitBGR); //对各个通道分别进行直方图均衡化 for(int i=0; i<mat.channels(); i++) equalizeHist(splitBGR[i],splitBGR[i]); //合并通道 merge(splitBGR,mergeImg); imshow("src",mat); imshow("hist",mergeImg); cv::waitKey(0); return 0; }
我们先来看看原图的直方图
我们发现高亮区域的像素点很少,主要像素点集中在中低亮度区域
我们先设置一个阈值,也就是图中的那根粉色的线,
当某一亮度值的像素点的个数低于这个值时,我们认为这些像素点是无关紧要的。
灰度图的亮度值范围是0-255,若亮度值为1的像素点的个数低于阈值,我们可简单的把亮度为1的像素点的亮度
全设为0,同理,我们从高往低找,若亮度值为254的像素点的个数低于阈值,我们可以把这些像素点的亮度设为255
这样我们可以从小到大,从大到小分别找到两个亮度,它们的像素点的个数恰大于阈值
他们之间的区域,我们可以认为是有效区域,也就是蓝色框出来的区域
我们把这一区域扩展到0-255的区域去,可实现均衡化效果
编程实现为
cv::Mat Histogram::stretch1(const cv::Mat& image, int minValue) { cv::MatND hist = getHistogram(image); int imin =0; for (; imin < histSize[0]; imin++) { if (hist.at<float>(imin) > minValue) { break; } } int imax = histSize[0] -1; for (; imax >=0; imax--) { if (hist.at<float>(imax) > minValue) { break; } } cv::Mat lookup(cv::Size(1, 256), CV_8U); for (int i =0; i <256; i++) { if (i < imin) { lookup.at<uchar>(i) =0; } elseif (i > imax) { lookup.at<uchar>(i) =255; } else { lookup.at<uchar>(i) = static_cast<uchar>(255.0* (i - imin) / (imax - imin) +0.5);} } cv::Mat result; cv::LUT(image, lookup, result); return result; }
对于cv::LUT函数,我之前就介绍过了
可以看出拉伸后的直方图和原直方图形状是一致的
再来看看另一种直方图均衡化的思路
理想的直方图均衡化效果是希望每个亮度的像素点的个数都相同
我们设原亮度为 i 的点均衡化后亮度为S(i),原亮度为 i 的点的个数为N(i)
其占总像素点的概率为p(i) = N(i) / SUM; SUM为像素点的总和
可以得到公式
S(0) = p(0)*255
S(1) = [p(0)+p(1)]*255
S(2) = [p(0)+p(1)+p(2)]*255
........
S(255) = [p(0)+p(1)+......+p(255)]*255 = 255
我们在原图中将亮度为 i 的像素点赋值为 S(i),就可以实现均衡化了
cv::Mat Histogram::stretch2(const cv::Mat& image) { cv::MatND hist = getHistogram(image); float scale[256]; float lookupF[256]; cv::Mat lookup(cv::Size(1, 256), CV_8U); int pixNum = image.cols * image.rows; for (int i =0; i <256; i++) { scale[i] = hist.at<float>(i) / pixNum *255; if (i ==0) { lookupF[i] = scale[i]; } else { lookupF[i] = lookupF[i -1] + scale[i]; } } for (int i =0; i <256; i++) { lookup.at<uchar>(i) = static_cast<uchar>(lookupF[i]); } cv::Mat result; cv::LUT(image, lookup, result); return result; } cv::Mat Histogram::stretch3(const cv::Mat& image) { cv::Mat result; cv::equalizeHist(image, result); return result; }
在这里,我们定义了两个函数,一个按照刚才的思路来实现
另一个是OpenCV2 提供的标准的均衡化函数
我们来看看效果
两种方法得到的效果和直方图的形状几乎一模一样
可见,标准的均衡化方法也是按此思路实现的
具体的源代码就不研究了
#include <opencv2/opencv.hpp> using namespace cv; using namespace std; #include "Histogram1D.h" class ObjectFinder { private: float hranges[2]; const float* ranges[3]; int channels[3]; float threshold; cv::MatND histogram; cv::SparseMat shistogram; public: ObjectFinder() : threshold(0.1f){ ranges[0]= hranges; ranges[1]= hranges; ranges[2]= hranges; } // 设置阈值 void setThreshold(float t) { threshold= t; } // 返回阈值 float getThreshold() { return threshold; } // 设置目标直方图,进行归一化 void setHistogram(const cv::MatND& h) { histogram= h; cv::normalize(histogram,histogram,1.0); } // 查找属于目标直方图概率的像素 cv::Mat find(const cv::Mat& image) { cv::Mat result; hranges[0]= 0.0; hranges[1]= 255.0; channels[0]= 0; channels[1]= 1; channels[2]= 2; cv::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; } }; int main() { //读取圆图像 cv::Mat initimage= cv::imread("f:\\img\\skin.jpg"); if (!initimage.data) return 0; //显示原图像 cv::namedWindow("原图像"); cv::imshow("原图像",initimage); //读取灰度图像 cv::Mat image= cv::imread("f:\\img\\skin.jpg",0); if (!image.data) return 0; //设置目标区域 cv::Mat imageROI; imageROI= image(cv::Rect(262,151,113,150)); // 区域为小孩的脸部区域 //显示目标区域 cv::namedWindow("目标区域图像"); cv::imshow("目标区域图像",imageROI); //计算目标区域直方图 Histogram1D h; cv::MatND hist= h.getHistogram(imageROI); cv::namedWindow("目标区域直方图"); cv::imshow("目标区域直方图",h.getHistogramImage(imageROI)); //创建检查类 ObjectFinder finder; //将目标区域直方图传入检测类 finder.setHistogram(hist); //初始化阈值 finder.setThreshold(-1.0f); //进行反投影 cv::Mat result1; result1= finder.find(image); //创建负图像并显示概率结果 cv::Mat tmp; result1.convertTo(tmp,CV_8U,-1.0,255.0); cv::namedWindow("负图像概率结果图像越暗概率越大"); cv::imshow("负图像概率结果图像越暗概率越大",tmp); //得到二值反投影图像 finder.setThreshold(0.01f); result1= finder.find(image); //在图像中绘制选中区域 cv::rectangle(image,cv::Rect(262,151,113,150),cv::Scalar(0,0,0)); //显示原图像 cv::namedWindow("原图像的灰度图"); cv::imshow("原图像的灰度图",image); //二值结果图 cv::namedWindow("二值结果图"); cv::imshow("二值结果图",result1); cv::waitKey(); return 0; }
Histogram1D.h
#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
#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
结果
标签:
原文地址:http://blog.csdn.net/q123456789098/article/details/51073746