calcHist() 函数详解
具体请参考:
https://blog.csdn.net/qq_42067550/article/details/122533459
绘制直方图的代码
注意:这里的代码用于生产灰度图的直方图,如果要获得彩色图片多个通道的直方图,需要先分离各个通道,再分别绘制!
#include "opencv2/opencv.hpp"
#include "opencv2/highgui.hpp"
#include <string>
using namespace std;
cv::Mat getHistogramImage(cv::Mat hist)
{
cv::Mat histData= hist.clone();
int histSize = histData.rows;
int targetPoint = 225;
//int bin_w = cvRound((double)hist_w / histSize);
int bin_w = 3; // 一个桶所占的宽度
int hist_w = histSize * bin_w + 50; // 加上 50 是为了在图像两边各留 25 个像素的冗余
int hist_h = cvRound(hist_w * 2 / 3) + 50; // 绘制长方形图片,同样预留边框
// 创建直方图画布
cv::Mat histImage(hist_h, hist_w, CV_8UC3, cv::Scalar(255, 255, 255));
// 绘制坐标轴
cv::line(histImage, cv::Point(hist_w - 20, hist_h - 20), cv::Point(20, hist_h - 20), cv::Scalar(0, 0, 0), 2, 4, 0);
cv::line(histImage, cv::Point(20, hist_h - 20), cv::Point(20, 20), cv::Scalar(0, 0, 0), 2, 4, 0);
// 绘制坐标轴刻度
int seg = 16; // 每隔开 32 个桶设一个标记,256/32=8 共 9 个标记位(加上 0)
int segs = histSize / seg;
for (int i = 0; i <= segs; i++)
{
cv::line(histImage, cv::Point(26 + i * seg * bin_w, hist_h - 20), cv::Point(26 + i * seg * bin_w, hist_h - 15), cv::Scalar(0, 0, 0), 1, 4, 0);
string text = to_string(i * seg);
cv::putText(histImage, text, cv::Point(20 + i * seg * bin_w, hist_h - 5), 1, 0.8, cv::Scalar(0, 0, 0), 1, 8, false);
}
for (int i = 0; i <= segs; i++)
{
cv::line(histImage, cv::Point(20, hist_h - 20 - i * (hist_h - 40) / 8), cv::Point(15, hist_h - 20 - i * (hist_h - 40) / 8), cv::Scalar(0, 0, 0), 1, 4, 0);
}
/// 将直方图归一化到范围 [ 0, histImage.rows ]
cv::normalize(histData, histData, 0, hist_h - 50, cv::NORM_MINMAX, -1, cv::Mat());
/// 在直方图画布上画出直方图
for (int i = 1; i < histSize; i++)
{
cv::line(histImage, cv::Point(26 + i * bin_w, hist_h - 20 - cvRound(histData.at<float>(i))),
cv::Point(26 + (i - 1) * bin_w, hist_h - 20 - cvRound(histData.at<float>(i-1))),
cv::Scalar(10), 1, cv::LINE_AA, 0);
}
return histImage;
}
int main()
{
cv::Mat img = cv::imread("./dog.jpeg", 0); // 读取灰度图
cv::Mat histogram;
int histSize = 256;
float range[] = {0, 255};
int channels[] = {0};
const float *histRanges = { range };
bool uniform = true;
bool accumulate = false;
cv::calcHist(&img, 1, channels, cv::Mat(), histogram, 1, &histSize, &histRanges, uniform, accumulate);
cv::Mat histImage = getHistogramImage(histogram);
cv::imshow("1", histImage);
cv::waitKey(0);
return 0;
}
测试图片
生成的直方图