计算图像的直方图
- 图像是由像素组成的,在一个单通道的灰度图像中,每个像素的值介于0~255之间。直方图是一个简单的表,给出了一副图像或一组图像中拥有给定数值的像素数量。灰度图像 的直方图有256个条目(容器)。0号容器给出值为0的像素个数,1号容器给出值为1的像素个数,以此类推。
定义一个专门的类处理单通道的灰度图像。
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号通道
}
计算一个灰度直方图的方法,返回对象是一个拥有256个条目的一维数组。
//计算1D直方图
MatND getHistogram(const Mat &image){
MatND hist;
calcHist(&image,
1,//计算单张图像的直方图
channels,//通道数量
Mat (),//不适用图像作为掩码
hist,//返回的直方图
1,//1D的直方图
histSize,//项的数量
ranges//像素值的范围
);
return hist;
}
将直方图以柱状图的形式显示。
//计算1D直方图并返回一副图像
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 <int>(0.9*histSize[0]);
//每个条目都绘制一条直线
for(int h = 0; h<histSize[0]; h++)
{
float binVal = hist.at<float>(h);
int intensity = static_cast<int>(binVal*hpt/maxVal);
//两点之间绘制一条直线
line(histImg, Point(h,histSize [0]),
Point(h,histSize [0]-intensity),
Scalar::all(0));
}
return histImg;
}
结果图像峰值处的值可做为二值化的阈值。
使用查找表修改图像外观
- 查找表是一个简单的一对一(多对一)函数,定义了如何将像素值转换为新的值,本质上是一个一维数组,对于常规灰度图像而言有256个项目,表的第i项表示相应的灰度的新值。
创建一个查找表反转像素的强度。
//创建图像的反向查找表
int dim(256);
Mat lut(1, //1D
&dim, //256项
CV_8U);//uchar
for(int i = 0; i<256; i++){
lut.at<char>(i) = 255-i;
}
对图像应用查找表以生成新图像。
Mat applyLookUp(const Mat& image, const Mat& lookup){
Mat result;
//应用查找表
LUT(image, lookup, result);
return result;
}
通过拉伸直方图能得到扩展后的对比度,旨在检测直方图中非零项的最低(imin)和最高(imax)强度值,强度值可以被重新映射,这样imin值是重新定位在强度0,imax是分配值255。
Mat stretch (const Mat&image, int minValue=0){
//计算直方图
MatND hist = getHistogram(image);
//寻找直方图的左端
int imin = 0;
for(;imin<histSize[0]; imin++){
std::cout<<hist.at<float>(imin)<<std::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++){
//确保数值位于imin与imax之间
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;
}