一開始是看《OpenCV計算機視覺編程攻略(第2版)》這本書學做直方圖,但是書本里說直方圖的部分只詳細說了黑白圖像(單通道)的直方圖繪制方法,RGB圖像的直方圖只說了如何計算,沒有說計算完之后如何繪制,自己想了很久也沒想到正確的繪制方法。
去查OpenCV的官方文檔,里面的例子只說了如何繪制H和S兩通道的直方圖,很多函數的用法也沒搞清楚。
后來在網上看別人的程序,找到有繪制HSV三通道直方圖的程序,花了一點時間一行一行地看,並且結合自己已經學過的知識把程序改成繪制RGB三通道的直方圖的程序。
histogram.h:
#ifndef HISTOGRAM_H #define HISTOGRAM_H #include <opencv2\opencv.hpp> #include <iostream> #include <string> class Histogram { private: int histSize[3]; //直方圖中箱子的數量 float hranges[2]; //值范圍 const float * ranges[3]; //值范圍的指針 int channels[3]; //要檢查的通道數量 public: Histogram(); cv::Mat getHistogram(const cv::Mat & image); std::vector<cv::Mat> getHistogramImage(const cv::Mat & image, int zoom = 1); static std::vector<cv::Mat> getImageOfHistogram(const cv::Mat & hist, int zoom); }; #endif
histogram.cpp:
#include "histogram.h" Histogram::Histogram() { histSize[0] = 256; histSize[1] = 256; histSize[2] = 256; hranges[0] = 0.0; hranges[1] = 256.0; ranges[0] = hranges; ranges[1] = hranges; ranges[2] = hranges; channels[0] = 0; channels[1] = 1; channels[2] = 2; } cv::Mat Histogram::getHistogram(const cv::Mat & image) { cv::Mat hist; hranges[0] = 0.0; hranges[1] = 256.0; channels[0] = 0; channels[1] = 1; channels[2] = 2; cv::calcHist(&image, 1, channels, cv::Mat(), hist, 3, histSize, ranges); return hist; } std::vector<cv::Mat> Histogram::getHistogramImage(const cv::Mat & image, int zoom) { cv::Mat hist = getHistogram(image); return Histogram::getImageOfHistogram(hist, zoom); } std::vector<cv::Mat> Histogram::getImageOfHistogram(const cv::Mat & hist, int zoom) { int scale = 2; float hist_b[256]; float hist_g[256]; float hist_r[256];
memset(hist_b, 0, 256 * sizeof(float)); memset(hist_g, 0, 256 * sizeof(float)); memset(hist_r, 0, 256 * sizeof(float)); //計算三個通道的直方圖 for(int b = 0; b < 256; b ++ ) { for(int g = 0; g < 256; g ++) { for(int r = 0; r < 256; r ++) { float binVal = hist.at<float>(b, g, r); hist_b[b] += binVal; hist_g[g] += binVal; hist_r[r] += binVal; } } } //獲得三個通道直方圖中的最大值 double max_b = 0.0, max_g = 0.0,max_r = 0.0; for(int i = 0; i < 256; i ++) { if(hist_b[i] > max_b) { max_b = hist_b[i]; } } for(int i = 0; i < 256; i ++) { if(hist_g[i] > max_g) { max_g = hist_g[i]; } } for(int i = 0; i < 256; i ++) { if(hist_r[i] > max_r) { max_r = hist_r[i]; } } //初始化空的圖 cv::Mat b_img = cv::Mat::zeros(256, 256 * scale, CV_8UC3); cv::Mat g_img = cv::Mat::zeros(256, 256 * scale, CV_8UC3); cv::Mat r_img = cv::Mat::zeros(256, 256 * scale, CV_8UC3); //繪制三個通道的直方圖 for(int i = 0; i < 256; i ++) { int intensity = cvRound(hist_b[i] * b_img.rows / max_b); cv::rectangle(b_img, cv::Point(i * scale, b_img.rows - intensity), cv::Point((i + 1) * scale - 1, b_img.rows - 1), cv::Scalar(255, 0 ,0), 1); } for(int i = 0; i < 256; i ++) { int intensity = cvRound(hist_g[i] * g_img.rows / max_g); cv::rectangle(g_img, cv::Point(i * scale, g_img.rows - intensity), cv::Point((i + 1) * scale - 1, g_img.rows - 1), cv::Scalar(0, 255, 0), 1); } for(int i = 0; i < 256; i ++) { int intensity = cvRound(hist_r[i] * r_img.rows / max_r); cv::rectangle(r_img, cv::Point(i * scale, r_img.rows - intensity), cv::Point((i + 1) * scale - 1, r_img.rows - 1), cv::Scalar(0, 0, 255), 1); } std::vector<cv::Mat> imgs; imgs.push_back(b_img); imgs.push_back(g_img); imgs.push_back(r_img); return imgs; }
main.cpp:
#include <opencv2\opencv.hpp> #include <iostream> #include <string> #include "histogram.h" using namespace std; int main() { cv::Mat image = cv::imread("animal.jpg"); cv::imshow("image", image); Histogram h; std::vector<cv::Mat> imgs = h.getHistogramImage(image); cv::namedWindow("B"); cv::imshow("B", imgs[0]); cv::namedWindow("G"); cv::imshow("G", imgs[1]); cv::namedWindow("R"); cv::imshow("R", imgs[2]); cv::waitKey(); return 0; }
運行結果:

參考資料:
http://blog.csdn.net/ljbkiss/article/details/7420429
