转自:https://www.cnblogs.com/wangguchangqing/p/7098213.html
直方图规定化
从上面可以看出,直方图的均衡化自动的确定了变换函数,可以很方便的得到变换后的图像,但是在有些应用中这种自动的增强并不是最好的方法。有时候,需要图像具有某一特定的直方图形状(也就是灰度分布),而不是均匀分布的直方图,这时候可以使用直方图规定化。
直方图规定化,也叫做直方图匹配,用于将图像变换为某一特定的灰度分布,也就是其目的的灰度直方图是已知的。这其实和均衡化很类似,均衡化后的灰度直方图也是已知的,是一个均匀分布的直方图;而规定化后的直方图可以随意的指定,也就是在执行规定化操作时,首先要知道变换后的灰度直方图,这样才能确定变换函数。规定化操作能够有目的的增强某个灰度区间,相比于,均衡化操作,规定化多了一个输入,但是其变换后的结果也更灵活。
在理解了上述的均衡化过程后,直方图的规定化也较为简单。可以利用均衡化后的直方图作为一个中间过程,然后求取规定化的变换函数。具体步骤如下:
- 将原始图像的灰度直方图进行均衡化,得到一个变换函数s=T(r)s=T(r),其中s是均衡化后的像素,r是原始像素
- 对规定的直方图进行均衡化,得到一个变换函数v=G(z)v=G(z),其中v是均衡化后的像素,z是规定化的像素
- 上面都是对同一图像的均衡化,其结果应该是相等的,s=v,且z=G−1(v)=G−1(T(r))s=v,且z=G−1(v)=G−1(T(r))
通过,均衡化作为中间结果,将得到原始像素rr和zz规定化后像素之间的映射关系。
详解规定化过程
对图像进行直方图规定化操作,原始图像的直方图和以及规定化后的直方图是已知的。假设Pr(r)Pr(r)表示原始图像的灰度概率密度,Pz(z)Pz(z)表示规定化图像的灰度概率密度(r和z分别是原始图像的灰度级,规定化后图像的灰度级)。
- 对原始图像进行均衡化操作,则有sk=T(rk)=L⋅∑i=0i=kPr(rk)sk=T(rk)=L⋅∑i=0i=kPr(rk)
- 对规定化的直方图进行均衡化操作,则vk=G(zm)=L⋅∑j=0j=mPz(zm)vk=G(zm)=L⋅∑j=0j=mPz(zm)
- 由于是对同一图像的均衡化操作,所以有sk=vmsk=vm。
- 规定化操作的目的就是找到原始图像的像素sksk到规定化后图像像素的zkzk之间的一个映射。有了上一步的等式后,可以得到sk=G(zk)sk=G(zk),因此要想找到sksk想对应的zkzk只需要在zz进行迭代,找到使式子G(zm)−skG(zm)−sk的绝对值最小即可。
- 上述描述只是理论的推导过程,在实际的计算过程中,不需要做两次的均衡化操作,具体的推导过程如下:
sk=vkL⋅∑i=0i=kPr(rk)=L⋅∑j=0j=mPz(zm)∑i=0i=kPr(rk)=∑j=0j=mPz(zm)sk=vkL⋅∑i=0i=kPr(rk)=L⋅∑j=0j=mPz(zm)∑i=0i=kPr(rk)=∑j=0j=mPz(zm)
上面公式表示,假如sksk 规定化后的对应灰度是zmzm的话,需要满足的条件是sksk的累积概率和zmzm的累积概率是最接近的。
下面是一个具体计算的例子:
首先得到原直方图的各个灰度级的累积概率VsVs以及规定化后直方图的各个灰度级的累积概率VzVz,那么确定sksk到zmzm之间映射关系的条件就是:
∣Vs−Vz∣∣Vs−Vz∣
的值最小。
以k=2k=2为例,其原始直方图的累积概率是:0.65,在规定化后的直方图的累积概率中和0.65最接近(相等)的是灰度值为5的累积概率密度,则可以得到原始图像中的灰度级2,在规定化后的图像中的灰度级是5。
直方图规定化的实现
直方图规定化的实现可以分为一下三步:
- 计算原图像的累积直方图
- 计算规定直方图的累积直方图
- 计算两累积直方图的差值的绝对值
- 根据累积直方图差值建立灰度级的映射
具体代码实现如下:
void hist_specify(const Mat &src, const Mat &dst,Mat &result)
{
Histogram1D hist1D;
MatND src_hist = hist1D.getHistogram(src);
MatND dst_hist = hist1D.getHistogram(dst);
float src_cdf[256] = { 0 };
float dst_cdf[256] = { 0 };
// 源图像和目标图像的大小不一样,要将得到的直方图进行归一化处理
src_hist /= (src.rows * src.cols);
dst_hist /= (dst.rows * dst.cols);
// 计算原始直方图和规定直方图的累积概率
for (int i = 0; i < 256; i++)
{
if (i == 0)
{
src_cdf[i] = src_hist.at<float>(i);
dst_cdf[i] = dst_hist.at<float>(i);
}
else
{
src_cdf[i] = src_cdf[i - 1] + src_hist.at<float>(i);
dst_cdf[i] = dst_cdf[i - 1] + dst_hist.at<float>(i);
}
}
// 累积概率的差值
float diff_cdf[256][256];
for (int i = 0; i < 256; i++)
for (int j = 0; j < 256; j++)
diff_cdf[i][j] = fabs(src_cdf[i] - dst_cdf[j]);
// 构建灰度级映射表
Mat lut(1, 256, CV_8U);
for (int i = 0; i < 256; i++)
{
// 查找源灰度级为i的映射灰度
// 和i的累积概率差值最小的规定化灰度
float min = diff_cdf[i][0];
int index = 0;
for (int j = 1; j < 256; j++)
{
if (min > diff_cdf[i][j])
{
min = diff_cdf[i][j];
index = j;
}
}
lut.at<uchar>(i) = static_cast<uchar>(index);
}
// 应用查找表,做直方图规定化
LUT(src, lut, result);
}