写在前面:入门OpenCV的时候,找了很多资料,发现各种教材深浅不一,对于新手来说总是难以上手。最近看了《OpenCV2 计算机视觉编程手册》,发现该书难度适中,很适合自己。现在将自己学习该书的过程整理如下,便于以后回过头来复习。
灰度直方图是OpenCV中一种简单实用的工具,这一篇我们来学习怎样显示一幅图像的灰度直方图。
灰度直方图是灰度级的函数,它表示图像中具有某种灰度级的像素的个数,反映了图像中某种灰度出现的频率。如果将图像总像素亮度(灰度级别)看成是一个随机变量,则其分布情况就反映了图像的统计特性,这可用probability density function(PDF)来刻画和描述,表现为灰度直方图。【百度百科】
class Histogram1D{
private:
int histSize[1];//项的数量
float hranges[2]; //像素的最小及最大值
const float*ranges[1];
int channels[1]; //仅用到一个通道
public:
Histogram1D(){
//准备1D直方图的参数
histSize[0] = 256;
hranges[0] = 0.0;
hranges[1] = 255.0;
ranges[0] = hranges;
channels[0] = 0; //默认情况,我们考察0号通道
}
//方法:计算1D直方图
MatND getHistogram(const Mat &image){
MatND hist;
//计算直方图
calcHist(&image,
1, //计算单张图像的直方图
channels, //通道数量
Mat(), //不使用图像作为掩码
hist, //返回的直方图
1, //这是1D的直方图
histSize, //项的数量
ranges //像素值的范围
);
return hist;
}
//方法:直方图可视化
Mat getHistogramImage(const Mat &image){
//首先计算直方图
MatND hist = getHistogram(image);
//获取最大值和最小值
double maxVal = 0;
double minVal = 0;
minMaxLoc(hist, &minVal, &maxVal, 0, 0);
//显示直方图的图像
Mat histImg(histSize[0], histSize[0], CV_8U, Scalar(255));
//设置最高点为nbins的90%
int hpt = static_cast(0.9*histSize[0]);
//每个条目都绘制一条垂直线
for (int h = 0; h < histSize[0]; h++){
float binVal = hist.at(h);
int intensity = static_cast(binVal*hpt / maxVal);
//两点之间绘制一条线
line(histImg, Point(h, histSize[0]), Point(h, histSize[0] - intensity), Scalar::all(0));
}
return histImg;
}
};
这个类中定义了一维直方图中参数、计算直方图的方法及将直方图可视化的方法。
//------------------------------------【程序功能】-----------------------------------------------
// 描述:显示灰度图的一维直方图
//-----------------------------------------------------------------------------------------------
//----------------------------------【头文件包含部分】-------------------------------------------
// 描述:包含程序所依赖的文件
//-----------------------------------------------------------------------------------------------
#include
#include "highgui.h"
#include
//-----------------------------------【命名空间声明】--------------------------------------------
// 描述:包含程序所使用的命名空间
//-----------------------------------------------------------------------------------------------
using namespace cv;
using namespace std;
// 定义直方图的类
class Histogram1D{
private:
int histSize[1];//项的数量
float hranges[2];
const float*ranges[1];
int channels[1];
public:
Histogram1D(){
histSize[0] = 256;
hranges[0] = 0.0;
hranges[1] = 255.0;
ranges[0] = hranges;
channels[0] = 0;
}
MatND getHistogram(const Mat &image){
MatND hist;
calcHist(&image,
1,
channels,
Mat(),
hist,
1,
histSize,
ranges
);
return hist;
}
Mat getHistogramImage(const Mat &image){
MatND hist = getHistogram(image);
double maxVal = 0;
double minVal = 0;
minMaxLoc(hist, &minVal, &maxVal, 0, 0);
Mat histImg(histSize[0], histSize[0], CV_8U, Scalar(255));
int hpt = static_cast(0.9*histSize[0]);
for (int h = 0; h < histSize[0]; h++){
float binVal = hist.at(h);
int intensity = static_cast(binVal*hpt / maxVal);
line(histImg, Point(h, histSize[0]), Point(h, histSize[0] - intensity), Scalar::all(0));
}
return histImg;
}
}
//-------------------------------------【main()函数】-----------------------------------------------
//描述:控制台应用程序的入口
//--------------------------------------------------------------------------------------------------
int main(){
Mat image = imread("sky-lancer.jpg", 0); //默认读入灰度图
namedWindow("sky-lancer1");
imshow("sky-lancer1", image);
waitKey(5000);
Histogram1D h;
namedWindow("Histogram");
imshow("Histogram", h.getHistogramImage(image));
waitKey(5000);
}
原图
读入的灰度图
显示的灰度直方图
要获得彩色图像的其他通道的直方图,可以从所定义的类入手,修改其通道数,也可以使用Split(Mat &src,Mat &dst)函数,先将彩色图像分为3个通道,再分别调用getHistogramImage方法。
代码如下:
int main(){
vector mv;
Mat image0 = imread("sky-lancer.jpg", 1);
split(image0,mv);
namedWindow("通道0");
imshow("通道1", mv.at(0));
waitKey(5000);
Histogram1D h;
namedWindow("Histogram1");
imshow("Histogram1", h.getHistogramImage(mv.at(0)));
waitKey(5000);
}