灰度圖像直方圖有256個項目,也叫箱子(bin)。如果把直方圖所有的箱子進行累加,得到的結果就是像素的總數。若將直方圖歸一化,即所有的箱子累加和等於1,這時箱子的數值表示對應的像素數量佔總數的百分比。
代碼如下:
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat image=imread("/Users/zhangxiaoyu/Desktop/2.png",0);//flags=0代表讀取灰色圖像
if(image.empty())
{
cout<<"Error!cannot be read...../n";
return -1;
}
int nimages=1;//圖片數量爲1
int channels[1]={0};//通道數量
Mat outputHist;//輸出直方圖
int dims=1;//一維
int histSize[1]={256};//存放每個維度直方圖尺寸的數組
float hranges[2]={0,255};//每一維數值的取值範圍
const float *ranges[1]={hranges};//值範圍的指針
//計算直方圖
calcHist(&image, nimages, channels, Mat(), outputHist, dims, histSize, ranges);
//循環遍歷
for(int i=0;i<256;i++)
std::cout<<"bin/value:"<<i<<"="<<outputHist.at<float>(i)<<std::endl;
//畫出直方圖
int scale = 1;
//直方圖的圖片
Mat histimage(histSize[0] * scale, histSize[0], CV_8U, cv::Scalar(255));
//找到最大值和最小值
double maxValue = 0;
double minValue = 0;
minMaxLoc(outputHist, &minValue, &maxValue, 0, 0);
//測試
std::cout << minValue << std::endl;
std::cout << maxValue << std::endl;
//縱座標縮放比例
double rate = (histSize[0] / maxValue)*0.9;
for (int i = 0; i < histSize[0]; i++)
{
//得到每個i和箱子的值
float value = outputHist.at<float>(i);
//畫直線
line(histimage, Point(i*scale, histSize[0]), Point(i*scale, histSize[0] - value*rate), Scalar(0));
}
namedWindow("hist");
imshow("histimage", histimage);
//waitKey(0);
Mat thresholded;//輸出分割後的圖像
threshold(image, thresholded, 166, 255, THRESH_BINARY);
namedWindow("threshold_image");
imshow("threshold_image", thresholded);
waitKey(0);
}
原始圖片如下所示:
圖像的灰度直方圖爲:
由上圖可以看出,灰度直方圖的兩個“山峯”之間有“低谷”,可根據低谷的灰度直將圖像分割,如下圖所示:
基本可以看出,原始圖像被分割爲兩部分,背景與前景。