【歡迎關注編碼小哥,學習更多實用的編程方法和技巧】
1、直方圖的計算
cv::calcHist
?是 OpenCV 中用于計算圖像直方圖的函數。它可以處理多通道圖像,并通過指定圖像、通道、掩膜、直方圖大小和范圍等參數來生成直方圖。
函數原型
void cv::calcHist(const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform = true, bool accumulate = false)
參數
- images: 要計算的原圖,類型為?
const Mat*
,表示一個圖像數組。 - nimages: 圖像數組的大小,類型為?
int
。 - channels: 指定計算的通道,類型為?
const int*
,表示一個通道數組。每個通道對應一個圖像。 - mask: 用于計算特定區域的掩膜,類型為?
InputArray
,表示一個圖像或矩形區域。 - hist: 輸出的直方圖,類型為?
OutputArray
,表示一個多維數組。 - dims: 直方圖的維度,類型為?
int
,表示直方圖的維度。 - histSize: 直方圖的大小,類型為?
const int*
,表示一個大小數組,每個大小對應一個維度。 - ranges: 像素值范圍,類型為?
const float**
,表示一個范圍數組,每個范圍對應一個維度。 - uniform: 是否使用均勻的直方圖,類型為?
bool
,默認為?true
。 - accumulate: 是否累積計算結果,類型為?
bool
,默認為?false
。
返回值
- 無返回值,該函數直接修改輸出直方圖。
-
#include <opencv2/opencv.hpp>int main() {// 讀取圖像cv::Mat img = cv::imread("image.jpg");// 計算灰度圖直方圖cv::Mat gray;cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);int histSize = 256;float range[] = {0, 256};cv::Mat hist;cv::calcHist(&gray, 1, &0, cv::Mat(), hist, 1, &histSize, &range);// 計算彩色圖直方圖int channels[] = {0, 1, 2};cv::Mat hist_b, hist_g, hist_r;cv::calcHist(&img, 1, channels, cv::Mat(), hist_b, 1, &histSize, &range);cv::calcHist(&img, 1, channels + 1, cv::Mat(), hist_g, 1, &histSize, &range);cv::calcHist(&img, 1, channels + 2, cv::Mat(), hist_r, 1, &histSize, &range);// 繪制直方圖cv::Mat hist_img(256, 256, CV_8UC3);cv::normalize(hist, hist, 0, hist_img.rows, cv::NORM_MINMAX);for (int i = 0; i < histSize; i++) {cv::line(hist_img, cv::Point(i, hist_img.rows), cv::Point(i, hist_img.rows - cvRound(hist.at<float>(i))), cv::Scalar(255, 0, 0));}cv::imshow("Histogram", hist_img);cv::waitKey(0);cv::destroyAllWindows();return 0; }
cv::calcHist
?函數可以處理多通道圖像,但必須指定計算的通道。cv::calcHist
?函數可以計算多個直方圖,但必須具有相同的尺寸和類型。cv::calcHist
?函數可以累積計算結果,但必須指定輸出直方圖。
2、一維直方圖的繪制
一維直方圖是一種常見的數據可視化方法,用于顯示數據的分布情況。在 OpenCV 中,可以使用以下步驟繪制一維直方圖:
- 計算直方圖:使用?
cv::calcHist
?函數計算圖像的直方圖。 - 歸一化直方圖:使用?
cv::normalize
?函數將直方圖歸一化到指定的范圍。 - 繪制直方圖:使用?
cv::line
?函數繪制直方圖。
#include <opencv2/opencv.hpp>int main() {// 讀取圖像cv::Mat img = cv::imread("image.jpg");// 計算灰度圖直方圖cv::Mat gray;cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);int histSize = 256;float range[] = {0, 256};cv::Mat hist;cv::calcHist(&gray, 1, &0, cv::Mat(), hist, 1, &histSize, &range);// 歸一化直方圖cv::Mat hist_norm;cv::normalize(hist, hist_norm, 0, 256, cv::NORM_MINMAX);// 繪制直方圖cv::Mat hist_img(256, 256, CV_8UC3);for (int i = 0; i < histSize; i++) {cv::line(hist_img, cv::Point(i, hist_img.rows), cv::Point(i, hist_img.rows - cvRound(hist_norm.at<float>(i))), cv::Scalar(255, 0, 0));}// 顯示直方圖cv::imshow("Histogram", hist_img);cv::waitKey(0);cv::destroyAllWindows();return 0;
}
?在這個示例中,我們首先讀取一張圖像,然后計算其灰度圖直方圖。接著,我們將直方圖歸一化到 0-256 的范圍,然后繪制直方圖。最后,我們顯示直方圖。
注意:在繪制直方圖時,我們使用?cv::line
?函數繪制每個直方圖條。我們將直方圖條的高度設置為?hist_img.rows - cvRound(hist_norm.at<float>(i))
,以便直方圖條的高度與直方圖值成比例。
如果想繪制彩色圖直方圖,可以使用以下代碼:
// 計算彩色圖直方圖
int channels[] = {0, 1, 2};
cv::Mat hist_b, hist_g, hist_r;
cv::calcHist(&img, 1, channels, cv::Mat(), hist_b, 1, &histSize, &range);
cv::calcHist(&img, 1, channels + 1, cv::Mat(), hist_g, 1, &histSize, &range);
cv::calcHist(&img, 1, channels + 2, cv::Mat(), hist_r, 1, &histSize, &range);// 歸一化直方圖
cv::Mat hist_b_norm, hist_g_norm, hist_r_norm;
cv::normalize(hist_b, hist_b_norm, 0, 256, cv::NORM_MINMAX);
cv::normalize(hist_g, hist_g_norm, 0, 256, cv::NORM_MINMAX);
cv::normalize(hist_r, hist_r_norm, 0, 256, cv::NORM_MINMAX);// 繪制直方圖
cv::Mat hist_img(256, 256, CV_8UC3);
for (int i = 0; i < histSize; i++) {cv::line(hist_img, cv::Point(i, hist_img.rows), cv::Point(i, hist_img.rows - cvRound(hist_b_norm.at<float>(i))), cv::Scalar(255, 0, 0));cv::line(hist_img, cv::Point(i, hist_img.rows), cv::Point(i, hist_img.rows - cvRound(hist_g_norm.at<float>(i))), cv::Scalar(0, 255, 0));cv::line(hist_img, cv::Point(i, hist_img.rows), cv::Point(i, hist_img.rows - cvRound(hist_r_norm.at<float>(i))), cv::Scalar(0, 0, 255));
}
在這個示例中,我們計算彩色圖的直方圖,然后歸一化直方圖。接著,我們繪制直方圖,每個通道使用不同的顏色。
3、多維直方圖的繪制?
2D直方圖是一種用于表示兩個變量之間關系的數據可視化方法。在 OpenCV 中,可以使用以下步驟繪制 2D 直方圖:
- 計算直方圖:使用?
cv::calcHist
?函數計算圖像的直方圖。 - 歸一化直方圖:使用?
cv::normalize
?函數將直方圖歸一化到指定的范圍。 - 繪制直方圖:使用?
cv::imshow
?函數顯示直方圖。
以下是示例代碼:
#include <opencv2/opencv.hpp>int main() {// 讀取圖像cv::Mat img = cv::imread("image.jpg");// 計算 2D 直方圖int channels[] = {0, 1};int histSize[] = {256, 256};float range[] = {0, 256, 0, 256};cv::Mat hist;cv::calcHist(&img, 1, channels, cv::Mat(), hist, 2, histSize, range);// 歸一化 2D 直方圖cv::Mat hist_norm;cv::normalize(hist, hist_norm, 0, 256, cv::NORM_MINMAX);// 繪制 2D 直方圖cv::Mat hist_img(256, 256, CV_8UC3);for (int i = 0; i < 256; i++) {for (int j = 0; j < 256; j++) {int index = i * 256 + j;cv::Vec3b color = cv::Vec3b(i, j, 0);hist_img.at<cv::Vec3b>(i, j) = color * (hist_norm.at<float>(index) / 256.0f);}}// 顯示 2D 直方圖cv::imshow("2D Histogram", hist_img);cv::waitKey(0);cv::destroyAllWindows();return 0;
}
?在這個示例中,我們計算 2D 直方圖,然后歸一化 2D 直方圖。接著,我們繪制 2D 直方圖,每個像素的顏色根據 2D 直方圖值計算。
注意:在繪制 2D 直方圖時,我們使用?cv::Vec3b
?類型表示顏色,每個顏色通道的值根據 2D 直方圖值計算。
如果想繪制 3D 直方圖,可以使用以下代碼:
// 計算 3D 直方圖
int channels[] = {0, 1, 2};
int histSize[] = {256, 256, 256};
float range[] = {0, 256, 0, 256, 0, 256};
cv::Mat hist;
cv::calcHist(&img, 1, channels, cv::Mat(), hist, 3, histSize, range);// 歸一化 3D 直方圖
cv::Mat hist_norm;
cv::normalize(hist, hist_norm, 0, 256, cv::NORM_MINMAX);// 繪制 3D 直方圖
cv::Mat hist_img(256, 256, CV_8UC3);
for (int i = 0; i < 256; i++) {for (int j = 0; j < 256; j++) {for (int k = 0; k < 256; k++) {int index = i * 256 * 256 + j * 256 + k;cv::Vec3b color = cv::Vec3b(i, j, k);hist_img.at<cv::Vec3b>(i, j) = color * (hist_norm.at<float>(index) / 256.0f);}}
}// 顯示 3D 直方圖
cv::imshow("3D Histogram", hist_img);
cv::waitKey(0);
cv::destroyAllWindows();