接着上面的章节,我们在 Histogram1D 类中加入一个新方法,即直方图均衡化的方法,现在贴出完整的代码,Histogram1D 类 头文件如下:
#ifndef HISTOGRAM1D_H
#define HISTOGRAM1D_H
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
class Histogram1D
{
public:
Histogram1D();
MatND getHistogram(const Mat &source);
Mat getHistogramImage(const Mat &source);
Mat stretch(const Mat &source, int minValue);
Mat applyLookUp(const Mat &source, const Mat &lookup);
Mat equalize(const Mat &source);//直方图均衡化
private:
int histSize[1]; //直方图项数
int channels[1]; //通道数量
float histMinMax[2]; //像素最小值最大值
const float* ranges[1]; //像素值范围
};
#endif // HISTOGRAM1D_H
Histogram1D 类 源文件如下:
#include "histogram1d.h"
Histogram1D::Histogram1D()
{
//1D参数初始化
histSize[0] = 256;
histMinMax[0] = 0.0;
histMinMax[1] = 255.0;
ranges[0] = histMinMax;
channels[0] = 0;
}
MatND Histogram1D::getHistogram(const Mat &source)
{
MatND Hist;
calcHist(&source, 1, channels, Mat(), Hist, 1, histSize, ranges);
return Hist;
}
Mat Histogram1D::getHistogramImage(const Mat &source)
{
MatND hist = getHistogram(source);//计算直方图
double maxVal = 0;
double minVal = 0;
minMaxLoc(hist, &minVal, &maxVal);//获取最大值和最小值
Mat histImg(histSize[0], histSize[0], CV_8U, Scalar(255));//用于显示直方图图像
int topPoint = static_cast<int>(0.9*histSize[0]);
for ( int i = 0; i < histSize[0]; i ++ )
{
float binVal = hist.at<float>(i);
int intensity = static_cast<int>(binVal*topPoint/maxVal);
line(histImg, Point(i, histSize[0]), Point(i, histSize[0]-intensity),
Scalar::all(0));
}
return histImg;
}
Mat Histogram1D::stretch(const Mat &source, int minValue = 0)
{
MatND hist = getHistogram(source);//计算直方图
int imin = 0;//寻找直方图左端,即最小值
for ( ; imin < histSize[0]; imin ++ )
{
if ( hist.at<float>(imin) > minValue )
break;
}
int imax = histSize[0] - 1;//寻找直方图右端,即最大值
for ( ; imax >= 0; imax -- )
{
if ( hist.at<float>(imax) > minValue )
break;
}
int dim(256);//创建查找表
Mat lookup( 1, &dim, CV_8U );//填充查找表
for ( int i = 0; i < 256; i ++ )
{
if ( i < imin ) lookup.at<uchar>(i) = 0;
else if ( i > imax ) lookup.at<float>(i) = 255;
else lookup.at<uchar>(i) = static_cast<uchar>(255.0*(i-imin)/(imax-imin) + 0.5);
}
Mat result;
result = applyLookUp( source, lookup );
return result;
}
Mat Histogram1D::applyLookUp(const Mat &source, const Mat &lookup)
{
Mat result;
LUT( source, lookup, result);
return result;
}
Mat Histogram1D::equalize(const Mat &source)//直方图均衡化
{
Mat result;
equalizeHist(source, result);
return result;
}
main.cpp 源文件如下:
#include <QCoreApplication>
#include "histogram1d.h"
using namespace cv;
using namespace std;
int main()
{
Mat src = imread("lena.jpg",0);
Mat stretch;
Histogram1D Hg;
stretch = Hg.stretch(src, 50);
Mat srcHg = Hg.getHistogramImage(src);
Mat strHHg = Hg.getHistogramImage(stretch);
Mat equal = Hg.equalize(src);
Mat equHg = Hg.getHistogramImage(equal);
namedWindow("src", 0);
imshow("src", src);
namedWindow("srcHg", 0);
imshow("srcHg", srcHg);
namedWindow("stretch", 0);
imshow("stretch", stretch);
namedWindow("strHHg", 0);
imshow("strHHg", strHHg);
namedWindow("equal", 0);
imshow("equal", equal);
namedWindow("equHg", 0);
imshow("equHg", equHg);
waitKey(0);
return 0;
}
直方图均衡化是图像处理领域中利用图像直方图对对比度进行调整的方法。这种方法通常用来增加许多图像的局部对比度,尤其是当图像的有用数据的对比度相当接近的时候。通过这种方法,亮度可以更好地在直方图上分布。这样就可以用于增强局部的对比度而不影响整体的对比度,直方图均衡化通过有效地扩展常用的亮度来实现这种功能。这个方法确实可以简单有效提升图像质量。
以下是原图像、原图像直方图、直方图拉伸后图像、直方图拉伸后直方图、直方图均衡化后图像、直方图均衡化后直方图的对比: