这个类本身应该说是很有用的,但要想用好它还真有些技巧。所谓难者不会,会者不难。
其实介绍总结它用法的文章很多了,之所以我要在写一下,就是从我理解的方式再说一遍。
毕竟大家思路不一样,理解起来可能有偏差。我就是看了msdn后还是没搞明白,又看了很多帖子,综合起来看才搞明白。
首先遇到的问题:为啥用CImage类进行像素操作会这么慢?我本来只是怀疑,但我在http://www.qqgb.com/Program/VC/VCJQ/Program_181956.html找到了答案。和我怀疑的一样。
点对点的图像处理用GetPixel和SetPixel就是自己找慢 这两个都是函数,光参数进出栈的时间都比处理的时间长,更不用说函数内部繁琐的判断和逻辑消耗的时间了 你需要得到CImage对象的Buffer,锁定后直接操作内存
既然这样,那我们怎么得到CImage对象的Buffer?看msdn,以及网上的帖子,都说用GetBits(),但真用对了,还真费了点周折。
主要综合了如下3个帖子。
http://hi.baidu.com/sealmlove2/blog/item/fb615c38202943fb3a87ce82.html
http://blog.sina.com.cn/s/blog_487547aa0100an6k.html
http://topic.csdn.net/u/20080608/00/4df18305-7852-42ab-a948-88789ea3e65e.html
其实GetBits()返回的就是 该类本身一个成员HBITMAP m_hBitmap;中相应的dib数据部分,但具体指向的是哪部分,还有一定的讲究。
typedef struct tagBITMAP { // bm LONG bmType;
LONG bmWidth;
LONG bmHeight;
LONG bmWidthBytes;
WORD bmPlanes;
WORD bmBitsPixel;
LPVOID bmBits; <-----------------------------
} BITMAP;
结合msdn说明 及以上文章,总结出如下方法:
1、定义数据区指针为BYTE* img_Data img_Data=(BYTE *)m_Image.GetBits()+(m_Image.GetPitch()*(m_Image.GetHeight()-1));
2、if( pitch < 0) pImageData = image . GetPixelAddress(h -1 ,0);
else pImageData = image. GetPixelAddress( 0,0);
前因后果就不多解释了,那几个文章说得很清楚。
如果一直用这个指针操作的话,需要注意几个问题:
1、了解各行数据的存放位置关系;GetPitch()
2、字节对齐问题;GetPitch()
3、各像素所占位置大小;GetBPP()
其实每次都用 GetPixelAddress 也可以 ,我就是这么用的。
取像素和设置像素颜色信息 上面文章给了函数。
我改造成了如下代码:
取
BYTE* pByte = (BYTE *)m_bmpImage.GetPixelAddress(x,y);
pixelsB[x+y*w] = *(pByte);
pixelsG[x+y*w] = *(pByte+1);
pixelsR[x+y*w] = *(pByte+2);
设
BYTE *p = (BYTE*)resImg->GetPixelAddress(x, y);
*p++ = totalB&0xFF;
*p++ = totalG&0xFF;
*p = totalR&0xFF;
其他的一些问题在上面的几个文章中,以及msdn上都说得很明白了,我就不再费口舌了。