直方图简介
- 一般来说直方图基于图像像素值,其实对于图像梯度、每个像素的角度、等一切图像的属性值,我们都可以建立直方图,这个才是直方图概念的真正意义,不过是基于图像像素灰度直方图是最常见的。
- 直方图最常见的几个属性:
- dims 表示维度,对灰度图像来说只有一个通道值dims=1
- bins 表示在维度中心区域大小划分,bins=256,划分为256个级别
- range 表示值的范围,灰度值范围为[0-255]之间
函数API
API
// 把多通道图像分为多个单通道图像 split( const Mat &src, //输入图像 Mat* mvbegin)// 输出的通道图像数组
参数介绍
参数较为简单,这里不做介绍
API
calcHist( const Mat* images,//输入图像指针 int images,// 图像数目 const int* channels,// 通道数 InputArray mask,// 输入mask,可选,不用 OutputArray hist,//输出的直方图数据 int dims,// 维数 const int* histsize,// 直方图级数 const float* ranges,// 值域范围 bool uniform,// true by default bool accumulate// false by defaut )
参数介绍
- const Mat images*:输入图像
- int nimages:输入图像的个数
- const int channels*:需要统计直方图的第几通道
- InputArray mask:掩膜,,计算掩膜内的直方图 …Mat()
- OutputArray hist:输出的直方图数组
- int dims:需要统计直方图通道的个数
- const int histSize*:指的是直方图分成多少个区间,就是 bin的个数
- const float ranges**: 统计像素值得区间
- bool uniform=true::是否对得到的直方图数组进行归一化处理
- bool accumulate=false:在多个图像时,是否累计计算像素值得个数
代码演示
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
#define Pic_Path "/home/image/Pictures/my_picture/"
#define Pic_Name "model_1.jpeg"
int main(void)
{
string pic = string(Pic_Path) + string(Pic_Name);
cout << pic << endl;
cv::Mat src;
//读取原始图片
src = cv::imread(pic.c_str());
if(src.empty())
{
cout << "图片不存在" << endl;
return -1;
}
cv::namedWindow("原始图片",cv::WINDOW_AUTOSIZE);
cv::imshow("原始图片",src);
//分通道显示
vector<Mat> bgr_planes;
split(src, bgr_planes);
//设定像素取值范围
int histSize = 256;
float range[] = { 0,256 };
const float *histRanges = { range };
//三个通道分别计算直方图
Mat b_hist, g_hist, r_hist;
//输入图像指针 图像数目 通道数 mask可以不用 输出直方图 直方图维度 直方图级数 值域范围
calcHist(&bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRanges, true, false);
calcHist(&bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRanges, true, false);
calcHist(&bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRanges, true, false);
//创建直方图画布并归一化处理
int hist_h = 400; //绘制图像高度
int hist_w = 512; //绘制图像宽度
int bin_w = hist_w / histSize; //画点时x坐标的步进长度 因为原图x范围为256
//创建画布 背景为黑色
Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
//图像归一化 统计像素时某些点数量较大 远远大于图像高度 这里将点的范围全部控制到0-400范围之间
//normalize参数:输入图像 输出图像 范围低值 范围高值 归一化类型
//normalize参数:当为负,输出在大小深度通道数都等于输入,当为正,输出只在深度与输如不同,不同的地方游dtype决定;掩膜
normalize(b_hist, b_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
normalize(g_hist, g_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
normalize(r_hist, r_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
//render histogram chart 在直方图画布上画出直方图
//cvRound 返回跟参数最接近的整数值;
//cvFloor 返回不大于参数的最大整数值;
//cvCeil 返回不小于参数的最小整数值
for (int i = 0; i < histSize; i++)
{
//屏幕坐标系以左上角为00点,向下、向右为正方向,所以高度上不做反转处理,显示出来的直方图是倒立的
//绘图时用直线描绘 原理是用前一个点做起点 用本身的点做终点 依次绘制
line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(b_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, LINE_AA);
line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(g_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, LINE_AA);
line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(r_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, LINE_AA);
}
imshow("直方图", histImage);
cv::waitKey(0);
cv::destroyAllWindows();
}