C++图像处理 -- 数据类型及公用函数
2012-01-09 21:34
441 查看
阅读提示:
《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。
《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。
尽可能保持二者内容一致,可相互对照。 不经意间,用C++写了不少有关图像处理的文章,与《Delphi图像处理》系列文章相比,文章之间缺乏必要的联系性,因此有必要进行一些调整,并都纳入《C++图像处理系列》。 本文写了一个C++头文件BmpData.h,它包含了Gdiplus.h文件,并提供了几个最基础的函数。 以后,所有《C++图像处理》系列的文章都包含此头文件,并直接使用GDI+位图数据结构BitmapData类型处理图像。例子也以GDI+位图为主。
因水平有限,错误在所难免,欢迎指正和指导。邮箱地址:maozefa@hotmail.com
这里可访问《C++图像处理 -- 文章索引》。
《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。
《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。
尽可能保持二者内容一致,可相互对照。 不经意间,用C++写了不少有关图像处理的文章,与《Delphi图像处理》系列文章相比,文章之间缺乏必要的联系性,因此有必要进行一些调整,并都纳入《C++图像处理系列》。 本文写了一个C++头文件BmpData.h,它包含了Gdiplus.h文件,并提供了几个最基础的函数。 以后,所有《C++图像处理》系列的文章都包含此头文件,并直接使用GDI+位图数据结构BitmapData类型处理图像。例子也以GDI+位图为主。
//--------------------------------------------------------------------------- #ifndef BmpDataH #define BmpDataH #include <windows.h> #include <algorithm> using std::min; using std::max; #include <gdiplus.h> using namespace Gdiplus; //--------------------------------------------------------------------------- #define ScanAllocFlag 0x00000100 #define PixelAlphaFlag 0x00010000 //--------------------------------------------------------------------------- // 定义象素插值方式 typedef enum { InterpolateModeDefault, // 缺省为线形插值 InterpolateModeNear, // 临近插值 InterpolateModeBilinear,// 线形插值 InterpolateModeBicubic // 双立方插值 }InterpolateMode; typedef enum { // PixelFormatInValid, PixelFormat1bit, PixelFormat4bit, PixelFormat8bit, PixelFormat15bit, PixelFormat16bit, PixelFormat24bit, PixelFormat32bit }ImagePixelFormat; // 定义ARGB像素结构 typedef union { ARGB Color; struct { BYTE Blue; BYTE Green; BYTE Red; BYTE Alpha; }; }ARGBQuad, *PARGBQuad; //--------------------------------------------------------------------------- FORCEINLINE VOID SetAlphaFlag(BitmapData *data, BOOL isAlpha) { if (isAlpha) data->Reserved |= PixelAlphaFlag; else data->Reserved &= ~PixelAlphaFlag; } //--------------------------------------------------------------------------- FORCEINLINE BOOL HasAlphaFlag(CONST BitmapData *data) { return (data->Reserved & PixelAlphaFlag) != 0; } //--------------------------------------------------------------------------- FORCEINLINE VOID SetInterpolateMode(BitmapData *data, InterpolateMode mode) { data->Reserved = (data->Reserved & 0xffffff) | (mode << 24); } //--------------------------------------------------------------------------- FORCEINLINE InterpolateMode GetInterpolateMode(CONST BitmapData *data) { return (InterpolateMode)(data->Reserved >> 24); } //--------------------------------------------------------------------------- // 锁定GDI+32位位图扫描线到data FORCEINLINE VOID LockBitmap(Gdiplus::Bitmap *bmp, BitmapData *data) { Gdiplus::Rect r(0, 0, bmp->GetWidth(), bmp->GetHeight()); BOOL hasAlpha = bmp->GetPixelFormat() & PixelFormatAlpha; bmp->LockBits(&r, ImageLockModeRead | ImageLockModeWrite, PixelFormat32bppARGB, data); SetAlphaFlag(data, hasAlpha); } //--------------------------------------------------------------------------- // GDI+位图扫描线解锁 FORCEINLINE VOID UnlockBitmap(Gdiplus::Bitmap *bmp, BitmapData *data) { data->Reserved &= 0xff; bmp->UnlockBits(data); } //--------------------------------------------------------------------------- // 用给定的图像数据制造并返回与GDI+兼容的32位位图数据结构。 // 参数;宽度,高度,扫描线宽度,扫描线首地址,alpha标记,返回的位图数据结构指针。 // 注:如果stride=0,自动计算扫描线宽度 FORCEINLINE VOID GetBitmapData(INT width, INT height, INT stride, LPVOID scan0, ImagePixelFormat format, BOOL isAlpha, BitmapData *data) { INT bits[] = {0x100, 0x400, 0x800, 0x1005, 0x1000, 0x1800, 0x2000}; data->Width = width; data->Height = height; data->Scan0 = scan0; data->PixelFormat = bits[format]; if (stride) data->Stride = stride; else data->Stride = (INT)((width * (data->PixelFormat >> 8) + 31) & ~31) >> 3; SetAlphaFlag(data, isAlpha); } //--------------------------------------------------------------------------- // 用给定的宽度、高度和像素位数制造并返回新的与GDI+兼容的位图数据结构。 // 必须用FreeBitmapData释放 FORCEINLINE VOID GetBitmapData(INT width, INT height, ImagePixelFormat format, BitmapData *data) { GetBitmapData(width, height, 0, NULL, format, format == PixelFormat32bit, data); data->Scan0 = GlobalLock(GlobalAlloc(GHND, data->Height * data->Stride)); if (data->Scan0) data->Reserved |= ScanAllocFlag; } //--------------------------------------------------------------------------- // 用给定的宽度和高度制造并返回新的与GDI+兼容的32位位图数据结构。 // 必须用FreeBitmapData释放 FORCEINLINE VOID GetBitmapData(INT width, INT height, BitmapData *data) { GetBitmapData(width, height, PixelFormat32bit, data); } //--------------------------------------------------------------------------- // 获取32位子位图数据结构 FORCEINLINE BOOL GetBitmapData(CONST BitmapData *data, INT x, INT y, INT width, INT height, BitmapData *sub) { width += x; height += y; if (width > (INT)data->Width) width = data->Width; if (height > (INT)data->Height) height = data->Height; INT ScanOffset = 0; if (x > 0) { width -= x; ScanOffset += (x << 2); } if (y > 0) { height -= y; ScanOffset += (y * data->Stride); } sub->Scan0 = (LPBYTE)data->Scan0 + ScanOffset; if (width <= 0 || height <= 0) return FALSE; sub->Width = width; sub->Height = height; sub->Stride = data->Stride; sub->PixelFormat = data->PixelFormat; sub->Reserved = data->Reserved & ~ScanAllocFlag; return TRUE; } //--------------------------------------------------------------------------- // 如果data分配了扫描线内存,释放扫描线内存 FORCEINLINE VOID FreeBitmapData(BitmapData *data) { if ((data->Reserved & ScanAllocFlag) && data->Scan0) { HGLOBAL handle = GlobalHandle(data->Scan0); if (handle) { GlobalUnlock(handle); GlobalFree(handle); } data->Reserved = 0; } } //--------------------------------------------------------------------------- // 获取32位位图数据拷贝参数 // 参数:目标数据,源数据,宽度,高度,目标扫描线,源扫描线,目标偏移,源偏移 FORCEINLINE VOID GetDataCopyParams(CONST BitmapData *dest, CONST BitmapData *source, UINT &width, UINT &height, PARGBQuad &dstScan0, PARGBQuad &srcScan0, INT &dstOffset, INT &srcOffset) { width = dest->Width < source->Width? dest->Width : source->Width; height = dest->Height < source->Height? dest->Height : source->Height; dstScan0 = (PARGBQuad)dest->Scan0; srcScan0 = (PARGBQuad)source->Scan0; dstOffset = (dest->Stride >> 2) - (INT)width; srcOffset = (source->Stride >> 2) - (INT)width; } //--------------------------------------------------------------------------- // 获取并返回32位位图数据结构data的边框扩展图像数据结构。Radius:扩展半径 FORCEINLINE VOID GetExpendData(CONST BitmapData *data, UINT radius, BitmapData *exp) { GetBitmapData(data->Width + (radius << 1), data->Height + (radius << 1), PixelFormat32bit, exp); SetAlphaFlag(exp, HasAlphaFlag(data)); BitmapData sub; PARGBQuad pd, ps; UINT width, height; INT dstOffset, srcOffset; GetBitmapData(exp, radius, radius, data->Width, data->Height, &sub); GetDataCopyParams(&sub, data, width, height, pd, ps, dstOffset, srcOffset); PARGBQuad pt = pd - radius; UINT x, y; // 如果图像数据含Alpha,转换为PARGB像素格式 if (HasAlphaFlag(data)) { for (y = 0; y < height; y ++, pd += dstOffset, ps += srcOffset) { for (x = 0; x < width; x ++, pd ++, ps ++) { pd->Blue = (ps->Blue * ps->Alpha + 127) / 255; pd->Green = (ps->Green * ps->Alpha + 127) / 255; pd->Red = (ps->Red * ps->Alpha + 127) / 255; pd->Alpha = ps->Alpha; } } } // 否则, 直接像素拷贝 else { for (y = 0; y < height; y ++, pd += dstOffset, ps += srcOffset) { for (x = 0; x < width; *pd ++ = *ps ++, x ++); } } // 扩展左右边框像素 for (y = 0, pd = pt; y < height; y ++) { for (x = 0, ps = pd + radius; x < radius; *pd ++ = *ps, x ++); for (x = 0, pd += width, ps = pd - 1; x < radius; *pd ++ = *ps, x ++); } // 扩展头尾边框像素 PARGBQuad pb = (PARGBQuad)((LPBYTE)pd - exp->Stride); PARGBQuad pd0 = (PARGBQuad)exp->Scan0; for (y = 0; y < radius; y ++) { for (x = 0; x < exp->Width; *pd0 ++ = pt[x], *pd ++ = pb[x], x ++); } } //--------------------------------------------------------------------------- // PARGB格式转换成ARGB格式 FORCEINLINE VOID PArgbConvertArgb(BitmapData *data) { PARGBQuad p = (PARGBQuad)data->Scan0; INT dataOffset = (data->Stride >> 2) - (INT)data->Width; for (UINT y = 0; y < data->Height; y ++, p += dataOffset) { for (UINT x = 0; x < data->Width; x ++, p ++) { p->Blue = p->Blue * 255 / p->Alpha; p->Green = p->Green * 255 / p->Alpha; p->Red = p->Red * 255 / p->Alpha; } } } //--------------------------------------------------------------------------- // ARGB格式转换成PARGB格式 FORCEINLINE VOID ArgbConvertPArgb(BitmapData *data) { PARGBQuad p = (PARGBQuad)data->Scan0; INT dataOffset = (data->Stride >> 2) - (INT)data->Width; for (UINT y = 0; y < data->Height; y ++, p += dataOffset) { for (UINT x = 0; x < data->Width; x ++, p ++) { p->Blue = (p->Blue * p->Alpha + 127) / 255; p->Green = (p->Green * p->Alpha + 127) / 255; p->Red = (p->Red * p->Alpha + 127) / 255; } } } //--------------------------------------------------------------------------- #endif
因水平有限,错误在所难免,欢迎指正和指导。邮箱地址:maozefa@hotmail.com
这里可访问《C++图像处理 -- 文章索引》。
相关文章推荐
- C++图像处理 -- 数据类型及公用函数
- 计算机视觉与图像处理学习笔记(三)opencv的基本数据类型与简单图像处理函数
- matlab中图像数据类型及处理函数
- Delphi图像处理 -- 数据类型及公用过程
- 一段小学信息技术基础知识的C++源程序: 函数,输入输出,数据类型,循环
- 求变量的数据类型,typeid,bool,C和C++的不同,new和delete,C++中的枚举,inline和可变参数模板,auto和函数模板,宽字符
- C++中判断数据类型的函数
- JavaScript(1)——数据类型、运算符、流程处理、函数
- 为什么在C++使用pthread_create()的时候,类成员函数做线程的处理函数必须要定义成static类型的?
- C++中printf、sprintf等函数读写64位字节数据类型
- C++ - 使用非成员函数(non-member)处理函数的所有参数都需要类型转换
- 图像处理之其他杂项(四)之cvSnakeImage()函数代码升级,从C接口到C++接口:snakeImage()
- Sql Server函数全解<三>数据类型转换函数和文本图像函数
- 《C++第十四周实验报告1-2》---规定MyArray只能处理元素为整型的数据未免太弱了, 请设计成模板类,使之适应各种类型
- Sql Server函数全解(三)数据类型转换函数和文本图像函数
- C++与Python的混合编程-调用有参函数以及C++数据类型与Python数据类型间的转换
- 函数处理,用指针类型是数据做函数参数比较大小
- trunc()函数用法处理日期、数字类型数据
- C++/CLI 托管C++的基本数据类型及函数【3】
- 图像处理中像素点的问题:double、long、unsigned、int、char类型数据所占字节数