天天看点

Opencv2系列学习笔记6(直方图的应用)

前面我讲述了直方图的概念以及如何用opencv实现一维和二维的直方图。详见这两篇blog: Mat 格式:http://blog.csdn.net/lu597203933/article/details/16884409  

cv:http://blog.csdn.net/lu597203933/article/details/14104505 

这次主要想讲点直方图的应用,其中包括使用查找表修改图像的外观、直方图的均衡化、反投影直方图检测特定图像的内容、meanshift算法<均值漂移>跟踪物体和利用图像直方图检索相似图像<可靠性比较低>。

一:使用查找表修改图像的外观

查找表是简单的一对一(或者多对一)函数,定义了如何将像素值转换为新像素值。Opencv的cv::LUT对图像应用查找表以生成新图像。公式为: result[i] = lookup[image[i]].

<1>图像反转

Code:

Main.cpp

[cpp]  view plain  copy  print ?

Opencv2系列学习笔记6(直方图的应用)
Opencv2系列学习笔记6(直方图的应用)
  1.        MatND hist = getHistogram(image);  
  2. int i;  
  3. for(i = 0; i < 256; i++)  
  4. {  
  5.     cout << "Value" << i << ": " << hist.at<float>(i) << endl;  
  6. }  
  7.     namedWindow("image", 0);  
  8.     imshow("image", image);  
  9.     namedWindow("result", 0);  
  10.     imshow("result", result);  
  11.     waitKey(0);  
  12.     return 0;  
  13. }  

Result:

Opencv2系列学习笔记6(直方图的应用)

四:使用meanshift算法<均值漂移>跟踪物体

Meanshift算法的具体介绍可以看我转载的一篇blog:http://blog.csdn.net/lu597203933/article/details/17042331  它就是以迭代的方式锁定概率函数的局部最大值

主要分为这三个步骤:首先需要得到目标的直方图,其次用该直方图对图片进行反投影,后对反投影的图像进行meanshift算法。其中迭代的次数和精度作为收敛的条件。

Code:

[cpp]  view plain  copy  print ?

Opencv2系列学习笔记6(直方图的应用)
Opencv2系列学习笔记6(直方图的应用)
  1. MatND getHueHistogram(Mat &image, int minSaturation = 0)  
  2. {  
  3.     MatND hist;  
  4.     Mat hsvColor;  
  5.     cvtColor(image, hsvColor, CV_BGR2HSV);  
  6.     vector<Mat> hsv;   
  7.     split(hsvColor, hsv);  
  8.     Mat mask;  
  9.     if(minSaturation > 0)  
  10.     {  
  11.         threshold(hsv[1], mask, minSaturation, 255, THRESH_BINARY);  
  12.         int channels[] = {0};  
  13.         int histSize[] = {181};  
  14.         float hRanges[] = {0, 180};  
  15.         const float *ranges[] = {hRanges};  
  16.         int dims = 1;  
  17.         calcHist(&hsv[0], 1, channels, mask, hist, dims, histSize, ranges);  
  18.     }  
  19.     normalize(hist, hist, 1.0);  
  20.     return hist;  
  21. }  
  22. Mat getBackProject(Mat &image, MatND colorHist)  
  23. {  
  24.     int channels[] = {0};  
  25.     Mat result;  
  26.     float hRanges[] = {0, 180};  
  27.     const float *ranges[] = {hRanges};  
  28.     calcBackProject(&image, 1, channels, colorHist, result, ranges, 255);  
  29.     int thre = 60;  
  30.     threshold(result, result, 60, 255,THRESH_BINARY);  
  31.     return result;  
  32. }  
  33. int main()  
  34. {  
  35.     // 载入第一幅图像  
  36.     Mat image = imread("F:\\4.jpg",1);  
  37.     // 定义需要跟踪的目标---感兴趣的区域  
  38.     Mat imageROI = image(Rect(230, 320, 60, 35));  
  39.     // 得到目标的直方图  ********  
  40.     int minSat = 65;  
  41.     MatND colorHist = getHueHistogram(imageROI, minSat);  
  42.     //  载入需要跟踪的图片  
  43.     Mat image2 = imread("F:\\10.jpg", 1);  
  44.     // 转换颜色到hsv空间  
  45.     Mat hsvColor;  
  46.     cvtColor(image2, hsvColor, CV_BGR2HSV);  
  47.     vector<Mat> hsv;  
  48.     split(image2, hsv);  
  49.     // 得到目标图像的反投影直方图  *********  
  50.     Mat result = getBackProject(hsv[0], colorHist);  
  51.     // 去除 低饱和区域  
  52.     threshold(hsv[1], hsv[1], minSat, 255, THRESH_BINARY);  
  53.     bitwise_and(result, hsv[1], result);  
  54.     Rect rect(230, 320, 60, 35);  
  55.     rectangle(image, rect, Scalar(0,0,255));  
  56.     rectangle(image2, rect, Scalar(0,0,255));  
  57.     // 定义迭代的次数以及迭代的精度  
  58.     TermCriteria criteria(TermCriteria::MAX_ITER, 10, 0.01);  
  59.     // meanshift 算法 跟踪目标 并且得到新目标的位置rect  
  60.     meanShift(result, rect, criteria);  
  61.     rectangle(image2, rect, cv::Scalar(0,255,0));  
  62.     namedWindow("image");  
  63.     imshow("image", image);  
  64.     namedWindow("result");  
  65.     imshow("result", result);  
  66.     namedWindow("image2", 0);  
  67.     imshow("image2", image2);  
  68.     waitKey(0);  
  69.     return 0;  
  70. }  

