C++ OpenCV繪制簡易直方圖DrawHistImg

需求說明

在對圖像進行處理時,經常會有這類需求:想要觀察圖像的直方圖分佈,例如灰度圖中0-255區間數值的分佈情況,從而可以進行後續的操作,如閾值分割二值化、直方圖均衡化等等。本文設計瞭一個能繪制簡易直方圖的簡單函數DrawHistImg,可以幫助大傢快速掌握繪制的原理,可以根據自己的創意對其進行改善和補充。

下面介紹具體實現流程。

具體流程

1)取圖像的灰度圖,並遍歷統計0-255各個灰度值所出現的次數。

cv::Mat src = imread("test.jpg", 0);
cv::Mat hist = cv::Mat::zeros(1, 256, CV_32FC1);
for (int i = 0; i < src.rows; ++i)
{
	for (int j = 0; j < src.cols; ++j)
	{
		hist.at<float>(0, src.at <uchar>(i, j))++;
	}
}

2)定義直方圖圖像histImage,並初始化一些參數。其中bins是數值最大值,即255;scale為每個灰度值所對應的直方圖寬度;histHeight為直方圖高度最大值,也是直方圖圖像的寬。

cv::Mat histImage = cv::Mat::zeros(540, 1020, CV_8UC1);
const int bins = 255;
int scale = 4;
int histHeight = 540;

3)利用minMaxLoc函數得出哪個灰度值的出現次數最高,為歸一化做準備。

double maxValue;
cv::Point2i maxLoc;
cv::minMaxLoc(hist, 0, &maxValue, 0, &maxLoc);

4)遍歷hist中每個灰度值,並根據其出現次數繪制直方圖,height是歸一化後的高度。

for (int i = 0; i < bins; i++)
{
	float binValue = (hist.at<float>(i));
	int height = cvRound(binValue * histHeight / maxValue);
	cv::rectangle(histImage, cv::Point(i * scale, histHeight),
		cv::Point((i + 1) * scale - 1, histHeight - height), cv::Scalar(255), -1);
 
}

5)函數執行完畢。 

功能函數

// 繪制簡易直方圖
cv::Mat DrawHistImg(cv::Mat &src)
{
	cv::Mat hist = cv::Mat::zeros(1, 256, CV_32FC1);
	for (int i = 0; i < src.rows; ++i)
	{
		for (int j = 0; j < src.cols; ++j)
		{
			hist.at<float>(0, src.at <uchar>(i, j))++;
		}
	}
	cv::Mat histImage = cv::Mat::zeros(540, 1020, CV_8UC1);
	const int bins = 255;
	double maxValue;
	cv::Point2i maxLoc;
	cv::minMaxLoc(hist, 0, &maxValue, 0, &maxLoc);
	int scale = 4; 
	int histHeight = 540;
 
	for (int i = 0; i < bins; i++)
	{
		float binValue = (hist.at<float>(i));
		int height = cvRound(binValue * histHeight / maxValue);
		cv::rectangle(histImage, cv::Point(i * scale, histHeight),
			cv::Point((i + 1) * scale - 1, histHeight - height), cv::Scalar(255), -1);
 
	}
	return histImage;
}

C++測試代碼

#include <iostream>
#include <time.h>
#include <opencv2/opencv.hpp>
 
using namespace std;
using namespace cv;
 
cv::Mat DrawHistImg(cv::Mat &hist);
 
int main()
{
	cv::Mat src = imread("test.jpg", 0);
 
	// 繪制均衡化後直方圖
	cv::Mat hrI = DrawHistImg(src);
 
	imshow("original", src);
	imshow("hist", hrI);
	waitKey(0);
 
	return 0;
}
 
 
// 繪制簡易直方圖
cv::Mat DrawHistImg(cv::Mat &src)
{
	cv::Mat hist = cv::Mat::zeros(1, 256, CV_32FC1);
	for (int i = 0; i < src.rows; ++i)
	{
		for (int j = 0; j < src.cols; ++j)
		{
			hist.at<float>(0, src.at <uchar>(i, j))++;
		}
	}
	cv::Mat histImage = cv::Mat::zeros(540, 1020, CV_8UC1);
	const int bins = 255;
	double maxValue;
	cv::Point2i maxLoc;
	cv::minMaxLoc(hist, 0, &maxValue, 0, &maxLoc);
	int scale = 4; 
	int histHeight = 540;
 
	for (int i = 0; i < bins; i++)
	{
		float binValue = (hist.at<float>(i));
		int height = cvRound(binValue * histHeight / maxValue);
		cv::rectangle(histImage, cv::Point(i * scale, histHeight),
			cv::Point((i + 1) * scale - 1, histHeight - height), cv::Scalar(255), -1);
 
	}
	return histImage;
}

測試效果

圖1 原圖

圖2 灰度圖

圖3 直方圖

如果函數有什麼可以改進完善的地方,非常歡迎大傢指出,一同進步何樂而不為呢~ 

以上就是C++ OpenCV繪制簡易直方圖DrawHistImg的詳細內容,更多關於C++ OpenCV繪制直方圖的資料請關註WalkonNet其它相關文章!

推薦閱讀: