#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