您的位置:首页 > 运维架构

我的OpenCV学习笔记(13):计算直方图,利用查找表拉伸直方图,直方图均衡

2012-05-03 20:53 555 查看
一些头文件:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

using namespace std;
using namespace cv;


 

首先建立一个类:

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;

}


 

在OpenCV中,使用calcHist计算直方图

Mat getHistogram(const Mat &image)
{
Mat hist;
//计算直方图函数
//参数为:源图像(序列)地址,输入图像的个数,通道数,掩码,输出结果,直方图维数,每一维的大小,每一维的取值范围
calcHist(&image,1,channels,Mat(),hist,1,histSize,ranges);

return hist;
}


但是,返回的结果并不是我们希望的“直方图”,hist只是记录了每个bin下的像素个数。我们需要自己利用line函数画图:

Mat getHistogramImage(const Mat &image)
{
//首先计算直方图
Mat hist = getHistogram(image);

//获取最大值和最小值
double maxVal = 0;
double minVal = 0;
//minMaxLoc用来获得最大值和最小值,后面两个参数为最小值和最大值的位置,0代表不需要获取
minMaxLoc(hist,&minVal,&maxVal,0,0);
//展示直方图的画板:底色为白色
Mat histImg(histSize[0],histSize[0],CV_8U,Scalar(255));

//将最高点设为bin总数的90%
int hpt = static_cast<int>(0.9*histSize[0]);
//为每一个bin画一条线
for(int h = 0; h < histSize[0];h++)
{
float binVal = hist.at<float>(h);
int intensity = static_cast<int>(binVal*hpt/maxVal);
//int intensity = static_cast<int>(binVal);
line(histImg,Point(h,histSize[0]),Point(h,histSize[0]-intensity),Scalar::all(0));

}
return histImg;
}


函数中对亮度进行了“压缩”,主要目的是让直方图能够更好的显示在画板上。

查找表,就是一个一对一或者多对一函数,指定了一个亮度经过查找表以后变成另外一个像素。在OpenCV中,使用LUT函数来实现

Mat applyLookUp(const Mat& image,const Mat& lookup)
{
Mat result;
LUT(image,lookup,result);
return result;
}


 

而变化的具体内容,依赖于你自己定义的查找表,比如,如果你想让查找表的结果为当前图像的翻转,可以在main函数中定义查找表为:

//用查找表翻转图像灰度
int dim(256);
Mat lut(1,&dim,CV_8U);

for(int i = 0; i < 256; i++)
{
lut.at<uchar>(i) = 255-i;
}
imshow("灰度翻转后的图像",h.applyLookUp(image,lut));


当你想让图像经过查找表以后直方图拉伸,变得效果好一点,可以这样:

将个数低于指定数目(默认为0)的bin舍去,剩下的最小值变为0,最大值变为255,中间的部分线性拉伸:

Mat strech(const Mat &image,int minValue = 0)
{
//首先计算直方图
Mat hist = getHistogram(image);
//左边入口
int imin = 0;
for(;imin< histSize[0];imin++)
{
cout<<hist.at<float>(imin)<<endl;
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<uchar>(i) = 255;
}
else
{
lookup.at<uchar>(i) = static_cast<uchar>(255.0*(i-imin)/(imax-imin)+0.5);
}
}
Mat result;
result = applyLookUp(image,lookup);
return result;

}

当然,这样的效果还不是最好的,最好的均衡应该使得直方图非常平缓,每个bin中的数目差不多,在OpenCV中,使用equalizeHist函数可以实现直方图均衡功能:

Mat equalize(const Mat &image)
{
Mat result;
equalizeHist(image,result);
return result;
}


有了上面定义的类,我们main函数就变得简单多了:

#include "histogram.h"

int main()
{
//以灰度方式读取图像
Mat image = imread("D:/picture/images/group.jpg",0);
imshow("源灰度图像",image);
if (!image.data)
return -1;
Histogram1D h;
imshow("直方图",h.getHistogramImage(image));

//用查找表翻转图像灰度
int dim(256);
Mat lut(1,&dim,CV_8U);

for(int i = 0; i < 256; i++)
{
lut.at<uchar>(i) = 255-i;
}
imshow("灰度翻转后的图像",h.applyLookUp(image,lut));

//用查找表拉伸图像灰度值
//忽略那些个数少于100个像素的bin
Mat strech = h.strech(image,100);
imshow("拉伸后的图像",strech);
imshow("拉伸后的直方图",h.getHistogramImage(strech));

//图像均衡
Mat afterEqualize = h.equalize(image);
imshow("均衡后的解果",afterEqualize);
imshow("均衡后的直方图",h.getHistogramImage(afterEqualize));
waitKey(0);
return 0;
}


由于画的图比较多,这里就不贴结果了。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  image float class