EDN首页   博客首页

最新日志

发表于:2008-5-25 23:48:21
标签:无标签

1

数字图像处理算法实现


                                 ------------编程心得(1)

2001414 朱伟 20014123

摘要: 关于空间域图像处理算法框架,直方图处理,空间域滤波器算法框架的编程心得,使用GDI+(C++)

一,图像文件的读取

    初学数字图像处理时,图像文件的读取往往是一件麻烦的事情,我们要面对各种各样的图像文件格式,如果仅用C++fstream库那就必须了解各种图像编码格式,这对于初学图像处理是不太现实的,需要一个能帮助轻松读取各类图像文件的库。在Win32平台上GDI+(C++)是不错的选择,不光使用上相对于Win32 GDI要容易得多,而且也容易移植到.Net平台上的GDI+

    Gdiplus::Bitmap类为我们提供了读取各类图像文件的接口,Bitmap::LockBits方法产生的BitmapData类也为我们提供了高速访问图像文件流的途径。这样我们就可以将精力集中于图像处理算法的实现,而不用关心各种图像编码。具体使用方式请参考MSDNGDI+文档中关于Bitmap类和BitmapData类的说明。另外GDI+仅在Windows XP/2003上获得直接支持,对于Windows 2000必须安装相关DLL,或者安装有Office 2003Visual Studio 2003 .Net等软件。

二,空间域图像处理算法框架

 (1) 在空间域图像处理中,对于一个图像我们往往需要对其逐个像素的进行处理,对每个像素的处理使用相同的算法(或者是图像中的某个矩形部分)。即,对于图像f(x,y),其中0xM,0yN,图像为M*N大小,使用算法algo,则f(x,y) = algo(f(x,y))。事先实现一个算法框架,然后再以函数指针或函数对象(functor,即实现operator()的对象)传入算法,可以减轻编程的工作量。

    如下代码便是一例:

#ifndef PROCESSALGO_H

#define PROCESSALGO_H

 

#include <windows.h>

#include <Gdiplus.h>

 

 

namespace nsimgtk

{

         template <typename pixelType, Gdiplus::PixelFormat pixelFormat, class Processor>

    bool ProcessPixelsOneByOne(Gdiplus::Bitmap* const p_bitmap, Processor processor, unsigned int x, unsigned int y,

                                                           unsigned int width, unsigned int height)

    {

                   if (p_bitmap == NULL)

                   {

                            return false;

                   }

 

                   if ((width + x > p_bitmap->GetWidth()) || (height + y >p_bitmap->GetHeight()))

                   {

                            return false;

                   }

 

        Gdiplus::BitmapData bitmapData;

                   Gdiplus::Rect rect(x, y, width,height);

       

        if (p_bitmap->LockBits(&rect, Gdiplus::ImageLockModeWrite, pixelFormat, &bitmapData) != Gdiplus::Ok)

            {

                            return false;

                   }

 

                   pixelType *pixels = (pixelType*)bitmapData.Scan0;

                  

 

        for (unsigned int row=0; row<height; ++row)

                   {

                            for (unsigned int col=0; col<width; ++col)

                            {

                                     processor(&pixels[col+row*bitmapData.Stride/sizeof(pixelType)]);     

                            }

                   }

 

                   if (p_bitmap->UnlockBits(&bitmapData) != Gdiplus::Ok)

                   {

                            return false;

                   }

       

                   return true;

         }

}

 

#endif

ProcessPixelsOneByOne函数可以对图像中从(x,y)位置起始,width*height大小的区域进行处理。模板参数pixelType用于指定像素大小,例如在Win32平台上传入unsigned char即为8位,用于8阶灰度图。模板参数Processor为图像处理算法实现,可以定义类实现void operator(pixelType *)函数,或者传入同样接口的函数指针。

    如下便是一些算法示例(说明见具体注释):

#ifndef SPATIALDOMAIN_H

#define SPATIALDOMAIN_H

#include <cmath>

#include <string>

 

namespace nsimgtk

{

    // 8阶灰度图的灰度反转算法 

         class NegativeGray8

         {

         public:

                   void operator()(unsigned char *const p_value)

                   {

                            *p_value ^= 0xff;

                   }

         };

   

    // 8阶灰度图的Gamma校正算法

         class GammaCorrectGray8

         {

         private:

                   unsigned char d_s[256];

         public:

                   GammaCorrectGray8::GammaCorrectGray8(double c, double gamma);

 

                   void operator()(unsigned char*const p_value)

                   {

                            *p_value = d_s[*p_value];

                   }

         };

 

    // 8阶灰度图的饱和度拉伸算法

         class ContrastStretchingGray8

         {

         private:

                   unsigned char d_s[256];

         public:

                   ContrastStretchingGray8::ContrastStretchingGray8(double a1, double b1, unsigned int x1,

                            double a2, double b2, unsigned int x2, double a3, double b3);

 

