0014-OpenCV環境下計算並繪製灰度直方圖的原始碼!
阿新 • • 發佈:2018-11-16
影象的直方圖是影象進行運算時的一個重要的資料特徵,許多演算法都需要用到影象的直方圖資料,OpenCV提供了函式calcHist用來計算影象的直方圖資料。這個函式的引數較多,下面介紹這個函式。
calcHist的原型如下:
void 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:源影象陣列,陣列內的圖片應該有相同的深度和大小,影象深度只能是CV_8U或CV_32F,通道數可以不同,注意這個引數是指標。
nimages:要計算影象的個數。
channel:計算哪些通道的直方圖。通道編號方法:第一張圖的通道編號為0至images[0].channels()-1,第二張圖的通道編號為images[0].channels()至images[0].channels() + images[1].channels()-1,以此類推,注意這個引數是指標。
mask:掩碼陣列。掩碼中的非0元素對應的影象元素將會被計算,0元素則被遮蔽不參與計算。掩碼陣列可以為空。
hist:直方圖計算結果儲存陣列。
dims
histSize:各個維度的大小。
ranges:儲存每個維度的統計範圍。
uniform:直方圖是否均勻化的標誌,意義暫時不清楚,等以後搞清楚了再來補充說明。
accumulate:記憶標誌。表示這個函式空間被再次呼叫前是否清零,如果不清零,則可以使得使用者儲存多張圖的直方圖資料,或者對之前的計算過的直方圖進行更新。
OpenCV下計算並繪製直方圖的程式碼如下:
影象處理開發資料、影象處理開發需求、影象處理接私活掙零花錢,可以搜尋公眾號"qxsf321",並關注!
原始碼中使用的影象下載連結:http://pan.baidu.com/s/1kUJMx1t 密碼:r3d3
//opencv版本:OpenCV3.0
//VS版本:VS2013
//Author:qxsf321.net
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
Mat img = imread("02.jpg");
if (img.empty())
{
cout << "Error: Could not load image" << endl;
return 0;
}
Mat srcImage;
cvtColor(img, srcImage, CV_BGR2GRAY);
imshow("【原圖的灰度圖】", srcImage);
//為計算直方圖配置變數
//首先是需要計算的通道編號,就是需要計算哪個通道的直方圖(BGR空間需要確定計算,計算方法見帖子中對相關引數的說明)
int channels = 0;
//然後是定義直方圖計算結果的儲存空間
Mat dstHist;
//接下來是直方圖的每一個維度的數目(這個數目用於將每一維度的數值分組)
int histSize[] = { 256 };
//最後是確定每個維度的取值範圍,就是每一維度的橫座標的取值範圍
//首先得定義一個數組用來儲存單個維度的的取值範圍
float midRanges[] = { 0, 256 };
//然後把這個陣列再放到一個二維陣列中
const float *ranges[] = { midRanges };
//準備工作做好後,就可以呼叫calcHis函式計算直方圖資料了
calcHist(&srcImage, 1, &channels, Mat(), dstHist, 1, histSize, ranges, true, false);
//calcHist函式呼叫結束後,dstHist變數中將儲存直方圖資料
//接下來繪製直方圖
//首先先建立一個黑底的影象,為了可以顯示彩色,所以該繪製圖像是一個8位的3通道影象
Mat drawImage = Mat::zeros(Size(256, 256), CV_8UC3);
//因為影象中的某個灰度值的總個數可能會超出所定義的影象的尺寸,所以要對個數進行歸一化處理
//先用 minMaxLoc函式來得到計算直方圖中的最大資料,這個函式的使用方法大家一看函式原型便知
double g_dHistMaxValue;
minMaxLoc(dstHist, 0, &g_dHistMaxValue, 0, 0);
//遍歷直方圖資料,對資料進行歸一化和繪圖處理
for (int i = 0; i < 256; i++)
{
int value = cvRound(dstHist.at<float>(i) * 256 * 0.9 / g_dHistMaxValue);
//line(drawImage, Point(i, drawImage.rows - 1), Point(i, drawImage.rows - 1 - value), Scalar(255, 0, 0));
line(drawImage, Point(i,0), Point(i, value), Scalar(255, 0, 0));
}
//對繪製出的影象作y方向上的翻轉處理,以符合我們的看圖習慣
// 輸出矩陣定義
Mat resultImage(drawImage.size(), drawImage.type());
// X與Y方向矩陣
Mat xMapImage(drawImage.size(), CV_32FC1);
Mat yMapImage(drawImage.size(), CV_32FC1);
int rows = drawImage.rows;
int cols = drawImage.cols;
for (int j = 0; j < rows; j++)
{
for (int i = 0; i < cols; i++)
{
// y方向上翻轉
xMapImage.at<float>(j, i) = i;
yMapImage.at<float>(j, i) = rows - j;
}
}
// 重對映操作
remap(drawImage, resultImage, xMapImage, yMapImage,
CV_INTER_LINEAR, cv::BORDER_CONSTANT,
cv::Scalar(0, 0, 0));
imshow("【未翻轉前的直方圖】", drawImage);
imshow("【翻轉後的直方圖】", resultImage);
waitKey(0);
return 0;
}
程式碼說明:
程式碼中用到了line函式來繪製直方圖,這裡給出它的原型,大家看下原型再結合原型自然就明白了怎麼用了。
void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color,int thickness = 1, int lineType = LINE_8, int shift = 0);
另外,大家要注意,在opencv中,座標原點在左上角,也就是說向下為y軸正方向,所以程式碼中為了大家的閱讀習慣還對影象進行了一次翻轉處理。翻轉部分程式碼的原理請大家參看博文https://blog.csdn.net/lehuoziyuan/article/details/84029770
程式碼執行結果截圖如下: