一些小概念
1.直方图是图像内容的一个重要特性。
2.如果一幅图像的区域中显示的是一种独特的纹理或是一个独特的物体,那么这个区域的直方图可以看作是一个概率函数,它给出的是某个像素属于该纹理或物体的概率。
3.反投影直方图的作用是在于替换一个输入图像中每一个像素值,使其变成归一化直方图中对应的概率值。
这是一个什么样的过程
名字听起来感觉很高端,其实这个一个很简单的过程。
1.首先我们截取一个区域,作为目标区域。
2.然后将目标区域取直方图,并将其直方图归一化,并得到这个区域的概率。
3.利用calcBackProject函数在图像中检索。其中函数会利用区域概率,对图像中的像素点经行映射,映射到[0,1]区间,所以要扩大255倍显示。
4.这样一来因为是负图像,所以越暗的地方相似概率越大。
calcBackProject函数
其结构
cv::calcBackProject(&image,//目标图像 1, // 图像个数 channels, // 通道数量 histogram, // 进行反投影的直方图 result, // 结果图像 ranges, // 每个维度的阈值 255.0 // 放缩因子 );
我们举个例子来说明上面说到的过程,我两个小婴儿的图像中我们截取婴儿头部皮肤,来检测婴儿全身皮肤在图像中的位置。
代码
#include "cv.h" #include "highgui.h" #include "histogram.h" #include <iostream> using namespace std; #include <opencv2\core\core.hpp> #include <opencv2\imgproc\imgproc.hpp> 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("../2.jpg"); if (!initimage.data) return 0; //显示原图像 cv::namedWindow("原图像"); cv::imshow("原图像",initimage); //读取灰度图像 cv::Mat image= cv::imread("../2.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; }
-END-