灰度化图像时,一定要根据原图像的像素格式,采取与之对应的灰度化方法,否则会出问题。
此函数灰度化原图像,并把灰度化后的图像保存在*pDesBitmap中( 注:有内存泄露,因为没有及时释放开辟的调色板空间,下面有修正版本)
调用方式如下:
- if (m_pMemBmp)
- {
- delete m_pMemBmp;
- m_pMemBmp=NULL;
- }
- Rect rect(0,0,m_pImage->GetWidth(),m_pImage->GetHeight());
- m_pMemBmp=m_pImage->Clone(rect,m_pImage->GetPixelFormat());
- Bitmap *p=m_pMemBmp;
- ToGray(m_pMemBmp,&m_pMemBmp);
- delete p;
- ReDraw();
- InvalidateRect(m_ClientRect);
上述灰度化图像有内存泄露问题 ,因为没有及时free掉开辟出来的调色板空间。
修改后的灰度化函数如下,只是添加了free (pal); // 释放掉了malloc开辟的空间
此函数将原图像灰度化,并把灰度化后的图像保存在*pDesBitmap中
- void NewImageView::ToGray(Bitmap * pOrgBitmap,Bitmap **pDesBitmap)
- {
- int width=pOrgBitmap->GetWidth();
- int height=pOrgBitmap->GetHeight();
- switch(pOrgBitmap->GetPixelFormat()) //像素格式不同,灰度化处理方式也不同
- {
- case PixelFormat24bppRGB:
- {
- Rect rect(0,0,width,height);
- BYTE byte;
- BitmapData bitmapData_org,bitmapData_new;
- Bitmap *pGrayImg=new Bitmap(width,height,PixelFormat8bppIndexed); // 建立带索引的位图PixelFormat8bppIndexed,此种格式的位图,一个像素占一个字节
- ColorPalette *pal=(ColorPalette *)malloc(sizeof(ColorPalette)+256*sizeof(ARGB));
- pal->Count=256;
- pal->Flags=2;
- for (int m=0;m<256;m++)
- {
- pal->Entries[m]=Color::MakeARGB(255,m,m,m);
- }
- pGrayImg->SetPalette(pal);
- free (pal); // 释放掉malloc开辟的空间
- pGrayImg->LockBits(&rect,ImageLockModeWrite,PixelFormat8bppIndexed,&bitmapData_new); //锁定位图,然后对其进行读写内存操作,相关信息保存到BitmapData中
- Status iSucess=pOrgBitmap->LockBits(
- &rect,
- ImageLockModeWrite,
- PixelFormat24bppRGB ,
- &bitmapData_org);
- BYTE *p=(BYTE*)bitmapData_org.Scan0; //原图rect区域内存位置的起始指针,以BYTE作为单元类型
- BYTE *q=(BYTE*)bitmapData_new.Scan0; //目标位图rect区域的起始指针
- BYTE *pt=p, *qt=q;
- BYTE val;
- // 灰度化
- for (int i=0;i<height;i++)
- {
- pt=p+i*bitmapData_org.Stride; //Stride为rect区域一行所占的字节数
- qt=q+i*bitmapData_new.Stride;
- for (int j=0;j<width;j++)
- {
- val=*(pt)*0.114+(*(pt+1))*0.587+(*(pt+2))*0.299;
- if (val>255)
- {
- val=255;
- }
- if (val<0)
- {
- val=0;
- }
- *qt=val; //根据红绿蓝求出此像素的灰度值,写入目标位图内存*qt中
- pt+=3; //原图一个像素占3个字节,所以,计算下一个像素灰度值时,指针要挪移3个单元
- qt+=1; //目标位图一个像素占一个字节,所以,设置下一个像素灰度值时,指针只需挪移1个单元
- }
- }
- pOrgBitmap->UnlockBits(&bitmapData_org); //源图像撤销锁定
- pGrayImg->UnlockBits(&bitmapData_new); // 目标图像撤销锁定
- *pDesBitmap=pGrayImg; //将目标图像的地址保存到*pDesBitmap中
- }
- break;
- case PixelFormat32bppARGB:
- {
- Rect rect(0,0,width,height);
- BYTE byte;
- BitmapData bitmapData_org,bitmapData_new;
- Bitmap *pGrayImg=new Bitmap(width,height,PixelFormat8bppIndexed);
- ColorPalette *pal=(ColorPalette *)malloc(sizeof(ColorPalette)+256*sizeof(ARGB));
- pal->Count=256;
- pal->Flags=0;
- for (int m=0;m<256;m++)
- {
- pal->Entries[m]=Color::MakeARGB(255,m,m,m);
- }
- pGrayImg->SetPalette(pal);
- free (pal); // 释放掉malloc开辟的空间
- pGrayImg->LockBits(&rect,ImageLockModeWrite,PixelFormat8bppIndexed,&bitmapData_new);
- Status iSucess=pOrgBitmap->LockBits(
- &rect,
- ImageLockModeWrite,
- PixelFormat32bppARGB ,
- &bitmapData_org);
- BYTE *p=(BYTE*)bitmapData_org.Scan0;
- BYTE *q=(BYTE*)bitmapData_new.Scan0;
- BYTE *pt=p, *qt=q;
- BYTE val;
- // 灰度化
- for (int i=0;i<height;i++)
- {
- pt=p+i*bitmapData_org.Stride;
- qt=q+i*bitmapData_new.Stride;
- for (int j=0;j<width;j++)
- {
- val=*(pt+1)*0.114+(*(pt+2))*0.587+(*(pt+3))*0.299;
- if (val>255)
- {
- val=255;
- }
- if (val<0)
- {
- val=0;
- }
- *qt=val;
- pt+=4;
- qt+=1;
- }
- }
- pOrgBitmap->UnlockBits(&bitmapData_org);
- pGrayImg->UnlockBits(&bitmapData_new);
- *pDesBitmap=pGrayImg;
- }
- break;
- case PixelFormat8bppIndexed: //之所以同为PixelFormat8bppIndexed还转换,
- // 是因为用m_pMemBmp=m_pImage->Clone(rect,m_pImage->GetPixelFormat())
- //克隆的内存位图,读写速度不如直接new Bitmap()生成的位图的读写速度快,不知道是为什么?
- // 所以这里,将Clone的位图再用new Bitmap 转换一下
- {
- Rect rect(0,0,width,height);
- BYTE byte;
- BitmapData bitmapData_org,bitmapData_new;
- Bitmap *pGrayImg=new Bitmap(width,height,PixelFormat8bppIndexed);
- ColorPalette *pal=(ColorPalette *)malloc(sizeof(ColorPalette)+256*sizeof(ARGB));
- pal->Count=256;
- pal->Flags=0;
- for (int m=0;m<256;m++)
- {
- pal->Entries[m]=Color::MakeARGB(255,m,m,m);
- }
- pGrayImg->SetPalette(pal);
- free (pal); // 释放掉malloc开辟的空间
- pGrayImg->LockBits(&rect,ImageLockModeWrite,PixelFormat8bppIndexed,&bitmapData_new);
- Status iSucess=pOrgBitmap->LockBits(
- &rect,
- ImageLockModeWrite,
- PixelFormat8bppIndexed,
- &bitmapData_org);
- BYTE *p=(BYTE*)bitmapData_org.Scan0;
- BYTE *q=(BYTE*)bitmapData_new.Scan0;
- BYTE *pt=p, *qt=q;
- BYTE val;
- // 灰度化
- for (int i=0;i<height;i++)
- {
- pt=p+i*bitmapData_org.Stride;
- qt=q+i*bitmapData_new.Stride;
- for (int j=0;j<width;j++)
- {
- val=*pt;
- *qt=val;
- pt+=1;
- qt+=1;
- }
- }
- pOrgBitmap->UnlockBits(&bitmapData_org);
- pGrayImg->UnlockBits(&bitmapData_new);
- *pDesBitmap=pGrayImg;
- }
- break;
- default:
- *pDesBitmap=pOrgBitmap;
- break;
- }
- }
使用free (pal); // 释放掉malloc开辟的空间 。
因为SetPalette(pal);已经将调色板信息放入位图中了,所以NEW 出来的这个调色板已经不需要了,因此要及时释放资源。
既然能将调色板信息直接放入位图中,那是不是也可以将调色板设置成局部变量呢?
- ColorPalette pal;
- pal.Count=256;
- pal.Flags=0;
- for (int m=0;m<256;m++)
- pal.Entries[m]=Color::MakeARGB(255,m,m,m);
- pGrayImg->SetPalette(&pal);
运行时,虽不报错,但是不显示图像,而且直接程序就退出了。 这是什么原因呢?
看下调色板的定义:
- typedef struct {
- UINT Flags;
- UINT Count;
- ARGB Entries[1];
- } ColorPalette;
其中,颜色矩阵大小为1,这是需要我们手动开辟空间更改的,所以将调色板设置成局部变量,而不给颜色矩阵开辟空间,直接访问pal[i]的话,便会出错。
联系客服