概述
数字图像处理实践[3]---夜间图像增强
EmilMatthew (EmilMatthew@126.com)
[ 类别 ]算法创新、算法对比
[推荐指数]★★★★
[ 摘要 ]本文提出了两种针对夜间灰度图像的增强算法:一种基于极暗区域连通集的分割算法,结合非线性动态调整及直方图均衡化方法对夜间图像进行增强,该算法的主要特点是对场景中的主要景物有较为突出的表现,轮廓清晰。
另一种算法是针对夜间图像直方图分布的特点,采用将图像的绿色通道转成灰度图像的方法,该算法的主要特点是对于场景的细节表现生动,视觉效果好。
[ 关键词 ] 夜间视图、图像增强、非线性调整、连通集、广度优先搜索、绿色通道
Digit Image Process Practice[3] ------Night Image Enhancement
[Classify] Algorithm Innovation , Algorithm Comparison
[ Level ] ★★★★
[Abstract] This article introduces two methods to enhance the night pictures. One method is based on the deeply dark area connected set partition algorithm , and both with the nonlinear adjusting method and equalized method. This algorithm has its special points such as enhancing the important part of the picture and has a clearly outline. Another method is based on the night picture’s grey histogram’s special property , changes its green channel to grey picture. This algorithm has its special points such as showing out the details vividly and has a good vision effect.
[Key Words] Night Vision , Image Enhancement , Nonlinear Dynamic Adjust ,Connected Set , Breadth First Search, Green Channel
[0引言]
夜间图像的主要特点是微光,暗色区域占据了画面的主要部分,相应的灰度直方图也集中分布于坐标系的左侧。因此,夜间图像的主要增强工作在于将较暗处的细节表达清楚,但又不能过亮,丢失过度的细节信息。[1]提出了将对比度增强方法与直方图均衡算法级联的方法,虽然该方法本身会带来一定的噪声,但是该文的一个比较有益的启发在于将多种效果进行组合,以获得较好的处理效果。[2]提出了一种针对BBHE(双直方均衡)算法改进的算法,该算法主要特点在于克服简并保持图像亮度进行增强。本文主要从图像的处理不同需求出发,考虑了两种不同的增强方案:方案一,基于极暗区域连通集的分割算法的处理目标更接进于让机器去“看”, 主要的特点是在于对于主要景物表现得十分清晰;而方案二,将绿色通道转成灰度图像,主要是针对灰度都集中分布在小于64的夜间灰度图像,处理结果更适合让人眼去看,主要特点在于体现画面的细节。
[1符号假设]
p: 最暗灰度像素的个数占总像素个数的百分比
[2基于极暗区域连通集的分割算法]
2.1想法的来源
该算法的想法是基于夜间图像的有较大的连通区域是暗区得出的,所谓暗区,是指某幅图像中最暗灰度像素的个数占总像素个数的一定百分比内(不妨设为p )的所有像素。下面是三幅测试图像及其灰度柱状图(注:由于个别像素所占比例过大,因此此处的灰度柱状图采取了“限高”处理):
图1:测试图像1及其灰度柱状图
图2:测试图像2及其灰度柱状图
图3:测试图像3及其灰度柱状图
所以,即便都是在视觉上的暗图像,在灰度的分布上还是有所不同的,图1中灰度<5像素几乎可以忽略,而图2、图3灰度<5的像素则占到了全部像素的相当一部分比例。所以,划分最暗区域的原则不应以灰度的某个上限为限定,而应以某图中最暗灰度像素占所有像素的百分比p为依据。下面是三幅图像当p=0.15时提取的极暗区域情况:
图4:测试图像1(p=0.15)
图5:测试图像2(p=0.15)
图6:测试图像3(p=0.15)
通过对三幅测试图像极暗区域的提取,可以看出,极暗区域的连通特性在夜间图像是显然成立的。
2.1算法的核心部分
之所以要提出连通区域,主要是考虑,如果仅仅以p值作为极暗区域的划分,会将一些较暗,但是夹杂在较亮区域的像素作与连通的极暗区域相同的粗略处理,难以体现细节。
算法的整体框架如下:
1. 采用广度优先搜索,根据p值,找出极暗连通区域。
2. 对于非极暗连通区域的像素,作均值化处理。
有两点要说明一下:
1. 定义极暗连通区域,是以其像素值的个数点总像素的个数的百分比q来
确定的,这里设q=0.02 .
2. 之所以不再对极暗连通区域作均值化处理,主要是这样考虑的:因为即
使对极暗连通区域作均值化处理,像素的范围同样被限定在一个视觉上几乎无法辨认的极暗区域,意义不大。
算法的实现部分参附录[0]。
算法的实验结果:
图7:测试图像1的算法效果对比图
图8:测试图像2的算法效果对比图
图9:测试图像3的算法效果对比图
从实验结果的对比中,可以看出:直方图均值化方法使得画面稍亮,而文献[1]的方法除了会带来噪声外,亦在细节处使得画面有些模糊感,本文提出的“极暗连通区域分割+非极暗连通区域均值化”(简称DPEQU)方法,具有对比明显,重点突出的优点。
2.2算法的改进
经过对比后,发现仅使用DPEQU方法仍有一些不足之处,如:一些位于极暗区域附近的像素,很容易在视觉上被极暗区域“吞噬”,从而丢失相应的信息。所以,考虑采用非线性动态范围调整方法先对画出进行调整,再用DPEQU,于是得到了 “非线性动态范围调整+极暗连通区域分割+非极暗连通区域均值化” 增强方法(简称DADPEQU)。
此处的非线性动态范围调整的公式为:
g(i,j)=c·log(1+f(i,j)) (i=1,2,…,m j=1,2,…,n)
其中,c值的计算方式如下:
令图像的灰度变化范围为s,则c=s/lg(1+s)
非线性动态范围调整的算法实现请参附录[1]。
由于非线性动态范围调整对稍亮些的图像,如测试图像1,就会呈现调整过度的状况,因此,对这类图像(判定这类图像的条件为灰度像素级别<20的像素个数占不到全画面像素的15%),不做动态调整,而仅使用DPEQU。
实验结果:
图10:测试图像2经DADPEQU算法增强后的效果
图11:测试图像3经DADPEQU算法增强后的效果
从实验结果来看,较DPEQU算法的改进之处,在于画面的细节得到突出的体现,不失为一种针对夜间图像增强的有效方法。当然,这个方法的缺点也是存在的,那就是局部的亮区容易被调整的过亮,从面掩盖暗区的一些细节,因此,如何在增亮和突出细节上找到一个较好的“平衡点”,仍是一个值得思考和探索的问题。
[3绿色通道转成灰度图像的方法]
下面介绍的增强方法,可以说是有些讨巧的,虽然表面上看上去很简单,但是针对夜间图像大部分灰度像素值<64(即绿色通道表现力最强,而红、蓝两通道没有表现的区域中)的特性[5],所以将原图先进行灰度到绿色通道的转换,然后以绿色通道中的绿度像素级别直接以同级别的灰度像素进行输出,下面是三幅图像三个通道所对应的画面信息的展现:
图12:测试图像1三个通道信息
图13:测试图像2三个通道信息
图14:测试图像3三个通道信息
所以,完全有理由在处理夜间图像时将红、蓝两通道的信息舍去,仅保留绿色通道的信息。
该算法的实现请参附录[2]
实验结果:
图15:测试图像1经绿色通道转成灰度算法增强后的效果
图16:测试图像2经绿色通道转成灰度算法增强后的效果
图17:测试图像2经绿色通道转成灰度算法增强后的效果
从数学上看,该算法实际上是对于灰度像素<64的像素都做了乘以255/64的操作,对于灰度像素>64的像素点则简单处理成255。虽然是一个简单的线性变换,但是从结果上来看,在画面的真实感和细节表达上,该算法处理出的画面显然要胜过本文中所展示的其它增强效果,非常适合当用户的要求为人眼观察时使用。当然,本算法亦存在着一定的缺陷,那便是增强后的画面仍是偏暗的,如果使用相应的增强效果,如均衡化、非线性动态范围调整,又会回到将细节处的信息“吞噬”掉的老路上。所以,找到适合针对绿色通道转成的灰度图像进行增亮的算法,仍是一个值得探索和努力的方向。
[参考文献与网站]
[0] 朱虹等著,数字图像处理基础,科学出版社,2005.
[1] 张 宇、王希勤、彭应宁,一种用于夜间图像增强的算法,清华大学学报(自然科学版),1999 年第39 卷第9 期 ,79~ 80.
[2] 沈嘉励、张 宇、王秀坛,一种夜视图象处理的新算法,中国图象图形学报,2000 年6 月,第5 卷(A 版) 第6 期.
[3] 马志峰、史彩成,自适应图像对比度模糊增强算法,激光与红外Vol. 36 , No. 3,2006年3月
[4] 王国权、仲伟波,灰度图像增强算法的改进与实现研究,计算机应用研究,2004年第12期,p175-176.
[5] EmilMatthew, 玩玩数字图像处理[2]---图像增强,http://blog.csdn.net/EmilMatthew/archive/2006/09/27/1290589.aspx
程序完成日:06/10/02
文章完成日:06/10/09
附录[0]
极暗连通区域分割算法(极暗连通区域分割+非极暗连通区域均值化)
void BMParse::nightPhotoPationMethod
(HDC inHdc,int offsetX,int offsetY,float portionOfDark)
{
//0.Inner value declaration
int darkAreaPixelCount;
int darkAreaUpLimit; //根据p值计算出的某幅图像灰度门限值
unsigned long totalPixelNum;
unsigned long darkAreaNum;
unsigned long tmpDarkAreaNum;
unsigned long parsedNum;
unsigned long totalDarkAreaNum;
unsigned long tmpULVal;
int histVal[256];
float histPercent[256];
int darkAreaPixelIndex[256];
int darkAreaSetNum;
int usefulDarkSetID[300]; //有效的连通集的标号
int usefulSetNum;
ePoint tmpPoint,tmpPoint2;
PSingleRearSeqQueue searchQueue;
//valuable for equalize op
int arrHists[256];
float pArr[256];
long totalHistVal;
unsigned long outputPixel;
int tmpTableVal;
int i,j,k;
//1.Use Pation Method to indentify the very dark area
//1.0 determine the dark area up limit
searchQueue=createNullSingleRearSeqQueue();
darkAreaPixelCount=0;
darkAreaNum=0;
totalPixelNum=mBMFileInfo.bmHeight*mBMFileInfo.bmWidth;
for(i=0;i<256;i++)
{
histVal[i]=0;
histPercent[i]=0;
}
for(i=0;i<mBMFileInfo.bmHeight;i++)
for(j=0;j<mBMFileInfo.bmWidth;j++)
{
histVal[bmpBWMatrix[i][j]]++;
bmpBWBackMatrix[i][j]=0;
}
for(i=0;i<256;i++)
histPercent[i]=(float)histVal[i]/(float)totalPixelNum;
i=0;
while(darkAreaPixelCount<6&&i<256)
{
if(histPercent[i]>0)
{
darkAreaPixelIndex[darkAreaPixelCount]=i;
darkAreaPixelCount++;
darkAreaNum+=histVal[i];
}
i++;
}
//check if darkAreaPixel>=totalPixelNum*portionOfDark
if(darkAreaNum<totalPixelNum*portionOfDark)
{
while(darkAreaNum<totalPixelNum*portionOfDark)
{
if(histPercent[i]>0)
{
darkAreaPixelIndex[darkAreaPixelCount]=i;
darkAreaNum+=histVal[i];
darkAreaPixelCount++;
}
i++;
}
}
//exception consult
if(i==256)
{
return;
}
//1.1 find dark area set
darkAreaUpLimit=i-1;
darkAreaSetNum=0;
usefulSetNum=0;
parsedNum=0;
totalDarkAreaNum=0;
for(i=0;i<mBMFileInfo.bmHeight;i++)
for(j=0;j<mBMFileInfo.bmWidth;j++)
{
if(bmpBWBackMatrix[i][j]==0)
{
if(bmpBWMatrix[i][j]>darkAreaUpLimit)
{
parsedNum++;
bmpBWBackMatrix[i][j]=-1;// marked ,not in dark area
}
else
{
//a.init part of the breadth first search
darkAreaSetNum++;
tmpDarkAreaNum=0;
tmpPoint.x=j;
tmpPoint.y=i;
enQueue(searchQueue,tmpPoint);
//b.core part of search
while(!isEmpty(searchQueue))
{
tmpPoint=getHeadData(searchQueue);
parsedNum++;
//save to count values bmpBWBackMatrix[tmpPoint.y][tmpPoint.x]=darkAreaSetNum;
tmpDarkAreaNum++;
//left -> bmpBWMatrix[tmpPoint.y][tmpPoint.x-1]
if(tmpPoint.x>0)
{ if(bmpBWBackMatrix[tmpPoint.y][tmpPoint.x-1]==0&&
bmpBWBackMatrix[tmpPoint.y][tmpPoint.x-1]!=-3&&
bmpBWMatrix[tmpPoint.y][tmpPoint.x-1]<=darkAreaUpLimit)
{
tmpPoint2.x=tmpPoint.x-1;
tmpPoint2.y=tmpPoint.y; bmpBWBackMatrix[tmpPoint.y][tmpPoint.x-1]=-3; enQueue(searchQueue,tmpPoint2); }
}
//up -> bmpBWMatrix[tmpPoint.y-1][tmpPoint.x]
if(tmpPoint.y>0)
{
if(bmpBWBackMatrix[tmpPoint.y-1][tmpPoint.x]==0&&
bmpBWBackMatrix[tmpPoint.y-1][tmpPoint.x]!=-3&&
bmpBWMatrix[tmpPoint.y-1][tmpPoint.x]<=darkAreaUpLimit)
{
tmpPoint2.x=tmpPoint.x; tmpPoint2.y=tmpPoint.y-1; bmpBWBackMatrix[tmpPoint.y-1][tmpPoint.x]=-3;
enQueue(searchQueue,tmpPoint2); }
}
//right -> bmpBWMatrix[tmpPoint.y][tmpPoint.x+1]
if(tmpPoint.x<mBMFileInfo.bmWidth-1)
{
if(bmpBWBackMatrix[tmpPoint.y][tmpPoint.x+1]==0&&
bmpBWBackMatrix[tmpPoint.y][tmpPoint.x+1]!=-3&&
bmpBWMatrix[tmpPoint.y][tmpPoint.x+1]<=darkAreaUpLimit)
{ tmpPoint2.x=tmpPoint.x+1;
tmpPoint2.y=tmpPoint.y;
bmpBWBackMatrix[tmpPoint.y][tmpPoint.x+1]=-3;
enQueue(searchQueue,tmpPoint2);
}
}
//down -> bmpBWMatrix[tmpPoint.y+1][tmpPoint.x]
if(tmpPoint.y<mBMFileInfo.bmHeight-1)
{ if(bmpBWBackMatrix[tmpPoint.y+1][tmpPoint.x]==0&&
bmpBWBackMatrix[tmpPoint.y+1][tmpPoint.x]!=-3&&
bmpBWMatrix[tmpPoint.y+1][tmpPoint.x]<=darkAreaUpLimit)
{
tmpPoint2.x=tmpPoint.x;
tmpPoint2.y=tmpPoint.y+1; bmpBWBackMatrix[tmpPoint.y+1][tmpPoint.x]=-3; enQueue(searchQueue,tmpPoint2); }
}
deQueue(searchQueue);
}
if(tmpDarkAreaNum>0.02*totalPixelNum)
{ usefulDarkSetID[usefulSetNum]=darkAreaSetNum;
usefulSetNum++;
totalDarkAreaNum+=tmpDarkAreaNum;
}
}
}
}
for(i=0;i<mBMFileInfo.bmHeight;i++)
for(j=0;j<mBMFileInfo.bmWidth;j++)
{
if(bmpBWBackMatrix[i][j]>0)
{
for(k=0;k<usefulSetNum;k++)
{
if(bmpBWBackMatrix[i][j]==usefulDarkSetID[k])
break;
}
if(k==usefulSetNum)
bmpBWBackMatrix[i][j]=-2;
else
bmpBWBackMatrix[i][j]=0;
}
}
for(i=0;i<mBMFileInfo.bmHeight;i++)
for(j=0;j<mBMFileInfo.bmWidth;j++)
if(bmpBWBackMatrix[i][j]!=0&&bmpBWBackMatrix[i][j]!=-1&&
bmpBWBackMatrix[i][j]!=-2)
{
return;
}
//2.Use equalize method to process the picture
//2.1 cal each grey value's fequence
for(i=0;i<256;i++)
arrHists[i]=0;
for(j=0;j<mBMFileInfo.bmHeight;j++)
for(i=0;i<mBMFileInfo.bmWidth;i++)
{ if(bmpBWBackMatrix[j][i]==-1||bmpBWBackMatrix[j][i]==-2)
arrHists[bmpBWMatrix[j][i]]++;
}
//2.cal total hist value
totalHistVal=0;
for(i=0;i<256;i++)
totalHistVal+=arrHists[i];
pArr[0]=0;
pArr[1]=(float)(arrHists[0]+arrHists[1])/(float)(2*totalHistVal);
for(i=2;i<256;i++)
pArr[i]=pArr[i-1]+(float)arrHists[i]/(float)totalHistVal;
//3.show out adjusted picture:
for(i=0;i<mBMFileInfo.bmHeight;i++)
for(j=0;j<mBMFileInfo.bmWidth;j++)
{ if(bmpBWBackMatrix[i][j]==-1||bmpBWBackMatrix[i][j]==-2)
{
tmpTableVal=255*pArr[bmpBWMatrix[i][j]];
}
else
tmpTableVal=bmpBWMatrix[i][j];
//make to windows color format
outputPixel=((unsigned long)paletteArr[tmpTableVal].b)*65536+
((unsigned long)paletteArr[tmpTableVal].g)*256+
(unsigned long)paletteArr[tmpTableVal].r;
//output pixel SetPixel(inHdc,j+offsetX,i+offsetY,outputPixel);
bmpBWBackMatrix[i][j]=tmpTableVal;
}
}
关于程序的几点说明:
1) bmpBWBackMatrix是程序中的一个重要的结构,其值的具体意义如下:
搜索过程中:
-3:在搜索过程中被新吸收的可接纳点,0:未搜索,>0 :属于已搜索区域。
搜索结束时:
-2:表示像素点属于极暗区域,但是所在区域不为连通集。
-1:表示像素点属于非极暗区域。
0 :表示像素点属于极暗连通区域。
2) 搜索连通集的过程采用队列实现了广度优先搜索。
附录[1]
非线性动态范围调整的算法实现
void BMParse::nolinearDynamicAdjust2()
{
//0. Valuables declaration:
float plusConstant;
float plusConstantChanged;
int maxGreyValue,minGreyValue,spanGreyValue;
int avgGreyVal;
int tmpTableVal;
unsigned long sumGreyVal;
unsigned long outputPixel;
unsigned long totalPixelNum;
unsigned long darkAreaNum;
int i,j;
darkAreaNum=0;
totalPixelNum=mBMFileInfo.bmHeight*mBMFileInfo.bmWidth;
for(i=0;i<mBMFileInfo.bmHeight;i++)
for(j=0;j<mBMFileInfo.bmWidth;j++)
{
if(bmpBWMatrix[i][j]<20)
darkAreaNum++;
}
if(darkAreaNum<0.15*totalPixelNum)
return;
//1.Core Process
//1.0Common Process
// find max and min greyvalue
maxGreyValue=-1;
minGreyValue=266;
for(i=0;i<mBMFileInfo.bmHeight;i++)
for(j=0;j<mBMFileInfo.bmWidth;j++)
{
if(bmpBWMatrix[i][j]>maxGreyValue)
{ maxGreyValue=bmpBWMatrix[i][j];
}
if(bmpBWMatrix[i][j]<minGreyValue)
{
minGreyValue=bmpBWMatrix[i][j];
}
}
//2.0.cal plus constant value
spanGreyValue=maxGreyValue-minGreyValue;
plusConstant=spanGreyValue/log10(1+spanGreyValue);
for(i=0;i<mBMFileInfo.bmHeight;i++)
for(j=0;j<mBMFileInfo.bmWidth;j++)
{
//cal adjusted grey table value index
tmpTableVal=(int)(plusConstant*log10(1+bmpBWMatrix[i][j]));
//copy to back bw matrix , for next step of processing use
bmpBWMatrix[i][j]=tmpTableVal;
}
}
附录[2]
原图->绿色通道->同级别的灰度像素
void BMParse::changeGreenChannelToGrey
(HDC inHdc,int offsetX,int offsetY)
{
//0.Inner Value declaration
unsigned long outputPixel;
int tmpTableVal;
int i,j;
//1.Core part of false color change
for(i=0;i<mBMFileInfo.bmHeight;i++)
for(j=0;j<mBMFileInfo.bmWidth;j++)
{
//green channel
if(bmpBWMatrix[i][j]<64) tmpTableVal=255/64*bmpBWMatrix[i][j];
else if(bmpBWMatrix[i][j]<192)
tmpTableVal=255;
else tmpTableVal=-255/63*(bmpBWMatrix[i][j]-192)+255;
//make to windows color format
outputPixel=((unsigned long)paletteArr[tmpTableVal].b)*65536+
((unsigned long)paletteArr[tmpTableVal].g)*256+
(unsigned long)paletteArr[tmpTableVal].r;
//1.2show out
SetPixel(inHdc,j+offsetX,i+offsetY,outputPixel);
bmpBWBackMatrix[i][j]=tmpTableVal;
}
}
[源码下载、源程序下载]
源程序内容列表:
Code1:直方图均衡化
Code2:文献[1]中的方法实现
Code3:非线性动态范围调整_极暗连通区域分割_非极暗连通区域均值化(DADPEQU)
Code4:绿色通道转成灰度图像
http://emilmatthew.51.net/EmilPapers/0631ImageProcess3/code1.rar
http://emilmatthew.51.net/EmilPapers/0631ImageProcess3/code2.rar
http://emilmatthew.51.net/EmilPapers/0631ImageProcess3/code3.rar
http://emilmatthew.51.net/EmilPapers/0631ImageProcess3/code4.rar
若直接点击无法下载(或浏览),请将下载(或浏览)的超链接粘接至浏览器地( 推荐MYIE或GREENBORWSER)址栏后按回车.若不出意外,此时应能下载.
若下载中出现了问题,请参考:
http://blog.csdn.net/emilmatthew/archive/2006/04/08/655612.aspx
[参考文献下载]
[1] 张 宇、王希勤、彭应宁,一种用于夜间图像增强的算法,清华大学学报(自然科学版),1999 年第39 卷第9 期 ,79~ 80.
[2] 沈嘉励、张 宇、王秀坛,一种夜视图象处理的新算法,中国图象图形学报,2000 年6 月,第5 卷(A 版) 第6 期.
声明:参考文献的著作权为原作者所有,参考文献的电子版来源为CNKI,在此表示感谢。
最后
以上就是隐形苗条为你收集整理的数字图像处理实践[3]---夜间图像增强的全部内容,希望文章能够帮你解决数字图像处理实践[3]---夜间图像增强所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复