一個圖像是由不同顏色值的像素組成的,像索值在圖像中的分布情況是這幅圖像的一個重要特征。圖像是由像素組成的,在一個單通道的灰度圖像中,每個像素的值介於0(黑色)-
255(白色)之間。根據圖像的內容,你會發現每個灰度值的像素數目是不同的。
直方圖是一個簡單的表,它給出了一幅圖像或一組圖像中擁有給定數值的像素數量。因此,灰度圖像的直方圖有256個條目(或稱為容器)。0號容器給出值為0的像素個數,1號容器給出值為1的像素個數,依此類推。顯然,如果你對方圖的所有項求和,會得到像素的總數。直方圖也可以被歸一化,歸一化后的所有項之和等於1。在這種情況下,每一項給出的都是擁有特定數值的像素在圖像中占的比例。
謝謝原博:http://blog.csdn.net/andrewseu/article/details/49616279
http://blog.csdn.net/garfielder007/article/details/49931049
以下是兩種提取圖像直方圖的方法:
法一:
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 }