                   void operator()(unsigned char*const p_value)

                   {

                            *p_value = d_s[*p_value];

                   }

         };

   

    // 8阶灰度图的位平面分割,构造函数指定位平面号

         class BitPlaneSliceGray8

         {

         private:      

                   unsigned char d_s[256];

         public:

                   BitPlaneSliceGray8(unsigned char bitPlaneNum);

 

                   void operator()(unsigned char* const p_value)

                   {

                            *p_value = d_s[*p_value];

                   }

         };

}

 

#endif

 

// 上述类中各构造函数的实现代码,应该分在另一个文件中,此处为说明方便,一并列出

#include "SpatialDomain/spatialDomain.h"

 

namespace nsimgtk

{

         GammaCorrectGray8::GammaCorrectGray8(double c, double gamma)

         {

                   double temp;

                   for (unsigned int i=0; i<256; ++i)

                   {

                            temp = ceil(c * 255.0 * pow(double(i)/255.0, gamma));

                            d_s[i] = unsigned char(temp);

                   }

         }

 

         ContrastStretchingGray8::ContrastStretchingGray8(double a1, double b1, unsigned int x1,

                            double a2, double b2, unsigned int x2, double a3, double b3)

         {

                   if (x1 > 255 || x2 > 255 || x1 > x1)

                   {

                            for (unsigned int i=0; i<256; ++i)

                                     d_s[i] = i;

                   }

                   else

                   {

                            double tmp;

                            for (unsigned int i=0; i<x1; ++i)

                            {

                                     tmp = ceil(a1*double(i)+b1);

                                     d_s[i] = (unsigned char)tmp;

                            }

 

                            for (unsigned int i=x1; i<x2; ++i)

                            {

                                     tmp = ceil(a2*double(i)+b2);

                                     d_s[i] = (unsigned char)tmp;

                            }

 

                            for (unsigned int i=x2; i<256; ++i)

                            {

                                     tmp = ceil(a3*double(i)+b3);

                                     d_s[i] = (unsigned char)tmp;

                            }

                   }

         }

 

         BitPlaneSliceGray8::BitPlaneSliceGray8(unsigned char bitPlaneNum)

         {

                  unsigned char bitMaskArray[8] =

                   {

                            0x01, 0x02, 0x04, 0x08,

                            0x10, 0x20, 0x40, 0x80

                   };

 

                   for (unsigned int i=0; i<256; ++i)

                   {

                            unsigned char tmp = i;

                            tmp &= bitMaskArray[bitPlaneNum];

                            tmp = (tmp >> bitPlaneNum) * 255;

                            d_s[i] = tmp;

                  }

         }

}

(2) 直方图在GDI+1.0中没有获得支持,我们必须自行实现。直方图相关的处理在数字图像处理中占有重要地位,可以通过它获取图像灰度级的统计信息,且可以通过直方图进行一些重要的图像增强技术,如直方图均衡化,直方图规定化,基本全局门限等。

下面是获取8阶图像直方图的算法实现:

namespace nsimgtk

{

         bool GetHistogramNormalizeGray8(Gdiplus::Bitmap * const p_bitmap, float *histogramArray)

         {

                   if (p_bitmap == NULL || histogramArray == NULL)

                   {

                            return false;

                   }

 

                   Gdiplus::BitmapData bitmapData;

                   Gdiplus::Rect rect(0, 0, p_bitmap->GetWidth(), p_bitmap->GetHeight());

 

                   if (p_bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead, PixelFormat8bppIndexed, &bitmapData) != Gdiplus::Ok)

            {

                            return false;

                   }

 

                   unsigned char *pixels = (unsigned char*)bitmapData.Scan0;

        unsigned int histogram[256];

                   for (int i=0; i<256; ++i)

                   {

                            histogram[i] = 0;

                   }

 

                   for (unsigned int row=0; row<p_bitmap->GetWidth(); ++row)

                   {

                            for (unsigned int col=0; col<p_bitmap->GetHeight(); ++col)

                            {

                                     ++histogram[pixels[col+row*bitmapData.Stride]];

                            }

                   }

 

                   const unsigned int totalPixels = p_bitmap->GetWidth() * p_bitmap->GetHeight();

                   for (int i=0; i<256; ++i)

                   {

                            histogramArray[i] = float(histogram[i]) / float(totalPixels);

                   }

 

                   if (p_bitmap->UnlockBits(&bitmapData) != Gdiplus::Ok)

                   {

                            return false;

                   }

 

                   return true;

         }

}

在获取直方图后(即上面算法的第二个参数),再将其作为参数传入下面的对象的构造函数,然后以该对象为仿函数传入ProcessPixelsOneByOne即可实现8阶图像直方图均衡化:

#ifndef SPATIALDOMAIN_H

#define SPATIALDOMAIN_H

 

#include <cmath>

#include <string>

 

namespace nsimgtk

{