大纲
1.直方图介绍
2.绘制直方图
1.直方图介绍
去除掉物理的坐标信息,只保留像素的大小。
如下图灰度图像所示:图片中某一个像素大小出现的频率,与其位置无关。
定义:图像直方图是图像像素值的统计学特征、计算代价较小,具有图像平移、旋转
缩放不变性等众多优点,广泛地应用于图像处理的各个领域,特别是灰度图像的阈值
分割、基于颜色的图像检索以及图像分类、反向投影跟踪。
分类:
(1) 灰度直方图
(2) 颜色直方图
OpenCV中相关API
calcHist(&bgr_plane[0],1,0,Mat(),b_hist,1,bins,ranges);
2.绘制图像三通道直方图
效果图
source code
void QuickDemo::histogram_demo(Mat& image) //图像直方图
{
//三通道分离
std::vector<Mat>bgr_plane;
split(image, bgr_plane); //分离通道到容器 bgr_plane
//定义参数变量
const int channels[1] = { 0 }; //通道的个数
const int bins[1] = { 256 }; //直方图分割成多少个区间,就是bin的个数
float hranges[2] = { 0,255 }; //像素取值范围在0-255,直方图分割成多少个区间
const float* ranges[1] = { hranges };
Mat b_hist;
Mat g_hist;
Mat r_hist;
//calculate Blue,green,red chaneels histogram
//直方图的结果存放到b_hist,g_hist,r_hist中,是一个256x1的列数组
calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges);
calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges);
//自己设计--->直方图(尺寸)
int hist_w = 512;
int hist_h = 400;
//划分x轴的数据,通过之前定义的区间个数
int bin_w = cvRound((double)hist_w / bins[0]); //OpenCV 四舍五入的函数,把它分割成256分
Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3); //创建与指定的图片的尺寸相同的画布
//归一化直方图数据(限定数据范围在0-histImage.rows 之间)
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
//MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化
//Mask :Mat()
//-1 表达式数据类型和通道相同
//NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围。
//绘制直方图曲线
//在x轴方向上沿着从左到右绘制直线。
for (int i = 1; i < bins[0]; i++)
{
line(histImage,Point(bin_w*(i-1),hist_h-cvRound(b_hist.at<float>(i-1))),
Point(bin_w * (i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);
line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, 8, 0);
}
//显示直方图
namedWindow("Histogram Demo", WINDOW_AUTOSIZE);
imshow("Histogram Demo", histImage);
}
分解divide
(1)通道分离(channels divide)
//三通道分离
std::vector<Mat>bgr_plane;
split(image, bgr_plane); //分离通道到容器 bgr_plane
(2)定义参数变量(parameter varies)
const int bins[1] = { 256 }; //直方图分割成多少个区间,就是bin的个数
float hranges[2] = { 0,255 }; //像素取值范围在0-255,直方图分割成多少个区间
const float* ranges[1] = { hranges };
(3)定义存放直方图的结果变量
Mat b_hist;
Mat g_hist;
Mat r_hist;
(4)Calculates a histogram of a set of arrays.得到的是一个一维数组
calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges);
calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges);
(5)设计绘制直方图的大小,并设置x轴方向上的最小值,创建一个直方图大小的画布矩阵histImage
//自己设计--->直方图(尺寸)
int hist_w = 512;
int hist_h = 400;
//划分x轴的数据,通过之前定义的区间个数
int bin_w = cvRound((double)hist_w / bins[0]); //OpenCV 四舍五入的函数,把它分割成256分
Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3); //创建与指定的图片的尺寸相同的画布
(6)归一化处理,(限定数据范围:0 - histImage.rows 之间)
//MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化
//Mask :Mat()
//-1 表达式数据类型和通道相同
//NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围。
//MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化
//Mask :Mat()
//-1 表达式数据类型和通道相同
//NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围。
(7)绘制直方图曲线
//在x轴方向上沿着从左到右绘制直线。
for (int i = 1; i < bins[0]; i++)
{
line(histImage,Point(bin_w*(i-1),hist_h-cvRound(b_hist.at<float>(i-1))),
Point(bin_w * (i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);
line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, 8, 0);
}
代码解释:
(8)输出图片
//显示直方图
namedWindow("Histogram Demo", WINDOW_AUTOSIZE);
imshow("Histogram Demo", histImage);
DATE:2021-12-23