简易的灰度处理

10 篇文章 0 订阅
10 篇文章 0 订阅

近期在进行自绘控件的开发时,时常用到灰度图像。譬如真彩色工具条中的Disable状态的图标,譬如真彩菜单Disable状态的图标等。照常来说,可以让控件的使用者去制作相应的图标。然而,为了让控件的使用者在使用控件时尽量简单,一个比较好的办法是在程序中生成Disable状态的图标。本文提供了一个简单的封装类CGrayBitmap,使用它的静态方法DoGray可以根据一个常规图片生成它的灰度图。

      原创文章,转帖请注明出处:blog.csdn.net/sjdev

     

要对图像进行灰度处理,首先需要获取到图像的数据。GetBitmapBits和GetDIBits都可以得到位图的数据。GetBitmapBits用于获取设备独立位图的数据,GetDIBits用于获取兼容位图的数据。MSDN提示说GetBitmapBits只是为了兼容16位Windows而提供的,所以推荐使用GetDIBits。另外GetPixel也可以获取位图数据,不过在进行灰度处理时不建议使用,因为速度太慢了(在某些特殊情况下,GetPixel还是很有用的)。

首先看看GetDIBits函数的定义吧:

int GetDIBits(HDC hdc, HBITMAP hbmp, UINT uStartScan, UINT uScanLines, LPVOID lpvBits, LPBITMAPINFO lpbi, UINT uUsage);

注意,GetDIBits的第二个参数hbmp必须为兼容位图;lpvBits用于接收位图数据,如果该参数为空,函数调用将填充lpbi的相应参数;lpbi参数表示指向BITMAPINFO结构的指针,它指定了设备无关位图的数据结构;uUsage用于指定BITMAPINFO结构中bmpColors成员的数据格式,这里咱们使用DIB_RGB_COLORS,它表示颜色表由RGB三个值直接构成(另外一个参数DIB_PAL_COLORS表示使用调色板)。

来看一下使用GetDIBits获取位图数据的代码:

[cpp]  view plain copy
  1. // 获取对象信息  
  2. BITMAP bm;     
  3. if (!::GetObject(hSrcBitmap, sizeof(BITMAP), (LPBYTE)&bm))  
  4.     return NULL;  
  5.   
  6. // 定义位图信息  
  7. BITMAPINFO bi;  
  8. bi.bmiHeader.biSize = sizeof(bi.bmiHeader);  
  9. bi.bmiHeader.biWidth = bm.bmWidth;  
  10. bi.bmiHeader.biHeight = -bm.bmHeight;  
  11. bi.bmiHeader.biPlanes = 1;  
  12. bi.bmiHeader.biBitCount = 32;   
  13. bi.bmiHeader.biCompression = BI_RGB;   
  14. bi.bmiHeader.biSizeImage = bm.bmWidth * 4 * bm.bmHeight; // 32 bit  
  15. bi.bmiHeader.biClrUsed = 0;  
  16. bi.bmiHeader.biClrImportant = 0;  
  17.   
  18. // 获取位图数据  
  19. HDC hdc = GetDC(NULL);  
  20. BYTE* pBits = (BYTE*)new BYTE[bi.bmiHeader.biSizeImage];  
  21. ::ZeroMemory(pBits, bi.bmiHeader.biSizeImage);  
  22. if (!::GetDIBits(hdc, hSrcBitmap, 0, bm.bmHeight, pBits, &bi, DIB_RGB_COLORS))  
  23. {  
  24.     delete pBits;  
  25.     pBits = NULL;  
  26. }  

得到数据之后,就可以对于数据进行处理了。由于我们得到的是RGB数据,为了处理方便,定义了一个RGBX结构。灰度算法比较多,这里使用了常用的加权法。

来看一下处理数据的代码:

[cpp]  view plain copy
  1. // 对位图数据进行处理  
  2. RGBX* pSrc = (RGBX*)pBits;  
  3. RGBX* pDest = (RGBX*)new BYTE[bi.bmiHeader.biSizeImage];  
  4. ::ZeroMemory(pDest, bi.bmiHeader.biSizeImage);  
  5. for (LONG i = 0; i < bm.bmWidth; i++)     
  6. {     
  7.     for (LONG j = 0; j < bm.bmHeight; j++)     
  8.     {     
  9.         RGBX* pRGBSrc = &pSrc[j * bm.bmWidth + i];  
  10.         RGBX* pRGBDest = &pDest[j * bm.bmWidth + i];  
  11.         *pRGBDest = pRGBSrc->Gray();  
  12.     }     
  13. }    

将数据处理完之后,我们需要创建一个新的位图并给它设置位图数据,这样,新的位图就生成了。注意SetDIBits参数中指定的位图,必须是兼容位图,所以程序中采用CreateCompatibleBitmap而不是CreateBitmap函数来创建位图。代码如下:

