Opencv计算机视觉编程攻略-第四节 图直方图统计像素
- 1.计算图像直方图
- 2.基于查找表修改图像
- 3.直方图均衡化
- 4.直方图反向投影进行内容查找
- 5.用均值平移法查找目标
- 6.比较直方图搜索相似图像
- 7.用积分图统计图像
1.计算图像直方图
图像统计直方图的概念
图像统计直方图是一种用于描述图像中像素分布情况的工具。具体来说,灰度直方图是一个关于灰度级别的函数,它记录了图像中每种灰度级别对应的像素数量。这种分布反映了图像亮度的整体特性。
对于彩色图像(如RGB),可以通过将每个颜色通道分别映射到特定索引来构建其直方图,并利用核密度估计的方法来累积权重,从而得到更精确的颜色分布信息。
统计直方图主要基于opencv 的calcHist函数实现,其具体配置如下
calcHist(&image, 1, // histogram of 1 image onlychannels, // the channel usedMat(), // no mask is usedhist, // the resulting histogram1, // it is a 1D histogramhistSize, // number of binsranges // pixel value range);
学习文中给出的手绘统计直方图,基于统计的频数,绘制线高 line
// Create an image representing a histogramstatic Mat getImageOfHistogram(const Mat &hist, int zoom) {// Get min and max bin valuesdouble maxVal = 0;double minVal = 0;minMaxLoc(hist, &minVal, &maxVal, 0, 0);// get histogram sizeint histSize = hist.rows;// Square image on which to display histogramMat histImg(histSize*zoom, histSize*zoom, CV_8U, Scalar(255));// set highest point at 90% of nbins (i.e. image height)int hpt = static_cast<int>(0.9*histSize);// Draw vertical line for each binfor (int h = 0; h < histSize; h++) {float binVal = hist.at<float>(h);if (binVal>0) {int intensity = static_cast<int>(binVal*hpt / maxVal);line(histImg, Point(h*zoom, histSize*zoom),Point(h*zoom, (histSize - intensity)*zoom), Scalar(0), zoom);}}return histImg;}
2.基于查找表修改图像
所谓的查找表,相当于是一个数组,每个数组对应i值的原像素值映射为目标像素值
人工构建查找表
cv::Mat lut(1,256,CV_8U); // 1x256 matrix
// Or:
// int dim(256);
// cv::Mat lut(1, // 1 dimension
// &dim, // 256 entries
// CV_8U); // uchar
for (int i=0; i<256; i++) {// 0 becomes 255, 1 becomes 254, etc.lut.at<uchar>(i)= 255-i;
}
通过opencv的LUT函数一键映射查找表,进行取反操作
Mat result;// apply lookup tableLUT(image,lookup,result);
3.直方图均衡化
上文了解了统计直方图和查找表,基于直方图统计结果构建均衡化的查找表,从而全局修改图像整体颜色
equalizeHist(image,result); // 直接使用opencv函数实现均衡化
统计直方图的原理一般是值选择一定像素值范围,将该范围的像素映射的一个更大范围的像素值范围中,从而使得整体图像显得更均匀,手动实现代码如下:
Mat stretch(const Mat &image, float percentile) {// number of pixels in percentilefloat number= image.total()*percentile;// Compute histogram firstMat hist = getHistogram(image);// find left extremity of the histogramint imin = 0;for (float count=0.0; imin < 256; imin++) {// number of pixel at imin and below must be > numberif ((count+=hist.at<float>(imin)) >= number)break;}// find right extremity of the histogramint imax = 255;for (float count=0.0; imax >= 0; imax--) {// number of pixel at imax and below must be > numberif ((count += hist.at<float>(imax)) >= number)break;}// Create lookup tableint dims[1] = { 256 };Mat lookup(1, dims, 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) = cvRound(255.0*(i - imin) / (imax - imin));}// Apply lookup tableMat result;result = applyLookUp(image, lookup);return result;}
4.直方图反向投影进行内容查找
区域内图像的统计直方图某种程度表示了整体颜色分布特征,因而可以使用区域的统计直方图作为特征进行相似内容查找,以区域内白云的颜色为例进行统计
calcBackProject(&image,1, // we only use one image at a timechannels, // vector specifying what histogram dimensions belong to what image channelsshistogram, // the histogram we are usingresult, // the resulting back projection imageranges, // the range of values, for each dimension255.0 // the scaling factor is chosen such that a histogram value of 1 maps to 255);
在灰度图内进行统计分析,难以分割出较好的效果,使用rgb往往可以获得不错的效果,彩色图使用同一个函数
5.用均值平移法查找目标
以这个猩猩的脸部特征生成统计特征图
// 颜色转为hsv 如上一节所说,hsv分辨皮肤更清晰cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);// Get back-projection of hue histogramint ch[1]={0};finder.setThreshold(-1.0f); // no thresholdingcv::Mat result= finder.find(hsv,0.0f,180.0f,ch);// 使用反向统计直方图获得图像上和目标区域的相似性概率图// search objet with mean shift 使用均值漂移算法在概率图中查找,最后在一张有偏移的图像上准确找到目标cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER | cv::TermCriteria::EPS,10, // iterate max 10 times1); // or until the change in centroid position is less than 1px
6.比较直方图搜索相似图像
在传统数字图像处理领域,使用统计直方图进行图像相似度对比,是常用的方法,简单高效
double compare(const cv::Mat& image) {inputH= hist.getHistogram(image);// histogram comparison using intersectionreturn cv::compareHist(refH,inputH, cv::HISTCMP_INTERSECT);}
waves vs dog: 26535
waves vs marais: 12149
waves vs bear: 18353
waves vs beach: 33032 相似度最高的图像
waves vs polar: 20768
waves vs moose: 15225
waves vs lake: 15486
waves vs fundy: 14309
7.用积分图统计图像
积分图统计图像,本质就是数组的前缀和算法,通过一次性求解前缀,后续每个位置的要素数量就可以直接查询得到,避免每次的查找,这个在区域内进行搜索直方图特征中有较好的应用,实际操作中,将颜色维度从256压缩到更小空间从而实现加速:
double maxSimilarity=0.0;int xbest, ybest;// loop over a horizontal strip around girl location in initial imagefor (int y=110; y<120; y++) {for (int x=0; x<secondImage.cols-width; x++) {// compute histogram of 16 bins using integral imagehistogram= intHistogram(x,y,width,height);// compute distance with reference histogramdouble distance= cv::compareHist(refHistogram,histogram, cv::HISTCMP_INTERSECT);// find position of most similar histogramif (distance>maxSimilarity) {xbest= x;ybest= y;maxSimilarity= distance;}std::cout << "Distance(" << x << "," << y << ")=" << distance << std::endl;}}
如果看到这里,麻烦点一个赞再走,谢谢!相关代码同样上传代码库链接: 点击下载