opencv-017-图像直方图

知识点

图像直方图的解释
图像直方图是图像像素值的统计学特征、计算代价较小,具有图像平移、旋转、缩放不变性等众多优点,广泛地应用于图像处理的各个领域,特别是灰度图像的阈值分割、基于颜色的图像检索以及图像分类、反向投影跟踪。常见的分为

  • 灰度直方图
  • 颜色直方图

Bins是指直方图的大小范围, 对于像素值取值在0~255之间的,最少有256个bin,此外还可以有16、32、48、128等,256除以bin的大小应该是整数倍。

OpenCV中相关API
calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges);
cv.calcHist([image], [i], None, [256], [0, 256])

代码(c++,python)

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
61
62
63
64
65
66
67
68
#include <iostream>
#include <opencv2/opencv.hpp>
#include <vector>

using namespace std;
using namespace cv;

const int bins = 256;
Mat src;
const char *winTitle = "input image";

void showHistogram();

/*
* 图像直方图
*/
int main() {
src = imread("../images/test.png");
if (src.empty()) {
cout << "could not load image.." << endl;
}
imshow(winTitle, src);
showHistogram();

waitKey(0);
return 0;
}

void showHistogram() {
// 三通道分离
vector<Mat> bgr_plane;
split(src, bgr_plane);
// 定义参数变量
const int channels[1] = {0};
const int bins[1] = {256};
float hranges[2] = {0, 255};
const float *ranges[1] = {hranges};
Mat b_hist, g_hist, r_hist;
// 计算三通道直方图
calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges);
calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges);
/*
* 显示直方图
*/
int hist_w = 512;
int hist_h = 400;
int bin_w = cvRound((double) hist_w / bins[0]);
Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
// 归一化直方图数据
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1);
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1);
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1);
// 绘制直方图曲线
for (int i = 1; i < bins[0]; ++i) {
line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0),
2, 8, 0);
line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0),
2, 8, 0);
line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255),
2, 8, 0);

}
imshow("Histogram", histImage);
}
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
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt


def custom_hist(gray):
h, w = gray.shape
hist = np.zeros([256], dtype=np.int32)
for row in range(h):
for col in range(w):
pv = gray[row, col]
hist[pv] += 1

y_pos = np.arange(0, 256, 1, dtype=np.int32)
plt.bar(y_pos, hist, align='center', color='r', alpha=0.5)
plt.xticks(y_pos, y_pos)
plt.ylabel('Frequency')
plt.title('Histogram')

# plt.plot(hist, color='r')
# plt.xlim([0, 256])
plt.show()


def image_hist(image):
cv.imshow("input", image)
color = ('blue', 'green', 'red')
for i, color in enumerate(color):
hist = cv.calcHist([image], [i], None, [256], [0, 256])
plt.plot(hist, color=color)
plt.xlim([0, 256])
plt.show()


src = cv.imread("../images/test.png")
cv.namedWindow("input", cv.WINDOW_AUTOSIZE)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
cv.imshow("input", gray)
#custom_hist(gray)
image_hist(src)
cv.waitKey(0)
cv.destroyAllWindows()

结果

代码地址

github