函数说明
函数原型1 | void CalcHist(Mat[] images, int[] channels, InputArray? mask, OutputArray hist, int dims, int[] histSize, float[][] ranges, bool uniform = true, bool accumulate = false) | |
函数原型2 | void CalcHist(Mat[] images, int[] channels, InputArray? mask, OutputArray hist, int dims, int[] histSize, Rangef[] ranges, bool uniform = true, bool accumulate = false) | |
功能说明 | 计算一个或多个图像的直方图 | |
参数 | 说明 | 示例 |
Mat[] images | 一个或多个图像;多个图像的话,深度Depth或大小Size必须相同,类型为 CV_8U、 CV_16U 或 CV_32F | new []{src1,src2} |
int[] channels | 待计算的通道数组 | new []{0,1,2} |
InputArray? mask | 图像掩膜,可为空,不为空的话必须与images的大小相同的8位数组 | null 或 mat |
OutputArray hist | 输出对应dims维直方图数组 | outpputMat |
int dims | 输出的维数,正整数小于等于CV_MAX_DIMS(当前是32) | 1 |
int[] histSize | 每个维度的直方图数组大小(将ranges[i]分为histSize份) | new[] { 256 } |
float[][] ranges | 每个维度的直方图数组的边界 uniform为true时,只填写一个ranges范围就可以了,对应下限边界(包含)L0和上限边界UhistSize[i]-1; uniform为false时, | new[] { new Rangef(0, 256) } 实现统计为0到255 |
bool uniform = true | 是否统一(均匀) | true 或 false |
bool accumulate = false | 累积标志。可累积多个图像的直方图 | false 或 true |
//直方图均衡化,提高图像对比度
void EqualizeHist(InputArray src, //待均衡化8位单通道图像
OutputArray dst)//均衡化后的图像,与输入图像有相同的大小和类型
调用示例
public void Run()
{
//注意图像路径
using var src = Cv2.ImRead(ImagePath.LenaColor);
if (src.Empty()) throw new Exception("图像读取有误");
Cv2.ImShow("Src", src);
//统计BGR直方图
GetHistResult(src, out Mat histBGR, out Mat histBGRImage);
using var hsvSrc = src.CvtColor(ColorConversionCodes.BGR2HSV);
//统计HSV直方图
GetHistResult(hsvSrc, out _, out Mat histHSVImage);
Cv2.NamedWindow("histBGRImage", WindowFlags.Normal);
Cv2.ImShow("histBGRImage", histBGRImage);
Cv2.NamedWindow("histHSVImage", WindowFlags.Normal);
Cv2.ImShow("histHSVImage", histHSVImage);
//转为灰度图
using var srcGray = src.CvtColor(ColorConversionCodes.BGR2GRAY);
Cv2.ImShow("srcGray", srcGray);
//直方图均衡化必须为8位单通道
Cv2.EqualizeHist(srcGray, srcGray);
//均衡化后的灰度图
Cv2.ImShow("srcGrayEQ", srcGray);
//计算均衡化后的直方图
GetHistResult(srcGray, out _, out Mat histGrayImage);
Cv2.ImShow("histGrayImage", histGrayImage);
//分离通道
var splits = src.Split();
string[] bgr = new string[] { "Blue", "Green", "Red" };
Mat[] EqualizeHistMat = new Mat[3];
int i = 0;
foreach (var matSplit in splits)
{
Cv2.EqualizeHist(matSplit, matSplit);
GetHistResult(matSplit, out _, out Mat histSplitMat);
Cv2.ImShow($"EqualizeHist of {bgr[i]}", histSplitMat);
EqualizeHistMat[i] = matSplit;
i++;
}
using var megreMat = new Mat();
//合并各通道均衡化的图像
Cv2.Merge(EqualizeHistMat, megreMat);
Cv2.ImShow($"Merge BGR EqualizeHist", megreMat);
Cv2.WaitKey();
Cv2.DestroyAllWindows();
}
/// <summary>
/// 计算并生成绘制直方图
/// </summary>
/// <param name="src">待统计的图像</param>
/// <param name="hist">直方图结果</param>
/// <param name="histImage">直方图的绘制结果</param>
private void GetHistResult(Mat src, out Mat hist, out Mat histImage)
{
hist = new Mat();
const int histW = 512;
const int histH = 400;
histImage = new Mat(histH, histW, MatType.CV_8UC3, Scalar.All(0));
int histSize = 64;//直方图数组大小
var range = new Rangef(0, 256);//统计0至255(=266-1)
//将图像像素灰度[0,255]共分为64个等级统计,
//即值为[0,3]、[4,7]...和[252,255]分别统计,每个范围内的像素个数
for (int channel = 0; channel < src.Channels(); channel++)
{
Cv2.CalcHist(images: new[] { src },//待统计的图像
channels: new[] { channel },//待统计的通道
mask: null,//掩膜
hist: hist,//输出的统计结果
dims: 1,//直方图维度
histSize: new[] { histSize },//将range分为histSize梯度
ranges: new[] { range });//待统计通道像素的范围,不在这个范围内的不统计
DrawHist(histImage, hist, (channel == 0 ? Scalar.Blue : (channel == 1 ? Scalar.Green : Scalar.Red)));
}
}
/// <summary>
/// 绘制直方图
/// </summary>
/// <param name="histImage">直方图绘制结果</param>
/// <param name="histSize">直方图数组大小</param>
/// <param name="color">线的颜色</param>
private void DrawHist(Mat histImage, Mat hist, Scalar color)
{
var binW = Math.Round((double)histImage.Width / hist.Height);
//归一化
Cv2.Normalize(hist, hist, 0, histImage.Rows, NormTypes.MinMax, -1);
for (int i = 1; i < hist.Height; i++)
{
var pt1 = new Point2d(binW * (i - 1), histImage.Height - Math.Round(hist.At<float>(i - 1)));
var pt2 = new Point2d(binW * (i), histImage.Height - Math.Round(hist.At<float>(i)));
Cv2.Line(histImage, (Point)pt1, (Point)pt2, color, 1, LineTypes.AntiAlias);
}
}