Explaination:

<1>代码中我们使用HSV颜色空间中的色调分量以描述所要搜索的物体。

<2>还需要注意的是如果一个颜色的饱和度偏低,会导致色调信息变得不稳定以及不可靠。这是因为低饱和度的颜色中,红绿蓝三个分量几乎是相等的。

<3>meanshift:intcvMeanShift( const CvArr* prob_image, CvRect window, CvTermCriteria criteria,CvConnectedComp* comp );

参数

prob_image

目标直方图的反向投影(见 cvCalcBackProject).

window

初始搜索窗口

criteria

确定窗口搜索停止的准则

五:通过比较直方图检索相似图片

基本思想就是得到两幅图像的直方图,然后通过opencv提供的函数compareHist来得到它们的相似程度,返回的是个double值。

Code:

[cpp]  view plain  copy  print ?

Opencv2系列学习笔记6(直方图的应用)
Opencv2系列学习笔记6(直方图的应用)
  1. int main()  
  2. {  
  3.     Mat imageSource = imread("F:\\test\\tongtong.jpg", 1);  
  4.     colorReduce(imageSource, 32);  
  5.     MatND sourceHist = getHistogram(imageSource);  
  6.     stringstream ss;  
  7.     string str;  
  8.     string strBest = "";  
  9.     double minDistance = 256*100*100*100;  
  10.     for(int i = 1; i < 10; i++)  
  11.     {  
  12.         str = "F:\\test\\";  
  13.         ss.clear();  
  14.         ss << str;  
  15.         ss << i;  
  16.         ss << ".jpg";  
  17.         ss >> str;  
  18.         Mat imageDst = imread(str, 1);  
  19.         colorReduce(imageDst, 1);  
  20.         MatND dstHist = getHistogram(imageDst);  
  21.         double distance = compareHist(sourceHist, dstHist, CV_COMP_INTERSECT);  
  22.         if(distance < minDistance)  
  23.         {  
  24.             strBest = str;  
  25.             minDistance = distance;  
  26.         }  
  27.     }  
  28.     Mat best = imread(strBest,1);  
  29.     namedWindow(strBest);  
  30.     imshow(strBest,best);  
  31.     waitKey(0);  
  32.     return 0;  
  33. }  

Explaination:

<1>代码中使用了降低颜色数。这是因为直方图的比较大多数都是基于逐个容器的,即比较直方图容器时并不考虑相邻容器的影像。因此,测量相似度之前减少颜色空间是很重要的。

<2>compareHist函数直接明了,只需提供两个直方图,函数边返回测量距离。通过一个标志参数可以指定测量方法。代码中的参数CV_COMP_INTERSECT表示交叉测量法。即简单比较每个直方图容器的值,并保留最小的一个。相似性测量值只是这些最小值的和。

作者:小村长  出处:http://blog.csdn.net/lu597203933 欢迎转载或分享,但请务必声明文章出处。 (新浪微博:小村长zack, 欢迎交流!)