什么是反向投影直方图呢?简单的说在灰度图像的每个点(x,y),用它对应的直方图的bin的值(就是有多少像素落在bin内)来代替它。所以·如果这个bin的值比较大,那么反向投影显示的结果会比较亮,否则就比较暗。
从统计学的角度,反输出图像象素点的值是观测数组在某个分布(直方图)下的的概率。
所以加入我们已经得到了一个物体的直方图,我们可以计算它在另一幅图像中的反向投影,来判断这幅图像中是否有该物体。
OpenCV提供了计算反向投影直方图的函数:calcBackProject来计算一幅图像对于给定直方图的反向投影。
下面上代码:
一下是计算灰度图像直方图的类:
- #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);
-
-
-
- return hist;
- }
-
- Mat getHistogramImage(const Mat &image)
- {
-
- Mat hist = getHistogram(image);
-
-
- double maxVal = 0;
- double minVal = 0;
-
- minMaxLoc(hist,&minVal,&maxVal,0,0);
-
- Mat histImg(histSize[0],histSize[0],CV_8U,Scalar(255));
-
-
-
- int hpt = static_cast<int>(histSize[0]);
-
- for(int h = 0; h < histSize[0];h++)
- {
- float binVal = hist.at<float>(h);
- int intensity = static_cast<int>(binVal*hpt/maxVal);
-
- 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
下面的类是计算彩色图像的直方图:
- #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;
-
-
- 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;
-
- cvtColor(image,hue,CV_BGR2HSV);
-
-
- 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
这里面使用colorReduce函数减少了彩色图像的颜色。在计算彩色图像直方图类中,还包括了一个计算HSV空间中hue分量的直方图的函数。它在主函数中会使用到
有了计算直方图的函数,我们再看计算反向投影直方图的类:
- #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;
- }
-
-
- 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
其中的两个函数的区别在于一个计算的指定范围内的反向投影直方图。
最后我们看看主函数:
- #include "contentFinder.h"
- #include "histogram.h"
- #include "colorhistogram.h"
-
- int main()
- {
-
-
- Mat image = imread("D:/picture/images/waves.jpg",0);
- if(!image.data)
- return -1;
-
-
-
- Mat imageROI = image(Rect(360,55,40,50));
-
-
- Histogram1D h;
- Mat hist = h.getHistogram(imageROI);
-
-
- ContentFinder finder;
- finder.setHistogram(hist);
- finder.setThreshold(-1.0f);
-
- Mat result1;
- result1 = finder.find(image);
- Mat tmp;
- result1.convertTo(tmp,CV_8U,-1.0,255.0);
- imshow("反向投影结果",tmp);
-
-
- finder.setThreshold(0.12f);
- result1 = finder.find(image);
- imshow("灰度图像检测结果(1)",result1);
-
-
- rectangle(image,Rect(360,55,40,50),Scalar(0,0,0));
- imshow("源图像",image);
-
-
-
- Mat image2 = imread("D:/picture/images/dog.jpg",0);
-
- Mat result2 = finder.find(image2);
- imshow("灰度图像检测结果(2)",result2);
-
-
-
-
-
-
- ColorHistogram hc;
- Mat color = imread("D:/picture/images/waves.jpg");
- imshow("源图像(1)",color);
-
- color = hc.colorReduce(color,32);
-
-
-
- imageROI = color(Rect(0,0,165,75));
-
-
- Mat shist = hc.getHistogram(imageROI);
- finder.setHistogram(shist);
- finder.setThreshold(0.05f);
-
-
- result1 = finder.find(color);
- imshow("彩色图像检测结果(1)",result1);
-
-
-
- Mat color2 = imread("D:/picture/images/dog.jpg");
- imshow("源图像(2)",color2);
- color2 = hc.colorReduce(color2,32);
- result2 = finder.find(color2);
- imshow("彩色图像检测结果(2)",result2);
-
-
-
-
- color = imread("D:/picture/images/waves.jpg");
- imageROI = color(Rect(0,0,165,75));
- Mat colorhist = hc.getHueHistogram(imageROI);
- finder.setHistogram(colorhist);
- finder.setThreshold(0.3f);
- Mat hsv;
- cvtColor(color,hsv,CV_BGR2HSV);
- int ch[2]={1,2};
- ch[0] = 0;
- result1 = finder.find(hsv,0.0f,180.0f,ch,1);
- imshow("使用色度的结果(1)",result1);
-
-
- color2 = imread("D:/picture/images/dog.jpg");
- cvtColor(color2,hsv,CV_BGR2HSV);
- result2 = finder.find(hsv,0.0f,180.0f,ch,1);
- imshow("使用色度检测结果(2)",result2);
- waitKey(0);
- return 0;
- }
在主函数中,我们对几种法相投影直方图的方法进行了对比:
只用灰度图像的直方图;用彩色图像直方图;以及HSV空间中色图像检索。
转自:http://blog.csdn.net/thefutureisour/article/details/7554716