一个图像是由不同颜色值的像素组成的,像索值在图像中的分布情况是这幅图像的一个重要特征。图像是由像素组成的,在一个单通道的灰度图像中,每个像素的值介于0(黑色)-
255(白色)之间。根据图像的内容,你会发现每个灰度值的像素数目是不同的。
直方图是一个简单的表,它给出了一幅图像或一组图像中拥有给定数值的像素数量。因此,灰度图像的直方图有256个条目(或称为容器)。0号容器给出值为0的像素个数,1号容器给出值为1的像素个数,依此类推。显然,如果你对方图的所有项求和,会得到像素的总数。直方图也可以被归一化,归一化后的所有项之和等于1。在这种情况下,每一项给出的都是拥有特定数值的像素在图像中占的比例。
以下是两种提取图像直方图的方法:
法一:
1 // test1_320平滑处理.cpp : 定义控制台应用程序的入口点。
2 //
3
4 #include "stdafx.h"
5 #include"iostream"
6 #include<cv.h>
7 #include <opencv2/core/core.hpp>
8 #include<opencv2/imgproc/imgproc.hpp>
9 #include <opencv2/highgui/highgui.hpp>
10 using namespace std;
11 using namespace cv;
12
13
14 int _tmain(int argc, _TCHAR* argv[])
15 {
16 IplImage* src = cvLoadImage("Blind.jpg");
17 IplImage* hsv = cvCreateImage(cvGetSize(src), 8, 3);
18 IplImage* h_plane = cvCreateImage(cvGetSize(src), 8, 1);
19 IplImage* s_plane = cvCreateImage(cvGetSize(src), 8, 1);
20 IplImage* v_plane = cvCreateImage(cvGetSize(src), 8, 1);
21 IplImage* planes[] = {h_plane,s_plane};
22
23 //H分量划分为16个等级,S分量划分为8个等级
24 int h_bins = 16, s_bins = 8;
25 int hist_size[] = { h_bins, s_bins };
26
27 //H分量的变化范围
28 float h_ranges[] = { 0, 180 };
29 //S分量的变化范围
30 float s_ranges[] = { 0, 255 };
31 float* ranges[] = { h_ranges, s_ranges };
32 //输入图像转到HSV颜色空间
33 cvCvtColor(src, hsv, CV_BGR2HSV);
34 cvCvtPixToPlane(hsv, h_plane, s_plane, v_plane,0);
35 //创建直方图,二维,每个维度上均分
36 CvHistogram * hist = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1);
37 //根据H,S两个平面数据统计直方图
38 cvCalcHist(planes, hist, 0, 0);
39 //获取直方图统计的最大值,用于动态显示直方图
40 float max_value;
41 cvGetMinMaxHistValue(hist, 0, &max_value, 0, 0);
42 //设置直方图显示图像
43 int height = 240;
44 int width = (h_bins*s_bins * 6);
45 IplImage* hist_Img = cvCreateImage(cvSize(width, height), 8, 3);
46 cvZero(hist_Img);
47 //用来进行HSV到RGB颜色转换的临时单位图像
48 IplImage * hsv_color = cvCreateImage(cvSize(1, 1), 8, 3);
49 IplImage * rgb_color = cvCreateImage(cvSize(1, 1), 8, 3);
50 int bin_w = width / (h_bins*s_bins);
51 for (int h = 0; h < h_bins;h++)
52 {
53 for (int s = 0; s < s_bins;s++)
54 {
55 int i = h*s_bins + s;
56 //获取直方图中的统计次数,计算显示在图像中的高度
57 float bin_val = cvQueryHistValue_2D(hist, h, s);
58 int intensity = cvRound(bin_val*height / max_value);
59 //获取当前直方图代表的颜色,转换成RGB用于绘制
60 cvSet2D(hsv_color, 0, 0, cvScalar(h*180.f / h_bins, s*255.f / s_bins, 255,0));
61 cvCvtColor(hsv_color, rgb_color, CV_HSV2BGR);
62 CvScalar color = cvGet2D(rgb_color, 0, 0);
63 cvRectangle(hist_Img, cvPoint(i*bin_w, height),
64 cvPoint((i+1)*bin_w,height-intensity),color,-1,8,0);
65 }
66 }
67 cvNamedWindow("Source", 1);
68 cvShowImage("Source", src);
69 cvNamedWindow("H-S Histogram", 1);
70 cvShowImage("H-S Histogram", hist_Img);
71 cvWaitKey(0);
72 return 0;
73 }
法二:
1 // test2_321.cpp : 定义控制台应用程序的入口点。
2 //
3
4 #include "stdafx.h"
5 #include<iostream>
6 #include<opencv2/opencv.hpp>
7 #include <opencv2/core/core.hpp>
8 #include<opencv2/imgproc/imgproc.hpp>
9 #include <opencv2/highgui/highgui.hpp>
10 using namespace std;
11 using namespace cv;
12
13 class HistogramND
14 {
15 private:
16 Mat image;//源图像
17 int hisSize[1], hisWidth, hisHeight;//直方图的大小,宽度和高度
18 float range[2];//直方图取值范围
19 const float *ranges;
20 Mat channelsRGB[3];//分离的BGR通道
21 MatND outputRGB[3];//输出直方图分量
22 public:
23 HistogramND(){
24 hisSize[0] = 256;
25 hisWidth = 400;
26 hisHeight = 400;
27 range[0] = 0.0;
28 range[1] = 256.0;
29 ranges = &range[0];
30 }
31
32 //导入图片
33 bool importImage(String path){
34 image = imread(path);
35 if (!image.data)
36 return false;
37 return true;
38 }
39
40 //分离通道
41 void splitChannels(){
42 split(image, channelsRGB);
43 }
44
45 //计算直方图
46 void getHistogram(){
47 calcHist(&channelsRGB[0], 1, 0, Mat(), outputRGB[0], 1, hisSize, &ranges);
48 calcHist(&channelsRGB[1], 1, 0, Mat(), outputRGB[1], 1, hisSize, &ranges);
49 calcHist(&channelsRGB[2], 1, 0, Mat(), outputRGB[2], 1, hisSize, &ranges);
50
51 //输出各个bin的值
52 for (int i = 0; i < hisSize[0]; ++i){
53 cout << i << " B:" << outputRGB[0].at<float>(i);
54 cout << " G:" << outputRGB[1].at<float>(i);
55 cout << " R:" << outputRGB[2].at<float>(i) << endl;
56 }
57 }
58
59 //显示直方图
60 void displayHisttogram(){
61 Mat rgbHist[3];
62 for (int i = 0; i < 3; i++)
63 {
64 rgbHist[i] = Mat(hisWidth, hisHeight, CV_8UC3, Scalar::all(0));
65 }
66 normalize(outputRGB[0], outputRGB[0], 0, hisWidth - 20, NORM_MINMAX);
67 normalize(outputRGB[1], outputRGB[1], 0, hisWidth - 20, NORM_MINMAX);
68 normalize(outputRGB[2], outputRGB[2], 0, hisWidth - 20, NORM_MINMAX);
69 for (int i = 0; i < hisSize[0]; i++)
70 {
71 int val = saturate_cast<int>(outputRGB[0].at<float>(i));
72 rectangle(rgbHist[0], Point(i * 2 + 10, rgbHist[0].rows),
73 Point((i + 1) * 2 + 10, rgbHist[0].rows - val), Scalar(0, 0, 255), 1, 8);
74 val = saturate_cast<int>(outputRGB[1].at<float>(i));
75 rectangle(rgbHist[1], Point(i * 2 + 10, rgbHist[1].rows), Point((i + 1) * 2 + 10,
76 rgbHist[1].rows - val), Scalar(0, 255, 0), 1, 8);
77 val = saturate_cast<int>(outputRGB[2].at<float>(i));
78 rectangle(rgbHist[2], Point(i * 2 + 10, rgbHist[2].rows), Point((i + 1) * 2 + 10,
79 rgbHist[2].rows - val), Scalar(255, 0, 0), 1, 8);
80 }
81
82 cv::imshow("R", rgbHist[0]);
83 imshow("G", rgbHist[1]);
84 imshow("B", rgbHist[2]);
85 imshow("image", image);
86 }
87 };
88
89
90
91
92 int _tmain(int argc, _TCHAR* argv[])
93 {
94 String path = "D:\\LiHong\\Blind Way Recognition\\MyProject\\test2_321\\test2_321\\Blind.jpg";
95 /*cv::Mat img = cv::imread("Blind.jpg");*/
96 HistogramND hist;
97 /*if (!img.data)
98 {
99 return -1;
100 }*/
101 if (!hist.importImage(path)){
102 cout << "Import Error!" << endl;
103 return -1;
104 }
105 hist.splitChannels();
106 hist.getHistogram();
107 hist.displayHisttogram();
108 cv::waitKey();
109
110
111 return 0;
112 }