OpenCV学习笔记(13):利用反向投影直方图查找特定的内容(一)

来源:互联网 发布:恒久软件好使吗 编辑:程序博客网 时间:2024/06/18 16:41

什么是反向投影直方图呢?简单的说在灰度图像的每个点(x,y),用它对应的直方图的bin的值(就是有多少像素落在bin内)来代替它。所以·如果这个bin的值比较大,那么反向投影显示的结果会比较亮,否则就比较暗。

从统计学的角度,反输出图像象素点的值是观测数组在某个分布(直方图)下的的概率。

所以加入我们已经得到了一个物体的直方图,我们可以计算它在另一幅图像中的反向投影,来判断这幅图像中是否有该物体。

OpenCV提供了计算反向投影直方图的函数:calcBackProject来计算一幅图像对于给定直方图的反向投影。

下面上代码:

一下是计算灰度图像直方图的类:

[cpp] view plaincopy
  1. #if!defined HISTOGRAM  
  2. #define HISTOGRAM  
  3.   
  4. #include <opencv2/core/core.hpp>  
  5. #include <opencv2/imgproc/imgproc.hpp>  
  6. #include <iostream>  
  7.   
  8. using namespace std;  
  9. using namespace cv;  
  10.   
  11.   
  12. class Histogram1D  
  13. {  
  14. private:  
  15.       
  16.     //直方图的点数  
  17.     int histSize[1];  
  18.     //直方图的范围  
  19.     float hranges[2];  
  20.     //指向该范围的指针  
  21.     const float* ranges[1];  
  22.     //通道  
  23.     int channels[1];  
  24.       
  25.   
  26. public:  
  27.     //构造函数  
  28.     Histogram1D()  
  29.     {  
  30.          histSize[0] = 256;  
  31.          hranges[0] = 0.0;  
  32.          hranges[1] = 255.0;  
  33.          ranges[0] = hranges;  
  34.          channels[0] = 0;  
  35.   
  36.     }  
  37.   
  38.     Mat getHistogram(const Mat &image)  
  39.     {  
  40.         Mat hist;  
  41.         //计算直方图函数  
  42.         //参数为:源图像(序列)地址,输入图像的个数,通道数,掩码,输出结果,直方图维数,每一维的大小,每一维的取值范围  
  43.         calcHist(&image,1,channels,Mat(),hist,1,histSize,ranges);  
  44.         //这个函数虽然有很多参数,但是大多数时候,只会用于灰度图像或者彩色图像  
  45.         //但是,允许通过指明一个多通道图像使用多幅图像  
  46.         //第6个参数指明了直方图的维数  
  47.         return hist;  
  48.     }  
  49.   
  50.     Mat getHistogramImage(const Mat &image)  
  51.     {  
  52.         //首先计算直方图  
  53.         Mat hist = getHistogram(image);  
  54.   
  55.         //获取最大值和最小值  
  56.         double maxVal = 0;  
  57.         double minVal = 0;  
  58.         //minMaxLoc用来获得最大值和最小值,后面两个参数为最小值和最大值的位置,0代表不需要获取  
  59.         minMaxLoc(hist,&minVal,&maxVal,0,0);  
  60.         //展示直方图的画板:底色为白色  
  61.         Mat histImg(histSize[0],histSize[0],CV_8U,Scalar(255));  
  62.   
  63.         //将最高点设为bin总数的90%  
  64.         //int hpt = static_cast<int>(0.9*histSize[0]);  
  65.         int hpt = static_cast<int>(histSize[0]);  
  66.         //为每一个bin画一条线  
  67.         for(int h = 0; h < histSize[0];h++)  
  68.         {  
  69.             float binVal = hist.at<float>(h);  
  70.             int intensity = static_cast<int>(binVal*hpt/maxVal);  
  71.             //int intensity = static_cast<int>(binVal);  
  72.             line(histImg,Point(h,histSize[0]),Point(h,histSize[0]-intensity),Scalar::all(0));  
  73.               
  74.         }  
  75.         return histImg;  
  76.     }  
  77.   
  78.     Mat applyLookUp(const Mat& image,const Mat& lookup)  
  79.     {  
  80.         Mat result;  
  81.         LUT(image,lookup,result);  
  82.         return result;  
  83.     }  
  84.   
  85.   
  86.     Mat strech(const Mat &image,int minValue = 0)  
  87.     {  
  88.         //首先计算直方图  
  89.         Mat hist = getHistogram(image);  
  90.         //左边入口  
  91.         int imin = 0;  
  92.         for(;imin< histSize[0];imin++)  
  93.         {  
  94.             cout<<hist.at<float>(imin)<<endl;  
  95.             if(hist.at<float>(imin) > minValue)  
  96.                 break;  
  97.   
  98.         }  
  99.         //右边入口  
  100.         int imax = histSize[0]-1;  
  101.         for(;imax >= 0; imax--)  
  102.         {  
  103.             if(hist.at<float>(imax) > minValue)  
  104.                 break;  
  105.         }  
  106.   
  107.         //创建查找表  
  108.         int dim(256);  
  109.         Mat lookup(1,&dim,CV_8U);  
  110.           
  111.         for(int i = 0; i < 256; i++)  
  112.         {  
  113.             if(i < imin)  
  114.             {  
  115.                 lookup.at<uchar>(i) = 0;  
  116.             }  
  117.             else if(i > imax)  
  118.             {  
  119.                 lookup.at<uchar>(i) = 255;  
  120.             }  
  121.             else  
  122.             {  
  123.                 lookup.at<uchar>(i) = static_cast<uchar>(255.0*(i-imin)/(imax-imin)+0.5);  
  124.             }  
  125.         }  
  126.         Mat result;  
  127.         result = applyLookUp(image,lookup);  
  128.         return result;  
  129.   
  130.     }  
  131.     Mat equalize(const Mat &image)  
  132.     {  
  133.         Mat result;  
  134.         equalizeHist(image,result);  
  135.         return result;  
  136.     }  
  137.   
  138. };  
  139.   
  140. #endif  

 

