文章首发于我的个人博客
1、直方图
灰度范围为[0,L-1]的灰度图像的直方图是离散函数 h ( r k ) = n k h(r_k)=n_k h(rk)=nk。在实践中,通常用乘积MN表示的图像像素总数除它的每个分量来归一化直方图,M和N是图像的行和列的维数。因此,归一化后的直方图为 p ( r k ) = n k / M N p(r_k)=n_k/MN p(rk)=nk/MN。简单地说, p ( r k ) p(r_k) p(rk)是灰度级 r k r_k rk的在图像中出现概率的一个估计。归一化后的直方图所有分量之和应该为1。
直方图是大量空域处理技术的基础,直方图处理可以有效地用于图像增强。除了能提供有关图像的统计特征外,其所包含的信息还能用于其他很多的图像处理技术,如图像分割、图像压缩等。
- 暗图像的直方图
- 亮图像的直方图
- 低对比度图像的直方图
- code
void drawHistogram(cv::Mat image){
const cv::Mat originImageCopy = image.clone();
std::vector<int> countPixel(256, 0);
//直方图灰度分布概率
std::vector<float> pixelProb;
std::vector<int> pixel(256);
for(int i = 0; i < 256; i++){
pixel[i] = i;
}
for(int i = 0; i < originImageCopy.rows; i++){
for(int j = 0; j < originImageCopy.cols; j++){
countPixel[originImageCopy.at<uchar>(i, j)]++;
}
}
float sum_pixel = originImageCopy.rows * originImageCopy.cols;
for(auto iter = countPixel.begin(); iter != countPixel.end(); iter++){
pixelProb.push_back(*iter /sum_pixel);
}
}
2、直方图均衡
直方图均衡化是将一个已知灰度分布的图像使用某种非线性变换函数进行计算,使得运算结果编程一幅具有均匀灰度分布的新图像。
用于直方图均衡化的函数s = T®必须满足两个条件:
- T®是一个单调递增的单值函数
- 0 < = T ( r ) < = 1 0<=T(r)<=1 0<=T(r)<=1
在离散情况下:
p
r
(
r
k
)
=
n
k
M
N
,
k
=
1
,
2
,
3
,
.
.
.
,
L
−
1
p_r(r_k)=\frac{n_k}{MN},k=1,2,3,...,L-1
pr(rk)=MNnk,k=1,2,3,...,L−1
s k = T ( r k ) = ∑ j = 0 k p r ( r j ) = ∑ k j = 0 n k M N s_k=T(r_k)=\sum_{j=0}^{k}p_r(r_j)\\ =\sum_{k}^{j=0}\frac{n_k}{MN} sk=T(rk)=j=0∑kpr(rj)=k∑j=0MNnk
以上,k表示某个灰度级,L是整个灰度级的数目。通常的8位图像下,L为256.以上的方程就是通常说的直方图均衡化或线性化。
从该方程可以看出,均衡化后的图像比原图像所跨越的灰度级范围更宽。另外直方图处理是完全资助的,即该过程所需的参数完全来自图像本身,不需要任何额外的参数,是一种有力的自适应增强工具。
- 经过直方图均衡化后的图像
- code
cv::Mat equalizeHistogram(cv::Mat originImage){
float sumPixel = originImage.rows * originImage.cols;
int size = 256;
auto tempImage = originImage.clone();
//统计像素值出现的次数
std::vector<int> countPixel(256, 0);
//直方图灰度分布概率
std::vector<float> pixelProb;
//直方图均衡变换后得到的值
std::vector<int> transformValue;
//直方图均衡结果
std::vector<int> equalizeResult(256, 0);
//统计灰度值出现次数
for(int i = 0; i < originImage.rows; i++){
uchar* data = originImage.ptr<uchar>(i);
for(int j = 0; j < originImage.cols; j++){
countPixel[data[j]]++;
}
}
//计算灰度值概率
for(auto iter = countPixel.begin(); iter != countPixel.end(); iter++){
pixelProb.push_back(*iter / sumPixel);
}
//计算直方图均衡结果
for(int i = 0; i < pixelProb.size(); i++){
int s = 0;
for(int j = 0; j <= i; j++){
s += round(255 * pixelProb[j]);
}
if(s > 255)
s = 255;
transformValue.push_back(s);
}
//进行直方图均衡变换
for(int i = 0; i < tempImage.rows; i++){
for(int j = 0; j < tempImage.cols; j++){
tempImage.at<uchar>(i, j) = transformValue[tempImage.at<uchar>(i, j)];
}
}
}