局部直方图处理的用途
如果我们要谈论局部直方图处理,那么不得不提起与之相对应的全局直方图处理,之前写过一篇文章关于全局直方图处理的,对全局直方图不熟悉的话可以先去看一下,这样再看局部直方图处理会更好。记录一Opencv 和 C++实现全局直方图均衡化(原理到实践)
当我想让一幅图想的动态范围提高,提升图像的对比度我们可以采取全局直方图均衡化来处理图像,通常来说也会获得不错的结果。如下图所示
全局直方图均衡化处理前全局直方图均衡化处理后
这里可以看出在一般情况下全局直方图均衡处理的确可以提升图像的动态范围和对比度,但是在某一些情况下则不同,请看下面这个例子,原图是一副小行星的图片,图像中心亮度很高,但四周绝大部分区域亮度很低,这时如果仍然使用全局直方图均衡化处理图像,获得的结果往往不尽人意。
原图处理后
可以看出由于图像的动态范围被强行提升后整幅图像出现了严重失真,噪点被放大,图像细节丢失。此时使用局部的直方图处理结果会好很多。如下图所示。
原图处理后
可以看出使用局部直方图处理后的图像还原了一部分原图中看不到的暗部细节,但是图像仍然有割裂感(在明暗交界处),一部分原因是调参的问题,选取的模板尺寸和方差系数以及均值系数有关(这幅图大概调了一下,没有细调)。
以上关于全局直方图均衡化的处理和局部直方图处理的两个实验说明的各自所适用的领域。接下来进入正题,讨论局部直方图处理。
局部直方图处理
处理的基本思想是利用大小不同的模板在图像中滑动比较整幅图像的均值和方差与局部模板(块)的均值和方差进行比较,如果符合要求就将模板中心选择为合适的候选点,将候选点的亮度乘一个常数E。但是为什么是均值和方差呢?一副图像的亮度均值反应图像的平均亮度,方差则反应图像的整体对比度,方差越大,对比度也就越强。
数学部分
上述部分介绍了了利用局部直方图信息处理图像的一种方法,接下我们看一下相关的数学公式,关于如何计算图像的方差和均值。
图像均值公式 公式一
图像方差公式 公式二
公式中的L-1中L是图像的灰阶等级数或者是亮度等级数如果是8位的图像L是256,ri是亮度等级p(ri)是当前亮度等级占全图的比例,或者是ri出现的概率。其中p(ri)可以从图像的直方图中获取到。
通过以上两个公式我们就可以获取到全局图像和局部模板的均值和方差,接下来就是如何确定候选点的问题了。
公式三
其中msxy是模板均值,mg是全局均值,sigma_sxy是局部方差,sigma_G是全局方差,计算方式由公式一二给出。k0,k1,k2是我们在处理图像过程中可调的参数,k0<1,k1<k2<0,k1是为了防止对均匀部分(方差为0)的图像部分进行增强。
代码实现
#include<opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std ;
Mat src,gray,dst;
void global_equalization(Mat &img);
void Local_equalization(Mat &img, int size = 95, float k0 = 0.99, float k1 = 0.001, float k2 = 0.7, float E = 6);
int main(int argc, char *argv[])
{
src =imread("/home/qinzihang/opencv/samples/data/stone.jpg");
//resize(src, src, Size(200,200));
cvtColor(src, gray,COLOR_BGR2GRAY);
cvtColor(src, src,COLOR_BGR2GRAY);
imshow("GG",src);
Mat test = gray;
global_equalization(src);
Local_equalization(gray);
waitKey(0);
}
void global_equalization(Mat &img)
{
float gray_l[256] = {0};
float HI[256] = {0};//图像亮度密度1/N*h(I)
float CDF[256] = {0};//累积分布函数
int rows=img.rows;
int cols=img.cols;
Mat draw_mat = Mat::zeros(600,600,CV_8U);
float m = 0;
float variance = 0;
cout << rows << endl;//x
for(int i=0; i<rows; i++)
{
for(int j=0; j<cols; j++)
{
uchar t;
if(img.channels()==1)
{
t=img.at<uchar>(i,j);
gray_l[t]++;//获得图像亮度信息
}
}
}
for(int i = 0; i <256; i++)
{
line(draw_mat,Point(i+150,600-1),Point(i+150, 600-gray_l[i]),254);
imshow("draw", draw_mat);
HI[i] = (gray_l[i]/(img.cols*img.rows*1.0f));//获得密度概率
//cout << HI[i] << endl;
m += HI[i]*i;
}
for(int i = 0; i < 256; i++)
{
variance += (i - m) *(i - m)*HI[i];
}
for(int i = 0; i < 255; i++)
{
if(i == 0)
{
CDF[0] = HI[ 0];
}
else
{
CDF[i] = (CDF[i-1] +HI[i]);//C(I) = C(I - 1 ) +h(I)
//cout << CDF[i] << endl;
}
}
for(int i=0; i<rows; i++)
{
for(int j=0; j<cols; j++)
{
uchar t;
if(img.channels()==1)
{
t=img.at<uchar>(i,j);
img.at<uchar>(i,j) = 255*CDF[t];//完成图像重映射至0-255
}
} draw_mat = Mat::zeros(600,600,CV_8U);
}
imshow("yes",img);
}
void Local_equalization(Mat &img, int size , float k0 , float k1 , float k2, float E)
{
int gray_l[256] = {0};
float HI[256] = {0};//图像亮度密度1/N*h(I)
float CDF[256] = {0};//累积分布函数
int rows=img.rows;
int cols=img.cols;
Mat draw_mat = Mat::zeros(600,600,CV_8U);
float global_m = 0;
float global_variance = 0;
int border_x = size/2;
int border_y = size/2;
cout << rows << endl;//x
for(int i=0; i<rows; i++)
{
for(int j=0; j<cols; j++)
{
uchar t;
if(img.channels()==1)
{
t=img.at<uchar>(i,j);
gray_l[t]++;//获得图像亮度信息
}
}
}
for(int i = 0; i <256; i++)
{
HI[i] = (gray_l[i]/(img.cols*img.rows*1.0f));//获得密度概率
global_m += HI[i]*i;
}
cout << "global_m = " << global_m << endl;
for(int i = 0; i < 256; i++)
{
global_variance += (i - global_m) *(i - global_m)*HI[i];
}
cout << "global_variance = " << global_variance << endl;
for(int i=0; i<rows - border_x; i++)
{
for(int j=0; j<cols - border_y; j++)
{
Point center_pix = Point(j+ border_x, i + border_y);
int local_gray_l[256] = {0};
float local_m = 0;
float local_variance = 0;
float local_HI[256] = {0};
for(int M=0; M<size; M++)
{
for(int N=0; N<size; N++)
{
uchar t;
t=img.at<uchar>(i + M, j + N);
local_gray_l[t]++;
}
}
for(int k = 0; k <256; k++)
{
local_HI[k] = (local_gray_l[k]/(size*size*1.0f));//获得密度概率
local_m += local_HI[k]*k;
}
// cout << "local_m = " << local_m << endl;
for(int k = 0; k < 256; k++)
{
local_variance += (k - local_m) *(k - local_m)*local_HI[k];
}
// cout << "local_variance = " << local_variance << endl;
if( local_m < global_m*k0 && (k1 * global_variance < local_variance && local_variance < k2 * global_variance))
{
if(E * img.at<uchar>(center_pix) < 255)
{
img.at<uchar>(center_pix) = E * img.at<uchar>(center_pix);
//cout << "new_pix = " << E * img.at<uchar>(center_pix) << endl;
}
else
{
img.at<uchar>(center_pix) = 255;
}
}
}
}
imshow("loacl",img);
}
这部分代码实现和之前的全局直方图均衡类似,也很简单,如果有看不懂的可以留言或者去看一下以下两篇。
记录一Opencv 和 C++实现全局直方图均衡化(原理到实践)
以上便是本文的所有内容,如有错误疏漏欢迎大家指出.