下面的类是计算彩色图像的直方图:

[cpp] view plaincopy
  1. #if!defined COLORHISTOGRAM  
  2. #define COLORHISTOGRAM  
  3.   
  4. #include <opencv2/core/core.hpp>  
  5. #include <opencv2/imgproc/imgproc.hpp>  
  6.   
  7. using namespace cv;  
  8.   
  9. class ColorHistogram  
  10. {  
  11. private:  
  12.     int histSize[3];  
  13.     float hranges[2];  
  14.     const float* ranges[3];  
  15.     int channels[3];  
  16. public:  
  17.   
  18.     //构造函数  
  19.     ColorHistogram()  
  20.     {  
  21.         histSize[0]= histSize[1]= histSize[2]= 256;  
  22.         hranges[0] = 0.0;  
  23.         hranges[1] = 255.0;  
  24.         ranges[0] = hranges;  
  25.         ranges[1] = hranges;  
  26.         ranges[2] = hranges;  
  27.         channels[0] = 0;  
  28.         channels[1] = 1;  
  29.         channels[2] = 2;  
  30.     }  
  31.   
  32.     //计算彩色图像直方图  
  33.     Mat getHistogram(const Mat& image)  
  34.     {  
  35.         Mat hist;  
  36.   
  37.         //BGR直方图  
  38.         hranges[0]= 0.0;      
  39.         hranges[1]= 255.0;  
  40.         channels[0]= 0;   
  41.         channels[1]= 1;   
  42.         channels[2]= 2;   
  43.   
  44.         //计算  
  45.         calcHist(&image,1,channels,Mat(),hist,3,histSize,ranges);  
  46.         return hist;  
  47.     }  
  48.   
  49.     //计算颜色的直方图  
  50.     Mat getHueHistogram(const Mat &image)  
  51.     {  
  52.         Mat hist;  
  53.         Mat hue;  
  54.         //转换到HSV空间  
  55.         cvtColor(image,hue,CV_BGR2HSV);  
  56.   
  57.         //设置1维直方图使用的参数  
  58.         hranges[0] = 0.0;  
  59.         hranges[1] = 180.0;  
  60.         channels[0] = 0;  
  61.         //计算直方图  
  62.         calcHist(&hue,1,channels,Mat(),hist,1,histSize,ranges);  
  63.         return hist;  
  64.   
  65.     }  
  66.   
  67.     //减少颜色  
  68.     Mat colorReduce(const Mat &image,int div = 64)  
  69.     {  
  70.         int n = static_cast<int>(log(static_cast<double>(div))/log(2.0));  
  71.         uchar mask = 0xFF<<n;  
  72.         Mat_<Vec3b>::const_iterator it = image.begin<Vec3b>();  
  73.         Mat_<Vec3b>::const_iterator itend = image.end<Vec3b>();  
  74.         //设置输出图像  
  75.         Mat result(image.rows,image.cols,image.type());  
  76.         Mat_<Vec3b>::iterator itr = result.begin<Vec3b>();  
  77.         for(;it != itend;++it,++itr)  
  78.         {  
  79.             (*itr)[0] = ((*it)[0]&mask) + div/2;  
  80.             (*itr)[1] = ((*it)[1]&mask) + div/2;  
  81.             (*itr)[2] = ((*it)[2]&mask) + div/2;  
  82.         }  
  83.         return result;  
  84.     }  
  85.   
  86. };  
  87.   
  88.   
  89. #endif  


