Theory :
从图形上看,灰度直方图是一个二维图:
图像的灰度直方图是一个离散函数,它表示图像每一灰度级与该灰度级出现频率的对应关系。假设一幅图像的像素总数为 N,灰度级总数为 L,其中灰度级为 g 的像素总数为 Ng,则这幅数字图像的灰度直方图横坐标即为灰度 g ( 0 ≤ g ≤ L-1 ),纵坐标则为灰度值出现的次数 Ng。实际上,用 N 去除各个灰度值出现的次数 Ng 即可得到各个灰度级出现的概率 Pg = Ng / N = Ng / ∑Ng ,从而得到归一化的灰度直方图,其纵坐标为概率 Pg 。
Quote : ( From [OpenCV 2 Computer Vision Application Programming Cookbook (Robert Langaniere, 2011) ], 引用作直方图的解释 )
Implementation :
利用 OpenCV 提供的 calcHist 函数 :
void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false );
这个函数用于计算直方图是很强大的,在这里就实现一个最简单的灰度图像的直方图计算。
Code :
1: int main()2: {
3: Mat img = imread("lena.jpg", CV_LOAD_IMAGE_GRAYSCALE);4:
5: Mat* arrays = &img;
6: int narrays = 1;7: int channels[] = { 0 };8: InputArray mask = noArray();
9: Mat hist;
10: int dims = 1;11: int histSize[] = { 256 };12: float hranges[] = { 0.0, 255.0 };13: const float *ranges[] = { hranges };14: //调用 calcHist 计算直方图, 结果存放在 hist 中15: calcHist(arrays, narrays, channels, mask, hist, dims, histSize, ranges);
16:
17: //调用一个我自己写的简单的函数用于获取一张显示直方图数据的图片,18: //输入参数为直方图数据 hist 和期望得到的图片的尺寸19: Mat histImg = ggicci::getHistogram1DImage(hist, Size(600, 420));
20: imshow("lena gray image histogram", histImg);21: waitKey();
22: }
23:
24: Mat ggicci::getHistogram1DImage(const Mat& hist, Size imgSize)25: {
26: Mat histImg(imgSize, CV_8UC3);
27: int Padding = 10;28: int W = imgSize.width - 2 * Padding;29: int H = imgSize.height - 2 * Padding;30: double _max;31: minMaxLoc(hist, NULL, &_max);
32: double Per = (double)H / _max;33: const Point Orig(Padding, imgSize.height-Padding);34: int bin = W / (hist.rows + 2);35:
36: //画方柱37: for (int i = 1; i <= hist.rows; i++)38: {
39: Point pBottom(Orig.x + i * bin, Orig.y);
40: Point pTop(pBottom.x, pBottom.y - Per * hist.at<float>(i-1));41: line(histImg, pBottom, pTop, Scalar(255, 0, 0), bin);
42: }
43:
44: //画 3 条红线标明区域45: line(histImg, Point(Orig.x + bin, Orig.y - H), Point(Orig.x + hist.rows * bin, Orig.y - H), Scalar(0, 0, 255), 1);
46: line(histImg, Point(Orig.x + bin, Orig.y), Point(Orig.x + bin, Orig.y - H), Scalar(0, 0, 255), 1);
47: line(histImg, Point(Orig.x + hist.rows * bin, Orig.y), Point(Orig.x + hist.rows * bin, Orig.y - H), Scalar(0, 0, 255), 1);
48: drawArrow(histImg, Orig, Orig+Point(W, 0), 10, 30, Scalar::all(0), 2);
49: drawArrow(histImg, Orig, Orig-Point(0, H), 10, 30, Scalar::all(0), 2);
50:
51: return histImg;52: }
Result :