分享

使用GDI+灰度化图像

 yoken 2012-02-11

灰度化图像时,一定要根据原图像的像素格式,采取与之对应的灰度化方法,否则会出问题。

 此函数灰度化原图像,并把灰度化后的图像保存在*pDesBitmap中( 注:有内存泄露,因为没有及时释放开辟的调色板空间,下面有修正版本)

  1. void NewImageView::ToGray(Bitmap * pOrgBitmap,Bitmap **pDesBitmap)  
  2. {  
  3.   
  4.     int width=pOrgBitmap->GetWidth();  
  5.     int height=pOrgBitmap->GetHeight();  
  6.   
  7.     switch(pOrgBitmap->GetPixelFormat())  //像素格式不同,灰度化处理方式也不同   
  8.     {  
  9.     case PixelFormat24bppRGB:  
  10.         {  
  11.             Rect rect(0,0,width,height);  
  12.             BYTE byte;  
  13.             BitmapData bitmapData_org,bitmapData_new;  
  14.             Bitmap *pGrayImg=new Bitmap(width,height,PixelFormat8bppIndexed);  // 建立带索引的位图PixelFormat8bppIndexed,此种格式的位图,一个像素占一个字节   
  15.             ColorPalette *pal=(ColorPalette *)malloc(sizeof(ColorPalette)+256*sizeof(ARGB));  
  16.             pal->Count=256;  
  17.             pal->Flags=0;  
  18.   
  19.             for (int m=0;m<256;m++)  
  20.             {  
  21.                 pal->Entries[m]=Color::MakeARGB(255,m,m,m);  
  22.             }  
  23.   
  24.             pGrayImg->SetPalette(pal);  
  25.   
  26.             pGrayImg->LockBits(&rect,ImageLockModeWrite,PixelFormat8bppIndexed,&bitmapData_new); //锁定位图,然后对其进行读写内存操作,相关信息保存到BitmapData中   
  27.             Status iSucess=pOrgBitmap->LockBits(  
  28.                 &rect,  
  29.                 ImageLockModeWrite,  
  30.                 PixelFormat24bppRGB  ,  
  31.                 &bitmapData_org);  
  32.   
  33.             BYTE *p=(BYTE*)bitmapData_org.Scan0; //原图rect区域内存位置的起始指针,以BYTE作为单元类型   
  34.             BYTE *q=(BYTE*)bitmapData_new.Scan0;  //目标位图rect区域的起始指针   
  35.             BYTE *pt=p, *qt=q;  
  36.             BYTE val;  
  37.             //  灰度化   
  38.             for (int i=0;i<height;i++)  
  39.             {  
  40.                 pt=p+i*bitmapData_org.Stride;  //Stride为rect区域一行所占的字节数   
  41.                 qt=q+i*bitmapData_new.Stride;  
  42.   
  43.                 for (int j=0;j<width;j++)  
  44.                 {             
  45.                     val=*(pt)*0.114+(*(pt+1))*0.587+(*(pt+2))*0.299;  
  46.                     if (val>255)  
  47.                     {  
  48.                         val=255;  
  49.                     }  
  50.   
  51.                     if (val<0)  
  52.                     {  
  53.                         val=0;  
  54.                     }  
  55.   
  56.                     *qt=val;  //根据红绿蓝求出此像素的灰度值,写入目标位图内存*qt中   
  57.                     pt+=3;    //原图一个像素占3个字节,所以,计算下一个像素灰度值时,指针要挪移3个单元   
  58.                     qt+=1;    //目标位图一个像素占一个字节,所以,设置下一个像素灰度值时,指针只需挪移1个单元   
  59.   
  60.                 }  
  61.             }  
  62.             pOrgBitmap->UnlockBits(&bitmapData_org); //源图像撤销锁定   
  63.             pGrayImg->UnlockBits(&bitmapData_new);   // 目标图像撤销锁定   
  64.             *pDesBitmap=pGrayImg;                    //将目标图像的地址保存到*pDesBitmap中   
  65.         }  
  66.         break;  
  67.   
  68.     case PixelFormat32bppARGB:  
  69.         {  
  70.             Rect rect(0,0,width,height);  
  71.             BYTE byte;  
  72.             BitmapData bitmapData_org,bitmapData_new;  
  73.             Bitmap *pGrayImg=new Bitmap(width,height,PixelFormat8bppIndexed);  
  74.             ColorPalette *pal=(ColorPalette *)malloc(sizeof(ColorPalette)+256*sizeof(ARGB));  
  75.             pal->Count=256;  
  76.             pal->Flags=0;  
  77.   
  78.             for (int m=0;m<256;m++)  
  79.             {  
  80.                 pal->Entries[m]=Color::MakeARGB(255,m,m,m);  
  81.             }  
  82.   
  83.             pGrayImg->SetPalette(pal);  
  84.   
  85.             pGrayImg->LockBits(&rect,ImageLockModeWrite,PixelFormat8bppIndexed,&bitmapData_new);  
  86.   
  87.   
  88.             Status iSucess=pOrgBitmap->LockBits(  
  89.                 &rect,  
  90.                 ImageLockModeWrite,  
  91.                 PixelFormat32bppARGB  ,  
  92.                 &bitmapData_org);  
  93.   
  94.             BYTE *p=(BYTE*)bitmapData_org.Scan0;  
  95.             BYTE *q=(BYTE*)bitmapData_new.Scan0;  
  96.             BYTE *pt=p, *qt=q;  
  97.             BYTE val;  
  98.             //  灰度化   
  99.             for (int i=0;i<height;i++)  
  100.             {  
  101.                 pt=p+i*bitmapData_org.Stride;  
  102.                 qt=q+i*bitmapData_new.Stride;  
  103.   
  104.                 for (int j=0;j<width;j++)  
  105.                 {             
  106.                     val=*(pt+1)*0.114+(*(pt+2))*0.587+(*(pt+3))*0.299;  
  107.                     if (val>255)  
  108.                     {  
  109.                         val=255;  
  110.                     }  
  111.   
  112.                     if (val<0)  
  113.                     {  
  114.                         val=0;  
  115.                     }  
  116.   
  117.                     *qt=val;  
  118.                     pt+=4;  
  119.                     qt+=1;  
  120.                 }  
  121.             }  
  122.             pOrgBitmap->UnlockBits(&bitmapData_org);  
  123.             pGrayImg->UnlockBits(&bitmapData_new);  
  124.             *pDesBitmap=pGrayImg;  
  125.         }  
  126.         break;  
  127.     case PixelFormat8bppIndexed:  //之所以同为PixelFormat8bppIndexed还转换,   
  128.                                   // 是因为用m_pMemBmp=m_pImage->Clone(rect,m_pImage->GetPixelFormat())   
  129.                                   //克隆的内存位图,读写速度不如直接new Bitmap()生成的位图的读写速度快,不知道是为什么?   
  130.                                   // 所以这里,将Clone的位图再用new Bitmap 转换一下    
  131.         {  
  132.             Rect rect(0,0,width,height);  
  133.             BYTE byte;  
  134.             BitmapData bitmapData_org,bitmapData_new;  
  135.             Bitmap *pGrayImg=new Bitmap(width,height,PixelFormat8bppIndexed);  
  136.             ColorPalette *pal=(ColorPalette *)malloc(sizeof(ColorPalette)+256*sizeof(ARGB));  
  137.             pal->Count=256;  
  138.             pal->Flags=0;  
  139.             for (int m=0;m<256;m++)  
  140.             {  
  141.                 pal->Entries[m]=Color::MakeARGB(255,m,m,m);  
  142.             }  
  143.             pGrayImg->SetPalette(pal);  
  144.             pGrayImg->LockBits(&rect,ImageLockModeWrite,PixelFormat8bppIndexed,&bitmapData_new);  
  145.             Status iSucess=pOrgBitmap->LockBits(  
  146.                 &rect,  
  147.                 ImageLockModeWrite,  
  148.                 PixelFormat8bppIndexed,  
  149.                 &bitmapData_org);  
  150.   
  151.             BYTE *p=(BYTE*)bitmapData_org.Scan0;  
  152.             BYTE *q=(BYTE*)bitmapData_new.Scan0;  
  153.             BYTE *pt=p, *qt=q;  
  154.             BYTE val;  
  155.             //  灰度化   
  156.             for (int i=0;i<height;i++)  
  157.             {  
  158.                 pt=p+i*bitmapData_org.Stride;  
  159.                 qt=q+i*bitmapData_new.Stride;  
  160.                 for (int j=0;j<width;j++)  
  161.                 {             
  162.                     val=*pt;  
  163.                     *qt=val;  
  164.                     pt+=1;  
  165.                     qt+=1;  
  166.                 }  
  167.             }  
  168.             pOrgBitmap->UnlockBits(&bitmapData_org);  
  169.             pGrayImg->UnlockBits(&bitmapData_new);  
  170.             *pDesBitmap=pGrayImg;  
  171.         }  
  172.         break;  
  173.     default:  
  174.         *pDesBitmap=pOrgBitmap;  
  175.         break;  
  176.     }  
  177.       
  178. }  


