// 直方图简介
// 图像是由不同数值(颜色)的像素构成的,像素值在整幅图像中的分布情况是该图像的一个重要属性。
// 如何计算直方图、如何用直方图修改图像的外观、还可以用直方图来标识图像的内容、检测图像中特定的物体或纹理
// 计算图像直方图
// 可调用cv::calcHist 函数,这是一个通用的直方图计算函数,可处理包含任何值类型和范围的多通道图像。
代码
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
// 直方图简介
// 图像是由不同数值(颜色)的像素构成的,像素值在整幅图像中的分布情况是该图像的一个重要属性。
// 如何计算直方图、如何用直方图修改图像的外观、还可以用直方图来标识图像的内容、检测图像中特定的物体或纹理
// 计算图像直方图
// 可调用cv::calcHist 函数,这是一个通用的直方图计算函数,可处理包含任何值类型和范围的多通道图像。
// 这里创建一个类,专门用于处理单通道灰度图像
// 输入必须是灰度图
using namespace cv;
class Histogram1D{
private:
int histSize[1]; // 直方图中箱子的数量
float hranges[2]; // 值范围
const float* ranges[1]; // 值范围的指针
int channels[1]; // 要检查的通道数量
public:
Histogram1D(){
// 准备一维直方图的默认参数
histSize[0] = 256; // 256个箱子
hranges[0] = 0.0; // 从0开始 (含)
hranges[1] = 256.0; // 到256(不含)
ranges[0] = hranges;
channels[0] = 0; // 先关注通道0
}
Mat getHistomgram(const Mat &image){
Mat hist;
calcHist(&image, 1, // 仅为一幅图像的直方图
channels, // 使用的通道
Mat(), // 不使用掩码
hist, // 作为结果的直方图, cols=1, rows=图像像素种类
1, // 这是一维的直方图
histSize, // 箱子数量
ranges); // 像素值的范围
return hist;
}
// 创建一个表示直方图的图像(静态方法)
static Mat getImageOfHistogram(const Mat &hist, int zoom){
// 取得箱子值的最大值和最小值
double maxVal = 0;
double minVal = 0;
minMaxLoc(hist, &minVal, &maxVal, 0, 0);
// 取得直方图的大小
int histSize = hist.rows;
// 用于显示直方图的方形图像
Mat histImg(histSize*zoom, histSize*zoom,
CV_8U, Scalar(255));
// 图像高度
int hpt = static_cast<int>(0.9 * histSize);
int peak=0;
int loc=0;
// 在白色方形图像上为每个箱子画垂直线
for (int h = 0; h<histSize; h++){
// 每个箱子的值
float binVal = hist.at<float>(h);
if(binVal>0){
int intensity = static_cast<int>(binVal/maxVal * hpt);
// 寻找 峰值
if (h>0 and intensity > peak){
peak = intensity;
loc = h;
}
// 画垂直线
line(histImg, Point(h*zoom, histSize*zoom),
Point(h*zoom, (histSize - intensity)*zoom),
Scalar(0), zoom);
}
}
// 找出峰值所在位置
std::cout << "peak bin loc: " << loc <<
" bin value:" << peak;
return histImg;
}
//
Mat getHistogramImage(const Mat &image, int zoom=1){
// 得到直方图(一维数组)
Mat hist = getHistomgram(image);
return getImageOfHistogram(hist, zoom);
}
};
int main()
{
Mat dog = imread("/home/jason/work/01-img/dog.png", IMREAD_GRAYSCALE);
std::cout << dog.rows << "*"<< dog.cols << std::endl;
Rect rect(90, 50,450,340);
dog = dog(rect);
imshow("dog",dog);
Histogram1D h;
// Mat histo = h.getHistomgram(dog);
imshow("Histogram", h.getHistogramImage(dog));
// 直方图的峰值所在箱子位置是 115
// 直方图尖峰的两边的像素,分别对应了图像的背景和前景
// 可以在两部分的汇合处进行阈值化
//用灰度值115来进行阈值化。
Mat threshold;
cv::threshold(dog, threshold, 115, 255, cv::THRESH_BINARY);
imshow("threshold", threshold);
waitKey(0);
return 0;
}
结果