Opencv计算机视觉编程攻略-第四节 图直方图统计像素
1.计算图像直方图
图像统计直方图的概念
图像统计直方图是一种用于描述图像中像素分布情况的工具。具体来说,灰度直方图是一个关于灰度级别的函数,它记录了图像中每种灰度级别对应的像素数量。这种分布反映了图像亮度的整体特性。
对于彩色图像(如RGB),可以通过将每个颜色通道分别映射到特定索引来构建其直方图,并利用核密度估计的方法来累积权重,从而得到更精确的颜色分布信息。
统计直方图主要基于opencv 的calcHist函数实现,其具体配置如下
calcHist(&image,
1, // histogram of 1 image only
channels, // the channel used
Mat(), // no mask is used
hist, // the resulting histogram
1, // it is a 1D histogram
histSize, // number of bins
ranges // pixel value range
);
学习文中给出的手绘统计直方图,基于统计的频数,绘制线高 line
// Create an image representing a histogram
static Mat getImageOfHistogram(const Mat &hist, int zoom) {
// Get min and max bin values
double maxVal = 0;
double minVal = 0;
minMaxLoc(hist, &minVal, &maxVal, 0, 0);
// get histogram size
int histSize = hist.rows;
// Square image on which to display histogram
Mat 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 bin
for (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 table
LUT(image,lookup,result);
3.直方图均衡化
上文了解了统计直方图和查找表,基于直方图统计结果构建均衡化的查找表,从而全局修改图像整体颜色
equalizeHist(image,result); // 直接使用opencv函数实现均衡化
统计直方图的原理一般是值选择一定像素值范围,将该范围的像素映射的一个更大范围的像素值范围中,从而使得整体图像显得更均匀,手动实现代码如下:
Mat stretch(const Mat &image, float percentile) {
// number of pixels in percentile
float number= image.total()*percentile;
// Compute histogram first
Mat hist = getHistogram(image);
// find left extremity of the histogram
int imin = 0;
for (float count=0.0; imin < 256; imin++) {
// number of pixel at imin and below must be > number
if ((count+=hist.at<float>(imin)) >= number)
break;
}
// find right extremity of the histogram
int imax = 255;
for (float count=0.0; imax >= 0; imax--) {
// number of pixel at imax and below must be > number
if ((count += hist.at<float>(imax)) >= number)
break;
}
// Create lookup table
int 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 table
Mat result;
result = applyLookUp(image, lookup);
return result;
}
4.直方图反向投影进行内容查找
区域内图像的统计直方图某种程度表示了整体颜色分布特征,因而可以使用区域的统计直方图作为特征进行相似内容查找,以区域内白云的颜色为例进行统计
calcBackProject(&image,
1, // we only use one image at a time
channels, // vector specifying what histogram dimensions belong to what image channels
shistogram, // the histogram we are using
result, // the resulting back projection image
ranges, // the range of values, for each dimension
255.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 histogram
int ch[1]={0};
finder.setThreshold(-1.0f); // no thresholding
cv::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 times
1); // 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 intersection
return 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 image
for (int y=110; y<120; y++) {
for (int x=0; x<secondImage.cols-width; x++) {
// compute histogram of 16 bins using integral image
histogram= intHistogram(x,y,width,height);
// compute distance with reference histogram
double distance= cv::compareHist(refHistogram,histogram, cv::HISTCMP_INTERSECT);
// find position of most similar histogram
if (distance>maxSimilarity) {
xbest= x;
ybest= y;
maxSimilarity= distance;
}
std::cout << "Distance(" << x << "," << y << ")=" << distance << std::endl;
}
}
如果看到这里,麻烦点一个赞再走,谢谢!相关代码同样上传代码库链接: 点击下载