手工實現灰度及RGB直方圖 !庫
1. 灰度圖像直方圖
算法
1. 圖片灰度化;
2. 遍歷Mat,統計各灰度級的像素個數;
3. 根據opencv畫點線函數,繪制坐標軸及像素分布圖
源碼(編譯環境:VS2017+OpenCV) 補充:三通道直方圖(即RGB彩色圖象直方圖在后面)
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 #include <opencv2/opencv.hpp> 5 #include <opencv2/imgproc/imgproc.hpp> 6 #include <opencv2/core/core.hpp> 7 #include <opencv2/highgui/highgui.hpp> 8 using namespace cv; 9 using namespace std; 10 //直方圖繪制函數,參數vector<int> nums 是灰度圖片256級灰度的像素個數 11 void drawHist(vector<int> nums) 12 { 13 Mat hist = Mat::zeros(600, 800, CV_8UC3); 14 auto Max = max_element(nums.begin(), nums.end());//max迭代器類型,最大數目 15 putText(hist, "Histogram", Point(150, 100), FONT_HERSHEY_DUPLEX, 1, Scalar(255, 255, 255)); 16 //*********繪制坐標系************// 17 Point o = Point(100, 550); 18 Point x = Point(700, 550); 19 Point y = Point(100, 150); 20 //x軸 21 line(hist, o, x, Scalar(255, 255, 255), 2, 8, 0); 22 //y軸 23 line(hist, o, y, Scalar(255, 255, 255), 2, 8, 0); 24 25 //********繪制灰度曲線***********// 26 Point pts[256]; 27 //生成坐標點 28 for (int i = 0; i < 256; i++) 29 { 30 pts[i].x = i * 2 + 100; 31 pts[i].y = 550 - int(nums[i]*(300.0/(*Max)));//歸一化到[0, 300] 32 //顯示橫坐標 33 if ((i + 1) % 16 == 0) 34 { 35 string num = format("%d", i + 1); 36 putText(hist, num, Point(pts[i].x, 570), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 255, 255)); 37 } 38 } 39 //繪制線 40 for (int i = 1; i < 256; i++) 41 { 42 line(hist, pts[i - 1], pts[i], Scalar(0, 255, 0), 2); 43 } 44 //顯示圖像 45 imshow("直方圖" ,hist); 46 } 47 //計算直方圖,統計各灰度級像素個數 48 void calHist(const string img) 49 { 50 Mat src, grey; 51 //讀取圖象 52 src = imread(img); 53 if (!src.data) 54 { 55 cout << "Image: " + img + " 讀取失敗" << endl; 56 return; 57 } 58 //先轉為灰度圖 59 cvtColor(src, grey, COLOR_BGR2GRAY); 60 imshow("灰度圖", grey); 61 //計算各灰度級像素個數 62 vector<int> nums(256); 63 for (int i = 0; i < grey.rows; i++) 64 { 65 uchar* p = grey.ptr<uchar>(i); 66 for (int j = 0; j < grey.cols; j++) 67 { 68 nums[p[j]]++; 69 } 70 } 71 drawHist(nums); 72 } 73 74 int main() 75 { 76 string img = "D:\\trashBox\\testIMG\\lena.bmp"; 77 calHist(img); 78 79 waitKey(0); 80 return 0; 81 }
效果圖
直方圖hist
2. RGB彩色圖象直方圖
源碼
#include <iostream> #include <stdlib.h> #include <string> #include <algorithm> #include <opencv2/opencv.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/video.hpp> using namespace cv; using namespace std; //單通道圖片直方圖繪制 void drawHist(vector<int> nums) { Mat hist = Mat::zeros(600, 800, CV_8UC3); auto Max = max_element(nums.begin(), nums.end());//max迭代器類型,最大數目 putText(hist, "Histogram", Point(150, 100), FONT_HERSHEY_DUPLEX, 1, Scalar(255, 255, 255)); //*********繪制坐標系************// Point o = Point(100, 550); Point x = Point(700, 550); Point y = Point(100, 150); //x軸 line(hist, o, x, Scalar(255, 255, 255), 2, 8, 0); //y軸 line(hist, o, y, Scalar(255, 255, 255), 2, 8, 0); //********繪制灰度曲線***********// Point pts[256]; //生成坐標點 for (int i = 0; i < 256; i++) { pts[i].x = i * 2 + 100; pts[i].y = 550 - int(nums[i]*(300.0/(*Max)));//歸一化到[0, 300] //顯示橫坐標 if ((i + 1) % 16 == 0) { string num = format("%d", i + 1); putText(hist, num, Point(pts[i].x, 570), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 255, 255)); } } //繪制線 for (int i = 1; i < 256; i++) { line(hist, pts[i - 1], pts[i], Scalar(0, 255, 0), 2); } //顯示圖像 imshow("直方圖" ,hist); } //三通道圖片直方圖繪制 void drawHist(vector<int> &r, vector<int> &g, vector<int> &b) { Mat hist = Mat::zeros(600, 800, CV_8UC3); putText(hist, "Histogram", Point(150, 100), FONT_HERSHEY_DUPLEX, 1, Scalar(255, 255, 255)); //*********繪制坐標系************// Point o = Point(100, 550); Point x = Point(700, 550); Point y = Point(100, 150); //x軸 line(hist, o, x, Scalar(255, 255, 255), 2, 8, 0); //y軸 line(hist, o, y, Scalar(255, 255, 255), 2, 8, 0); //********繪制灰度曲線***********// auto Max_r = max_element(r.begin(), r.end()); auto Max_g = max_element(g.begin(), g.end()); auto Max_b = max_element(b.begin(), b.end()); Point pts[3][256]; //生成坐標點 for (int i = 0; i < 256; i++) { pts[0][i].x = i * 2 + 100; pts[0][i].y = 550 - int(r[i] * (300.0 / (*Max_r)));//歸一化到[0, 300] pts[1][i].x = i * 2 + 100; pts[1][i].y = 550 - int(g[i] * (300.0 / (*Max_g)));//歸一化到[0, 300] pts[2][i].x = i * 2 + 100; pts[2][i].y = 550 - int(b[i] * (300.0 / (*Max_b)));//歸一化到[0, 300] //顯示橫坐標 if ((i + 1) % 16 == 0) { string num = format("%d", i + 1); putText(hist, num, Point(pts[0][i].x, 570), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 255, 255)); } } //繪制線 for (int i = 1; i < 256; i++) { line(hist, pts[0][i - 1], pts[0][i], Scalar(255, 0, 0), 2); line(hist, pts[1][i - 1], pts[1][i], Scalar(0, 255, 0), 2); line(hist, pts[2][i - 1], pts[2][i], Scalar(0, 0, 255), 2); } //顯示圖像 imshow("直方圖", hist); } //灰度直方圖計算 void calHist(const string img) { Mat src, grey; //讀取圖象 src = imread(img); if (!src.data) { cout << "Image: " + img + " 讀取失敗" << endl; return; } //先轉為灰度圖 cvtColor(src, grey, COLOR_BGR2GRAY); imshow("灰度圖", grey); //計算各灰度級像素個數 vector<int> nums(256); for (int i = 0; i < grey.rows; i++) { uchar* p = grey.ptr<uchar>(i); for (int j = 0; j < grey.cols; j++) { nums[p[j]]++; } } drawHist(nums); } //多通道直方圖計算 void calHist(const string img, int pattern) { Mat src, grey; //讀取圖象 src = imread(img); if (!src.data) { cout << "Image: " + img + " 讀取失敗" << endl; return; } imshow("原圖像",src); //計算各灰度級像素個數 vector<int> r(256, 0); vector<int> g(256, 0); vector<int> b(256, 0); for (int i = 0; i < src.rows; i++) { uchar* p = src.ptr<uchar>(i); for (int j = 0; j < src.cols; j++) { r[p[j * 3 + 0]]++; g[p[j * 3 + 1]]++; b[p[j * 3 + 2]]++; } } drawHist(r, g, b); } int main() { string img = "D:\\trashBox\\testIMG\\tiger.jpg"; calHist(img);//計算灰度直方圖 calHist(img, 0);//計算三色直方圖 waitKey(0); return 0; }
算法
1. 遍歷Mat,統計RGB三通道各灰度級的像素個數;
2. 根據opencv畫點線函數,繪制坐標軸及像素分布圖
效果
三色(三通道)直方圖