基于C++/opencv 提取图像的直方图
一个图像是由不同颜色值的像素组成的,像索值在图像中的分布情况是这幅图像的一个重要特征。图像是由像素组成的,在一个单通道的灰度图像中,每个像素的值介于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 }