调用方式如下:

  1.  if (m_pMemBmp)  
  2.    {          
  3.     delete m_pMemBmp;  
  4.     m_pMemBmp=NULL;  
  5.    }  
  6.   
  7.   
  8. Rect rect(0,0,m_pImage->GetWidth(),m_pImage->GetHeight());  
  9. m_pMemBmp=m_pImage->Clone(rect,m_pImage->GetPixelFormat());  
  10. Bitmap *p=m_pMemBmp;  
  11. ToGray(m_pMemBmp,&m_pMemBmp);  
  12. delete p;  
  13.   
  14. ReDraw();  
  15. InvalidateRect(m_ClientRect);  


 

上述灰度化图像有内存泄露问题 ,因为没有及时free掉开辟出来的调色板空间。

修改后的灰度化函数如下,只是添加了free (pal); // 释放掉了malloc开辟的空间

 

此函数将原图像灰度化,并把灰度化后的图像保存在*pDesBitmap中

  1. void NewImageView::ToGray(Bitmap * pOrgBitmap,Bitmap **pDesBitmap)  
  2. {  
  3.   
  4.     int width=pOrgBitmap->GetWidth();  
  5.     int height=pOrgBitmap->GetHeight();  
  6.   
  7.     switch(pOrgBitmap->GetPixelFormat())  //像素格式不同,灰度化处理方式也不同   
  8.     {  
  9.     case PixelFormat24bppRGB:  
  10.         {  
  11.             Rect rect(0,0,width,height);  
  12.             BYTE byte;  
  13.             BitmapData bitmapData_org,bitmapData_new;  
  14.             Bitmap *pGrayImg=new Bitmap(width,height,PixelFormat8bppIndexed);  // 建立带索引的位图PixelFormat8bppIndexed,此种格式的位图,一个像素占一个字节   
  15.             ColorPalette *pal=(ColorPalette *)malloc(sizeof(ColorPalette)+256*sizeof(ARGB));  
  16.             pal->Count=256;  
  17.             pal->Flags=2;  
  18.   
  19.             for (int m=0;m<256;m++)  
  20.             {  
  21.                 pal->Entries[m]=Color::MakeARGB(255,m,m,m);  
  22.             }  
  23.   
  24.             pGrayImg->SetPalette(pal);  
  25.             free (pal); // 释放掉malloc开辟的空间   
  26.             pGrayImg->LockBits(&rect,ImageLockModeWrite,PixelFormat8bppIndexed,&bitmapData_new); //锁定位图,然后对其进行读写内存操作,相关信息保存到BitmapData中   
  27.             Status iSucess=pOrgBitmap->LockBits(  
  28.                 &rect,  
  29.                 ImageLockModeWrite,  
  30.                 PixelFormat24bppRGB  ,  
  31.                 &bitmapData_org);  
  32.   
  33.             BYTE *p=(BYTE*)bitmapData_org.Scan0; //原图rect区域内存位置的起始指针,以BYTE作为单元类型   
  34.             BYTE *q=(BYTE*)bitmapData_new.Scan0;  //目标位图rect区域的起始指针   
  35.             BYTE *pt=p, *qt=q;  
  36.             BYTE val;  
  37.             //  灰度化   
  38.             for (int i=0;i<height;i++)  
  39.             {  
  40.                 pt=p+i*bitmapData_org.Stride;  //Stride为rect区域一行所占的字节数   
  41.                 qt=q+i*bitmapData_new.Stride;  
  42.   
  43.                 for (int j=0;j<width;j++)  
  44.                 {             
  45.                     val=*(pt)*0.114+(*(pt+1))*0.587+(*(pt+2))*0.299;  
  46.                     if (val>255)  
  47.                     {  
  48.                         val=255;  
  49.                     }  
  50.   
  51.                     if (val<0)  
  52.                     {  
  53.                         val=0;  
  54.                     }  
  55.   
  56.                     *qt=val;  //根据红绿蓝求出此像素的灰度值,写入目标位图内存*qt中   
  57.                     pt+=3;    //原图一个像素占3个字节,所以,计算下一个像素灰度值时,指针要挪移3个单元   
  58.                     qt+=1;    //目标位图一个像素占一个字节,所以,设置下一个像素灰度值时,指针只需挪移1个单元   
  59.   
  60.                 }  
  61.             }  
  62.             pOrgBitmap->UnlockBits(&bitmapData_org); //源图像撤销锁定   
  63.             pGrayImg->UnlockBits(&bitmapData_new);   // 目标图像撤销锁定   
  64.             *pDesBitmap=pGrayImg;                    //将目标图像的地址保存到*pDesBitmap中   
  65.         }  
  66.         break;  
  67.   
  68.     case PixelFormat32bppARGB:  
  69.         {  
  70.             Rect rect(0,0,width,height);  
  71.             BYTE byte;  
  72.             BitmapData bitmapData_org,bitmapData_new;  
  73.             Bitmap *pGrayImg=new Bitmap(width,height,PixelFormat8bppIndexed);  
  74.             ColorPalette *pal=(ColorPalette *)malloc(sizeof(ColorPalette)+256*sizeof(ARGB));  
  75.             pal->Count=256;  
  76.             pal->Flags=0;  
  77.   
  78.             for (int m=0;m<256;m++)  
  79.             {  
  80.                 pal->Entries[m]=Color::MakeARGB(255,m,m,m);  
  81.             }  
  82.   
  83.             pGrayImg->SetPalette(pal);  
  84.             free (pal); // 释放掉malloc开辟的空间   
  85.               
  86.             pGrayImg->LockBits(&rect,ImageLockModeWrite,PixelFormat8bppIndexed,&bitmapData_new);  
  87.             Status iSucess=pOrgBitmap->LockBits(  
  88.                 &rect,  
  89.                 ImageLockModeWrite,  
  90.                 PixelFormat32bppARGB  ,  
  91.                 &bitmapData_org);  
  92.   
  93.             BYTE *p=(BYTE*)bitmapData_org.Scan0;  
  94.             BYTE *q=(BYTE*)bitmapData_new.Scan0;  
  95.             BYTE *pt=p, *qt=q;  
  96.             BYTE val;  
  97.             //  灰度化   
  98.             for (int i=0;i<height;i++)  
  99.             {  
  100.                 pt=p+i*bitmapData_org.Stride;  
  101.                 qt=q+i*bitmapData_new.Stride;  
  102.   
  103.                 for (int j=0;j<width;j++)  
  104.                 {             
  105.                     val=*(pt+1)*0.114+(*(pt+2))*0.587+(*(pt+3))*0.299;  
  106.                     if (val>255)  
  107.                     {  
  108.                         val=255;  
  109.                     }  
  110.   
  111.                     if (val<0)  
  112.                     {  
  113.                         val=0;  
  114.                     }  
  115.   
  116.                     *qt=val;  
  117.                     pt+=4;  
  118.                     qt+=1;  
  119.                 }  
  120.             }  
  121.             pOrgBitmap->UnlockBits(&bitmapData_org);  
  122.             pGrayImg->UnlockBits(&bitmapData_new);  
  123.             *pDesBitmap=pGrayImg;  
  124.         }  
  125.         break;  
  126.     case PixelFormat8bppIndexed:  //之所以同为PixelFormat8bppIndexed还转换,   
  127.                                   // 是因为用m_pMemBmp=m_pImage->Clone(rect,m_pImage->GetPixelFormat())   
  128.                                   //克隆的内存位图,读写速度不如直接new Bitmap()生成的位图的读写速度快,不知道是为什么?   
  129.                                   // 所以这里,将Clone的位图再用new Bitmap 转换一下    
  130.         {  
  131.             Rect rect(0,0,width,height);  
  132.             BYTE byte;  
  133.             BitmapData bitmapData_org,bitmapData_new;  
  134.             Bitmap *pGrayImg=new Bitmap(width,height,PixelFormat8bppIndexed);  
  135.             ColorPalette *pal=(ColorPalette *)malloc(sizeof(ColorPalette)+256*sizeof(ARGB));  
  136.             pal->Count=256;  
  137.             pal->Flags=0;  
  138.             for (int m=0;m<256;m++)  
  139.             {  
  140.                 pal->Entries[m]=Color::MakeARGB(255,m,m,m);  
  141.             }  
  142.             pGrayImg->SetPalette(pal);  
  143.             free (pal); // 释放掉malloc开辟的空间   
  144.   
  145.             pGrayImg->LockBits(&rect,ImageLockModeWrite,PixelFormat8bppIndexed,&bitmapData_new);  
  146.             Status iSucess=pOrgBitmap->LockBits(  
  147.                 &rect,  
  148.                 ImageLockModeWrite,  
  149.                 PixelFormat8bppIndexed,  
  150.                 &bitmapData_org);  
  151.   
  152.             BYTE *p=(BYTE*)bitmapData_org.Scan0;  
  153.             BYTE *q=(BYTE*)bitmapData_new.Scan0;  
  154.             BYTE *pt=p, *qt=q;  
  155.             BYTE val;  
  156.             //  灰度化   
  157.             for (int i=0;i<height;i++)  
  158.             {  
  159.                 pt=p+i*bitmapData_org.Stride;  
  160.                 qt=q+i*bitmapData_new.Stride;  
  161.                 for (int j=0;j<width;j++)  
  162.                 {             
  163.                     val=*pt;  
  164.                     *qt=val;  
  165.                     pt+=1;  
  166.                     qt+=1;  
  167.                 }  
  168.             }  
  169.             pOrgBitmap->UnlockBits(&bitmapData_org);  
  170.             pGrayImg->UnlockBits(&bitmapData_new);  
  171.             *pDesBitmap=pGrayImg;  
  172.         }  
  173.         break;  
  174.     default:  
  175.         *pDesBitmap=pOrgBitmap;  
  176.         break;  
  177.     }  
  178.       
  179. }  


 

使用free (pal); // 释放掉malloc开辟的空间 。

因为SetPalette(pal);已经将调色板信息放入位图中了,所以NEW 出来的这个调色板已经不需要了,因此要及时释放资源。

既然能将调色板信息直接放入位图中,那是不是也可以将调色板设置成局部变量呢?

 

  1. ColorPalette pal;  
  2. pal.Count=256;  
  3. pal.Flags=0;  
  4. for (int m=0;m<256;m++)  
  5.     pal.Entries[m]=Color::MakeARGB(255,m,m,m);  
  6. pGrayImg->SetPalette(&pal);  

 

运行时,虽不报错,但是不显示图像,而且直接程序就退出了。 这是什么原因呢?

看下调色板的定义:

  1. typedef struct {  
  2.     UINT Flags;  
  3.     UINT Count;  
  4.     ARGB Entries[1];  
  5. } ColorPalette;  


其中,颜色矩阵大小为1,这是需要我们手动开辟空间更改的,所以将调色板设置成局部变量,而不给颜色矩阵开辟空间,直接访问pal[i]的话,便会出错。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多