这里面使用colorReduce函数减少了彩色图像的颜色。在计算彩色图像直方图类中,还包括了一个计算HSV空间中hue分量的直方图的函数。它在主函数中会使用到

有了计算直方图的函数,我们再看计算反向投影直方图的类:

[cpp] view plaincopy
  1. #if!defined CONTENTFINDER  
  2. #define CONTENTFINDER  
  3.   
  4. #include <opencv2/core/core.hpp>  
  5. #include <opencv2/highgui/highgui.hpp>  
  6. #include <opencv2/imgproc/imgproc.hpp>  
  7.   
  8. using namespace cv;  
  9.   
  10. class ContentFinder  
  11. {  
  12. private:  
  13.     float hranges[2];  
  14.     const float* ranges[3];  
  15.     int channels[3];  
  16.     float threshold;  
  17.     Mat histogram;  
  18. public:  
  19.     ContentFinder():threshold(-1.0f)  
  20.     {  
  21.         //所有通道的范围相同  
  22.         ranges[0] = hranges;  
  23.         ranges[1] = hranges;   
  24.         ranges[2] = hranges;  
  25.     }  
  26.   
  27.     //设置门限参数[0,1]  
  28.     void setThreshold(float t)  
  29.     {  
  30.         threshold = t;  
  31.     }  
  32.   
  33.     //获取门限参数  
  34.     float getThreshold()  
  35.     {  
  36.         return threshold;  
  37.     }  
  38.   
  39.     //设置参考的直方图  
  40.     void setHistogram(const Mat& h)  
  41.     {  
  42.         histogram = h;  
  43.         normalize(histogram,histogram,1.0);  
  44.     }  
  45.   
  46.     //简单的利用反向投影直方图寻找  
  47.     Mat find(const Mat& image)  
  48.     {  
  49.         Mat result;  
  50.         hranges[0] = 0.0;  
  51.         hranges[1] = 255.0;  
  52.         channels[0] = 0;  
  53.         channels[1] = 1;  
  54.         channels[2] = 2;  
  55.   
  56.         calcBackProject(&image,1,channels,histogram,result,ranges,255.0);  
  57.         if (threshold>0.0)  
  58.         {  
  59.             cv::threshold(result, result, 255*threshold, 255, cv::THRESH_BINARY);  
  60.         }  
  61.   
  62.         return result;  
  63.     }  
  64.   
  65.     //复杂的利用反向投影直方图,增加了一些参数  
  66.     Mat find(const Mat &image,float minValue,float maxValue,int *channels,int dim)  
  67.     {  
  68.         Mat result;  
  69.         hranges[0] = minValue;  
  70.         hranges[1] = maxValue;  
  71.         for(int i = 0;i < dim;i++)  
  72.         {  
  73.             this->channels[i] = channels[i];  
  74.         }  
  75.         calcBackProject(&image,1,channels,histogram,result,ranges,255.0);  
  76.         if(threshold >0.0)  
  77.             cv::threshold(result,result, 255*threshold,255,THRESH_BINARY);  
  78.         return result;  
  79.   
  80.     }  
  81. };  
  82. #endif  

 

其中的两个函数的区别在于一个计算的指定范围内的反向投影直方图。

最后我们看看主函数:

