Ink One

OpenCV 学习笔记(2)

直方图计算与均衡化。

函数说明

calcHist

计算直方图。
在官方文档中的定义为:

1
2
3
4
5
6
7
8
9
10
void calcHist(const Mat* images,
int nimages,
const int* channels,
InputArray mask,
OutputArray hist,
int dims,
const int* histSize,
const float** ranges,
bool uniform=true,
bool accumulate=false)

参数说明

  • images - 一些原图,应该具有相同的深度,CV_8U 或者 CV_32F,以及相同的尺寸。它们可以具有任意的通道数。
  • nimages - 原图数
  • channels - 用于计算直方图的通道的列表。通道列表的第一个元素取值为 0 到 images[0].channels()-1 ,第二个元素取值为 images[0].channels()images[0].channels()+images[1].channels()-1 ,以此类推。
  • mask - 可选的掩码矩阵。如果该矩阵非空,它应该为 8-bit 的数组,并与 images[i] 具有相同的尺寸。非零的元素标记了直方图中需要计算的数组元素。
  • hist - 输出直方图
  • dims - 直方图维度,为正数且不大于 CV_MAX_DIMS(在当前 OpenCV 版本中该值为 32)。
  • histSize - 每个维度下直方图项的数量构成的数组。
  • ranges - 每个维度下直方图像素值的范围构成的数组。
    • 如果直方图设置归一(uniform = true),则对于每个维度 i ,可以标记第0个直方图的下边界为 $L_0$ ,最后一个直方图 histSize[i]-1 的上边界为 $U_{histSize[i]-1}$ ,即每一个 ranges[i] 都是具有两个元素的数组。
    • 如果直方图不归一(uniform = false),则每个 ranges[i] 包含 histSize[i]+1 个元素: $L_0$, $U_0=L_1$ , $U_1=L_2$ , … , $U_{histSize[i]-2}=L_{histSize[i]-2}$ , $U_{histSize[i]-1}$ 。不在 $L_0$ 和 $U_{histSize[i]-1}$ 范围内的数组元素不计算在直方图中。
  • uniform - 标识直方图是否归一
  • accumulate - 累积标识。如果 accumulate = true,直方图在被分配时不会清零。

minMaxLoc

定位最小值和最大值。
在官方文档中的定义为:

1
2
3
4
void minMaxLoc(InputArray src,
double* minVal, double* maxVal=0,
Point* minLoc=0, Point* maxLoc=0,
InputArray mask=noArray())

参数说明

  • src - 输入的单通道数组
  • minVal - 指向最小值的指针
  • maxVal - 指向最大值的指针
  • minVal - 指向最小值位置的指针(2维情况下)
  • maxVal - 指向最大值位置的指针(2维情况下)
  • mask - 可选掩码

line

绘制线段。
在官方文档中的定义为:

1
2
void line(Mat& img, Point pt1, Point pt2, const Scalar& color,
int thickness=1, int lineType=8, int shift=0)

参数说明

  • img - 绘制线段的图像
  • pt1 - 线段的一个端点
  • pt2 - 线段的第二个端点
  • color - 线段颜色
  • thickness - 线段粗细
  • lineType - 线段类型
    • 8 - 8连通线段
    • 4 - 4连通线段
    • CV_AA - 消除锯齿的线段
  • shift - 点坐标的小数点位数

equalizeHist

均衡化灰度图的直方图。
在官方文档中的定义为:

1
void equalizeHist(InputArray src, OutputArray dst)

参数说明

  • src - 8-bit单通道的原图像
  • dst - 均衡化直方图后的图像,与原图具有相同的尺寸和类型。

程序实现

计算下图的直方图并进行直方图均衡化。
source image
点此下载

实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <opencv2\opencv.hpp>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
using namespace cv;
using namespace std;
Mat getHistogram(const Mat &srcImage)
{
//计算直方图
MatND hist;
int channel = 0;
int dims = 1;
int size = 256;
float hranges[] = { 0, 255 };
const float *ranges[] = { hranges };
calcHist(&srcImage, 1, &channel, Mat(), hist, dims, &size, ranges);
//获取最大值和最小值
double minVal = 0, maxVal = 0;
minMaxLoc(hist, &minVal, &maxVal, 0, 0);
//显示直方图
Mat dstImage(size, size, CV_8U, Scalar(255));
int hpt = static_cast<int>(size);
for (int i = 0; i < size; i++) {
//计算直方图高度
float binVal = hist.at<float>(i);
int intVal = static_cast<int>(binVal*hpt / maxVal);
//两点之间绘制一条线段
line(dstImage, Point(i, size), Point(i, size - intVal), Scalar(0));
}
return dstImage;
}
int main()
{
//读取原图
Mat srcImage = imread("orange.jpg", 0);
imshow("source Image", srcImage);
if (!srcImage.data)
{
cout << "fail to load image!" << endl;
}
//计算直方图
Mat hist1;
hist1 = getHistogram(srcImage);
imshow("source Histogram", hist1);
imwrite("srcHist.jpg", hist1);
//计算均衡化图
Mat dstImage;
equalizeHist(srcImage, dstImage);
imshow("equalized Image", dstImage);
imwrite("dstImage.jpg", dstImage);
//计算均衡化直方图
Mat hist2;
hist2 = getHistogram(dstImage);
imshow("equalized Histogram", hist2);
imwrite("dstHist.jpg", hist2);
waitKey(0);
}

运行结果

  1. 原图

    source image
  2. 原图直方图

    source hist
  3. 均衡化图

    equalized image
  4. 均衡化直方图

    equalized hist