一、介绍
1.什么叫直方图
之前介绍了一个直方图均衡化的函数,从这篇开始将联系用6篇文章来介绍一下直方图的相关概念和函数的应用。
直方图,是指对整个图像像在灰度范围内的像素值(0~255)统计出现频率次数,据此生成的一个统计表,称为图像直方图。它是一个统计学概念,可以反映图像灰度的分布情况。假如说有某张图片,直方图是下面这样的:
1、X轴代表像素值,范围是0 - 255;
2、Y轴代表某个像素值在图像中出现的次数。比如0这个值,大概出现了5000次左右;35这个值,出现了大概7000次。
根据这个直方图,我们就能得出这张图片整体不是太亮,因为像素值在 0 - 100这个区间出现的次数最多,也就是图像里面多数像素值都是在 0 - 100之间。100 - 245 的像素值不太多,大于245的像素值倒是有一部分。
因此:
1、直方图是一种像素值分布的图形表达方式。
2、它可以统计每一个值所出现的次数。
3、不同的图形的直方图可能是相同的。
2.直方图计算的函数
Emgu CV里面直方图均衡化的函数是EqualizeHist(),函数定义如下:
public static void CalcHist(
IInputArrayOfArrays images, // 输入图像,
int[] channels, // 需要统计直方图的第几通道
IInputArray mask, // 掩码图
IOutputArray hist, // 直方图计算的输出值
int[] histSize, // 直方图横坐标的区间数
float[] ranges, // 一个列表,表示参与直方图计算的每个维度的数值范围,即横坐标的最小值和最大值,一般都是[0,256]
bool accumulate // 是否累积计算标记,一般都选false
)
说明:histSize这个参数代表直方图横坐标的区间数。如果是256,则它会将横坐标分为256份,也就是每一个像素值都要统计。如果是10,则它会将横坐标分为10份,然后统计每个区间的像素点总和。比如说第一个区间就是[0,25],第二份就是[26,51]。
二、举例
1.原始素材
原始素材定义为srcMat,如下:
2.代码
直方图均衡化代码如下:
Mat tempMat = srcMat.Clone(); // 深拷贝
Mat grayImg = new Mat();
CvInvoke.CvtColor(tempMat, grayImg, ColorConversion.Bgr2Gray);
// 定义输出的目标直方图
Mat histogram = new Mat();
// 需要统计的通道索引
int[] channelIndex = new int[] { 0 };
// 每一维数值的统计范围
float[] ranges = new float[] { 0, 256 };
// 直方图横坐标的区间数。如果是10,则它会横坐标分为10份,然后统计每个区间的像素点总和。也就是bins,表示这个直方图分成多少份(即多少个直方柱)
int[] hitSize = new int[] { 256 };
// 输入的Mat或Mat数组,并将灰度图赋值给它
VectorOfMat vMatImgs = new VectorOfMat();
vMatImgs.Push(grayImg);
// 直方图计算
CvInvoke.CalcHist(vMatImgs, channelIndex, new Mat(), histogram, hitSize, ranges, false);
// 找到直方图最大值
double minGrayValue = 0;
double maxGrayValue = 0;
System.Drawing.Point minLocationBlue = new System.Drawing.Point();
System.Drawing.Point maxLocationBlue = new System.Drawing.Point();
CvInvoke.MinMaxLoc(histogram, ref minGrayValue, ref maxGrayValue, ref minLocationBlue, ref maxLocationBlue);
// 画直方图,X轴上4个像素代表一个区间,共有256个区间
int width = 1024;
int height = 512;
Mat histShow = Mat.Zeros(height, width, DepthType.Cv8U, 1);
Image<Gray, int> histShowImage = histogram.ToImage<Gray, int>();
int grayValue = 0;
for (int i = 0; i < 256; i++)
{
grayValue = histShowImage.Data[i, 0, 0];
grayValue = (int)(512 * grayValue / maxGrayValue); // 绘制高度
CvInvoke.Rectangle(histShow, new Rectangle((4 * i) - 3, 512 - grayValue, 4, 512), new MCvScalar(255, 0, 0), -1, LineType.EightConnected, 0);
}
CvInvoke.Imshow("Gray image histogram, " + histShow.Size.ToString(), histShow);
3.运行结果
输出一张宽1024,高度为512的图片,横坐标区间数是256,也就是0到255每个值都单独统计。从原始图片也能看出来,特别亮的就是一个灯泡,而且灯泡的面积不大,剩余多数像素值都是在30到90这个区间内的。
假如上面的代码内,hitSize 参数值改变
int[] hitSize = new int[] { 10 };
像素值分成10个区间,得到的直方图应该是这样的。
原创不易,请勿抄袭。共同进步,相互学习。