数字图像处理算法.docx
《数字图像处理算法.docx》由会员分享,可在线阅读,更多相关《数字图像处理算法.docx(40页珍藏版)》请在冰豆网上搜索。
数字图像处理算法
窗体顶端
摘要:
关于空间域图像处理算法框架,直方图处理,空间域滤波器算法框架的编程心得,使用GDI+(C++)
一,图像文件的读取
初学数字图像处理时,图像文件的读取往往是一件麻烦的事情,我们要面对各种各样的图像文件格式,如果仅用C++的fstream库那就必须了解各种图像编码格式,这对于初学图像处理是不太现实的,需要一个能帮助轻松读取各类图像文件的库。
在Win32平台上GDI+(C++)是不错的选择,不光使用上相对于Win32GDI要容易得多,而且也容易移植到.Net平台上的GDI+。
Gdiplus:
:
Bitmap类为我们提供了读取各类图像文件的接口,Bitmap:
:
LockBits方法产生的BitmapData类也为我们提供了高速访问图像文件流的途径。
这样我们就可以将精力集中于图像处理算法的实现,而不用关心各种图像编码。
具体使用方式请参考MSDN中GDI+文档中关于Bitmap类和BitmapData类的说明。
另外GDI+仅在WindowsXP/2003上获得直接支持,对于Windows2000必须安装相关DLL,或者安装有Office2003,VisualStudio2003.Net等软件。
二,空间域图像处理算法框架
(1)在空间域图像处理中,对于一个图像我们往往需要对其逐个像素的进行处理,对每个像素的处理使用相同的算法(或者是图像中的某个矩形部分)。
即,对于图像f(x,y),其中0≤x≤M,0≤y≤N,图像为M*N大小,使用算法algo,则f(x,y)=algo(f(x,y))。
事先实现一个算法框架,然后再以函数指针或函数对象(functor,即实现operator()的对象)传入算法,可以减轻编程的工作量。
如下代码便是一例:
#ifndefPROCESSALGO_H
#definePROCESSALGO_H
#include
#include
namespacensimgtk
{
template:
PixelFormatpixelFormat,classProcessor>
boolProcessPixelsOneByOne(Gdiplus:
:
Bitmap*constp_bitmap,Processorprocessor,unsignedintx,unsignedinty,
unsignedintwidth,unsignedintheight)
{
if(p_bitmap==NULL)
{
returnfalse;
}
if((width+x>p_bitmap->GetWidth())||(height+y>p_bitmap->GetHeight()))
{
returnfalse;
}
Gdiplus:
:
BitmapDatabitmapData;
Gdiplus:
:
Rectrect(x,y,width,height);
if(p_bitmap->LockBits(&rect,Gdiplus:
:
ImageLockModeWrite,pixelFormat,&bitmapData)!
=Gdiplus:
:
Ok)
{
returnfalse;
}
pixelType*pixels=(pixelType*)bitmapData.Scan0;
for(unsignedintrow=0;row {
for(unsignedintcol=0;col {
processor(&pixels[col+row*bitmapData.Stride/sizeof(pixelType)]);
}
}
if(p_bitmap->UnlockBits(&bitmapData)!
=Gdiplus:
:
Ok)
{
returnfalse;
}
returntrue;
}
}
#endif
ProcessPixelsOneByOne函数可以对图像中从(x,y)位置起始,width*height大小的区域进行处理。
模板参数pixelType用于指定像素大小,例如在Win32平台上传入unsignedchar即为8位,用于8阶灰度图。
模板参数Processor为图像处理算法实现,可以定义类实现voidoperator(pixelType*)函数,或者传入同样接口的函数指针。
如下便是一些算法示例(说明见具体注释):
#ifndefSPATIALDOMAIN_H
#defineSPATIALDOMAIN_H
#include
#include
namespacensimgtk
{
//8阶灰度图的灰度反转算法
classNegativeGray8
{
public:
voidoperator()(unsignedchar*constp_value)
{
*p_value^=0xff;
}
};
//8阶灰度图的Gamma校正算法
classGammaCorrectGray8
{
private:
unsignedchard_s[256];
public:
GammaCorrectGray8:
:
GammaCorrectGray8(doublec,doublegamma);
voidoperator()(unsignedchar*constp_value)
{
*p_value=d_s[*p_value];
}
};
//8阶灰度图的饱和度拉伸算法
classContrastStretchingGray8
{
private:
unsignedchard_s[256];
public:
ContrastStretchingGray8:
:
ContrastStretchingGray8(doublea1,doubleb1,unsignedintx1,
doublea2,doubleb2,unsignedintx2,doublea3,doubleb3);
voidoperator()(unsignedchar*constp_value)
{
*p_value=d_s[*p_value];
}
};
//8阶灰度图的位平面分割,构造函数指定位平面号
classBitPlaneSliceGray8
{
private:
unsignedchard_s[256];
public:
BitPlaneSliceGray8(unsignedcharbitPlaneNum);
voidoperator()(unsignedchar*constp_value)
{
*p_value=d_s[*p_value];
}
};
}
#endif
//上述类中各构造函数的实现代码,应该分在另一个文件中,此处为说明方便,一并列出
#include"SpatialDomain/spatialDomain.h"
namespacensimgtk
{
GammaCorrectGray8:
:
GammaCorrectGray8(doublec,doublegamma)
{
doubletemp;
for(unsignedinti=0;i<256;++i)
{
temp=ceil(c*255.0*pow(double(i)/255.0,gamma));
d_s[i]=unsignedchar(temp);
}
}
ContrastStretchingGray8:
:
ContrastStretchingGray8(doublea1,doubleb1,unsignedintx1,
doublea2,doubleb2,unsignedintx2,doublea3,doubleb3)
{
if(x1>255||x2>255||x1>x1)
{
for(unsignedinti=0;i<256;++i)
d_s[i]=i;
}
else
{
doubletmp;
for(unsignedinti=0;i {
tmp=ceil(a1*double(i)+b1);
d_s[i]=(unsignedchar)tmp;
}
for(unsignedinti=x1;i {
tmp=ceil(a2*double(i)+b2);
d_s[i]=(unsignedchar)tmp;
}
for(unsignedinti=x2;i<256;++i)
{
tmp=ceil(a3*double(i)+b3);
d_s[i]=(unsignedchar)tmp;
}
}
}
BitPlaneSliceGray8:
:
BitPlaneSliceGray8(unsignedcharbitPlaneNum)
{
unsignedcharbitMaskArray[8]=
{
0x01,0x02,0x04,0x08,
0x10,0x20,0x40,0x80
};
for(unsignedinti=0;i<256;++i)
{
unsignedchartmp=i;
tmp&=bitMaskArray[bitPlaneNum];
tmp=(tmp>>bitPlaneNum)*255;
d_s[i]=tmp;
}
}
}
(2)直方图在GDI+1.0中没有获得支持,我们必须自行实现。
直方图相关的处理在数字图像处理中占有重要地位,可以通过它获取图像灰度级的统计信息,且可以通过直方图进行一些重要的图像增强技术,如直方图均衡化,直方图规定化,基本全局门限等。
下面是获取8阶图像直方图的算法实现:
namespacensimgtk
{
boolGetHistogramNormalizeGray8(Gdiplus:
:
Bitmap*constp_bitmap,float*histogramArray)
{
if(p_bitmap==NULL||histogramArray==NULL)
{
returnfalse;
}
Gdiplus:
:
BitmapDatabitmapData;
Gdiplus:
:
Rectrect(0,0,p_bitmap->GetWidth(),p_bitmap->GetHeight());
if(p_bitmap->LockBits(&rect,Gdiplus:
:
ImageLockModeRead,PixelFormat8bppIndexed,&bitmapData)!
=Gdiplus:
:
Ok)
{
returnfalse;
}
unsignedchar*pixels=(unsignedchar*)bitmapData.Scan0;
unsignedinthistogram[256];
for(inti=0;i<256;++i)
{
histogram[i]=0;
}
for(unsignedintrow=0;rowGetWidth();++row)
{
for(unsignedintcol=0;colGetHeight();++col)
{
++histogram[pixels[col+row*bitmapData.Stride]];
}
}
constunsignedinttotalPixels=p_bitmap->GetWidth()*p_bitmap->GetHeight();
for(inti=0;i<256;++i)
{
histogramArray[i]=float(histogram[i])/float(totalPixels);
}
if(p_bitmap->UnlockBits(&bitmapData)!
=Gdiplus:
:
Ok)
{
returnfalse;
}
returntrue;
}
}
在获取直方图后(即上面算法的第二个参数),再将其作为参数传入下面的对象的构造函数,然后以该对象为仿函数传入ProcessPixelsOneByOne即可实现8阶图像直方图均衡化:
#ifndefSPATIALDOMAIN_H
#defineSPATIALDOMAIN_H
#include
#include
namespacensimgtk
{
//8阶灰度图的直方图均衡化
classHistogramEqualizationGray8
{
private:
unsignedchard_s[256];
public:
HistogramEqualizationGray8(constfloat*consthistogramArray);
voidoperator()(unsignedchar*constp_value)
{
*p_value=d_s[*p_value];
}
};
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include"SpatialDomain/spatialDomain.h"
namespacensimgtk
{
HistogramEqualizationGray8:
:
HistogramEqualizationGray8(constfloat*consthistogramArray)
{
if(histogramArray!
=NULL)
{
floatsum=0.0;
for(inti=0;i<256;++i)