[cpp]  view plain copy
  1. // 创建新位图,设置位图数据  
  2. HBITMAP hGray = ::CreateCompatibleBitmap(hdc, bm.bmWidth, bm.bmHeight);  
  3. ::SetDIBits(hdc, hGray, 0, bm.bmHeight, pDest, &bi, DIB_RGB_COLORS);  

附件:

CGrayBitmap类的定义如下:

 

[cpp]  view plain copy
  1. #pragma once  
  2.   
  3. ///  
  4. // CGrayBitmap  
  5. class CGrayBitmap  
  6. {  
  7. ///  
  8. // RGBX  
  9. #pragma pack(push)  
  10. #pragma pack(1)  
  11.   
  12.     typedef struct tagRGBX  
  13.     {  
  14.     public:       
  15.         tagRGBX(BYTE red, BYTE green, BYTE blue)   
  16.         {   
  17.             btRed = red;   
  18.             btBlue = blue;   
  19.             btGreen = green;   
  20.             btUnused = 0;   
  21.         }  
  22.   
  23.         BYTE btBlue;  
  24.         BYTE btGreen;  
  25.         BYTE btRed;  
  26.   
  27.     protected:  
  28.         BYTE btUnused;  
  29.   
  30.     public:  
  31.         tagRGBX Gray()   
  32.         {   
  33.             int r = (int)btRed * 3;  
  34.             int g = (int)btGreen * 6;  
  35.             int b = (int)btBlue;  
  36.             BYTE btGray = (BYTE)((r + g + b) / 10);  
  37.             return RGBX(btGray, btGray, btGray);  
  38.         }  
  39.     }RGBX;  
  40.   
  41. #pragma pack(pop)  
  42. private:  
  43.     CGrayBitmap(){}  
  44. public:   
  45.     static HBITMAP DoGray(const HBITMAP hSrcBitmap)     
  46.     {     
  47.         ASSERT(hSrcBitmap != NULL);  
  48.   
  49.         // 获取对象信息  
  50.         BITMAP bm;     
  51.         if (!::GetObject(hSrcBitmap, sizeof(BITMAP), (LPBYTE)&bm))  
  52.             return NULL;  
  53.   
  54.         // 定义位图信息  
  55.         BITMAPINFO bi;  
  56.         bi.bmiHeader.biSize = sizeof(bi.bmiHeader);  
  57.         bi.bmiHeader.biWidth = bm.bmWidth;  
  58.         bi.bmiHeader.biHeight = -bm.bmHeight;  
  59.         bi.bmiHeader.biPlanes = 1;  
  60.         bi.bmiHeader.biBitCount = 32;   
  61.         bi.bmiHeader.biCompression = BI_RGB;   
  62.         bi.bmiHeader.biSizeImage = bm.bmWidth * 4 * bm.bmHeight; // 32 bit  
  63.         bi.bmiHeader.biClrUsed = 0;  
  64.         bi.bmiHeader.biClrImportant = 0;  
  65.   
  66.         // 获取位图数据  
  67.         HDC hdc = GetDC(NULL);  
  68.         BYTE* pBits = (BYTE*)new BYTE[bi.bmiHeader.biSizeImage];  
  69.         ::ZeroMemory(pBits, bi.bmiHeader.biSizeImage);  
  70.         if (!::GetDIBits(hdc, hSrcBitmap, 0, bm.bmHeight, pBits, &bi, DIB_RGB_COLORS))  
  71.         {  
  72.             delete pBits;  
  73.             pBits = NULL;  
  74.         }  
  75.   
  76.         // 对位图数据进行处理  
  77.         RGBX* pSrc = (RGBX*)pBits;  
  78.         RGBX* pDest = (RGBX*)new BYTE[bi.bmiHeader.biSizeImage];  
  79.         ::ZeroMemory(pDest, bi.bmiHeader.biSizeImage);  
  80.         for (LONG i = 0; i < bm.bmWidth; i++)     
  81.         {     
  82.             for (LONG j = 0; j < bm.bmHeight; j++)     
  83.             {     
  84.                 RGBX* pRGBSrc = &pSrc[j * bm.bmWidth + i];  
  85.                 RGBX* pRGBDest = &pDest[j * bm.bmWidth + i];  
  86.                 *pRGBDest = pRGBSrc->Gray();  
  87.             }     
  88.         }    
  89.   
  90.         // 创建新位图,设置位图数据  
  91.         HBITMAP hGray = ::CreateCompatibleBitmap(hdc, bm.bmWidth, bm.bmHeight);  
  92.         ::SetDIBits(hdc, hGray, 0, bm.bmHeight, pDest, &bi, DIB_RGB_COLORS);  
  93.           
  94.         // 释放资源  
  95.         delete[] pBits;  
  96.         pBits = NULL;  
  97.         delete[] pDest;   
  98.         pDest = NULL;  
  99.         ::ReleaseDC(NULL,hdc);     
  100.   
  101.         return hGray;  
  102.     }  
  103. };  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值