[cpp] view plaincopy
  1. #include "contentFinder.h"  
  2. #include "histogram.h"  
  3. #include "colorhistogram.h"  
  4.   
  5. int main()  
  6. {  
  7.       
  8.     //读取图像  
  9.     Mat image = imread("D:/picture/images/waves.jpg",0);  
  10.     if(!image.data)  
  11.         return -1;  
  12.   
  13.   
  14.     //定义感兴趣区域  
  15.     Mat imageROI = image(Rect(360,55,40,50));   
  16.   
  17.     //利用前面设计好的类计算感兴趣区域的直方图  
  18.     Histogram1D h;  
  19.     Mat hist = h.getHistogram(imageROI);  
  20.   
  21.     //创建一个ContentFinder对象  
  22.     ContentFinder finder;  
  23.     finder.setHistogram(hist);  
  24.     finder.setThreshold(-1.0f);  
  25.     //获取反向投影  
  26.     Mat result1;  
  27.     result1 = finder.find(image);  
  28.     Mat tmp;  
  29.     result1.convertTo(tmp,CV_8U,-1.0,255.0);  
  30.     imshow("反向投影结果",tmp);  
  31.   
  32.     //获取二值反向投影  
  33.     finder.setThreshold(0.12f);  
  34.     result1 = finder.find(image);  
  35.     imshow("灰度图像检测结果(1)",result1);  
  36.   
  37.     //给源图像加上矩形框  
  38.     rectangle(image,Rect(360,55,40,50),Scalar(0,0,0));  
  39.     imshow("源图像",image);  
  40.   
  41.   
  42.     //换一幅图像:这幅图像中也有大量云彩  
  43.     Mat image2 = imread("D:/picture/images/dog.jpg",0);  
  44.       
  45.     Mat result2 = finder.find(image2);  
  46.     imshow("灰度图像检测结果(2)",result2);  
  47.       
  48. //**************以上检测因为没有用到颜色信息,所以效果很差**************  
  49.   
  50.   
  51.     //获取彩色直方图  
  52.     //读取彩色图像  
  53.     ColorHistogram hc;  
  54.     Mat color = imread("D:/picture/images/waves.jpg");  
  55.     imshow("源图像(1)",color);  
  56.     //为了减少计算量,使用colorReduce函数  
  57.     color = hc.colorReduce(color,32);  
  58.       
  59.   
  60.     //定义感兴趣区域:云彩  
  61.     imageROI = color(Rect(0,0,165,75));  
  62.   
  63.     //获取直方图  
  64.     Mat shist = hc.getHistogram(imageROI);  
  65.     finder.setHistogram(shist);  
  66.     finder.setThreshold(0.05f);  
  67.   
  68.     //获取反向投影直方图  
  69.     result1 = finder.find(color);  
  70.     imshow("彩色图像检测结果(1)",result1);  
  71.   
  72.   
  73.     //读取第二幅图像并检测  
  74.     Mat color2 = imread("D:/picture/images/dog.jpg");  
  75.     imshow("源图像(2)",color2);  
  76.     color2 = hc.colorReduce(color2,32);  
  77.     result2 = finder.find(color2);  
  78.     imshow("彩色图像检测结果(2)",result2);  
  79.   
  80. //***************以上结果因为考虑了颜色信息,所以效果比较好*********************  
  81.   
  82.     //仅考虑色度信息,构成直方图,进行反向投影检测  
  83.     color = imread("D:/picture/images/waves.jpg");  
  84.     imageROI = color(Rect(0,0,165,75));  
  85.     Mat colorhist = hc.getHueHistogram(imageROI);  
  86.     finder.setHistogram(colorhist);  
  87.     finder.setThreshold(0.3f);  
  88.     Mat hsv;  
  89.     cvtColor(color,hsv,CV_BGR2HSV);  
  90.     int ch[2]={1,2};  
  91.     ch[0] = 0;  
  92.     result1 = finder.find(hsv,0.0f,180.0f,ch,1);  
  93.     imshow("使用色度的结果(1)",result1);  
  94.   
  95.     //换一幅图片  
  96.     color2 = imread("D:/picture/images/dog.jpg");  
  97.     cvtColor(color2,hsv,CV_BGR2HSV);  
  98.     result2 = finder.find(hsv,0.0f,180.0f,ch,1);  
  99.     imshow("使用色度检测结果(2)",result2);  
  100.     waitKey(0);  
  101.     return 0;  
  102. }  


在主函数中,我们对几种法相投影直方图的方法进行了对比:

只用灰度图像的直方图;用彩色图像直方图;以及HSV空间中色图像检索。


转自:http://blog.csdn.net/thefutureisour/article/details/7554716

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小米手机屏幕乱点怎么办 iphone6s卡屏了怎么办 苹果手机屏幕动不了怎么办 苹果手机滑不动怎么办 升级失败白苹果怎么办 6s屏幕不准怎么办 苹果4s充不进电怎么办 苹果4sbi锁怎么办 乐视pro3充电慢怎么办 手机屏幕触碰不灵敏怎么办 手机换屏幕失灵怎么办 手机图标有重影怎么办 苹果屏幕太灵敏怎么办 5s触摸不灵敏怎么办 导航触屏失灵怎么办 汽车导航触摸屏失灵怎么办 爱丽舍导航仪触屏失灵怎么办 手机要开机很久怎么办 小米手机屏失灵怎么办 5s手机屏幕松动怎么办 手机按钮不灵了怎么办 手机触摸屏不灵了怎么办 mac触摸板失灵怎么办 苹果屏幕触摸失灵怎么办 三星手机屏幕没反应怎么办 手机开机定屏怎么办 手机触摸局部失灵怎么办 苹果手机屏幕按键失灵怎么办 5s锁屏键坏了怎么办 平板版本太低怎么办 手机屏局部失灵怎么办 iphone8触屏不灵敏怎么办 苹果机8屏幕失灵怎么办 车钥匙丢车上怎么办 指纹锁华盖坏了怎么办 非法入了户口怎么办 司考成绩单丢了怎么办 小饭桌转让手续怎么办 两个领导不和你怎么办 两个领导意见不一致怎么办 两个领导对立我怎么办