VC++和VC++.NET中与图像处理有关的几个概念、结构和类

最近一直在看VC++有关图像处理方面的书,终于把以前一直混淆的几个概念、结构和类弄清楚了,特整理如下。如有错误,请大家批评指正,不胜感激。下一步想好好学习学习OpenCV,希望也能总结点东西。

一、DDB与DIB位图

  一个Windows的位图实际上是一些和显示像素相对应的位阵列,它有两种类型:一种称之为GDI(Graphic Device Interface)位图,另一种是DIB位图(Device-Independent Bitmap)。

  GDI位图包含了一种和Windows的GDI模块有关的Windows数据结构,该数据结构是与设备有关的,故此位图又称为DDB位图(Device-Dependent Bitmap)。当用户的程序取得位图数据信息时,其位图显示方式视显示卡而定。由于GDI位图的这种设备依赖性,当位图通过网络传送到另一台PC,很可能就会出现问题。

  DIB比GDI位图有很多编程优势,例如它自带颜色信息,从而使调色板管理更加容易。且任何运行Windows的机器都可以处理DIB,并通常以后缀为.BMP的文件形式被保存在磁盘中或作为资源存在于程序的EXE或DLL文件中。

二、CBitmap类、BITMAP结构

  CBitmap类继承自CGdiObject,是封装了图形设备接口(GDI)的位图,提供成员函数来操纵位图。要使用一个CBitmap对象,构造该对象,用初始化成员函数之一把一个位图句柄连接到该对象,然后调用该对象的成员函数。

  CBitmap类主要用于处理DDB位图,封装了与DDB位图操作函数相关的数据结构和操作函数。结构体BITMAP定义了DDB位图的类型、宽度、高度、颜色和像素值,其定义如下:

typedef struct _tagBITMAP       
{
LONG          bmType ;                      // set to 0       
LONG          bmWidth ;                     // width in pixels       
LONG          bmHeight ;                   // height in pixels       
LONG          bmWidthBytes ;                // width of row in bytes       
WORD         bmPlanes ;                    // number of color planes       
WORD         bmBitsPixel ;                 // number of bits per pixel       
LPVOID       bmBits ;                             // pointer to pixel bits       
}       
BITMAP, * PBITMAP ;

  而CBitmap的LoadBitmap、CreateCompatibleBitmap、SetBitmapBits、GetBitmap等成员函数则定义了对DDB位图的装载、创建、设定位值和属性查询等操作。

  创建或装入内存的位图必须用CDC::SelectObject函数来将其选入设备上下文中,然后用CDC的BitBlt或StretchBlt函数显示出来,这两个函数的原型如下:

BOOL BitBlt(int x, int y, int nWith, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop);

  该函数把源设备上下文中的位图复制到本身的设备上下文中,两个设备下下文可以是内存设备下下文,也可以是同一个设备上下文。

三、Image类和Bitmap类

  在VC++.NET中,GDI+的Image类封装了对BMP、GIF、JPEG、PNG、TIFF、WMF(Windows元文件)和EMF(增强WMF)图像文件的调入、显示、格式转换以及简单处理(如缩放、旋转、拉伸等)的功能。而Bitmap类(注意不是结构BITMAP)是从Image类继承的一个图像(另一个从Image继承的类是Metafile类),它封装了Windows位图操作的常用功能。例如,Bitmap::SetPixel和Bitmap::GetPixel分别用来对位图进行读写像素操作,从而可以为图像的柔化和锐化处理提供一种可能。这些功能和MFC的新类CImage功能基本一样,如果仅用于图像的读取与显示,用Bitmap类或Image类是不错的选择,如果是做图像处理,则CImage可能更符合MFC程序员的编程习惯。

四、CImage类

  CImage类是VC++.NET中MFC和ATL共享的新类,它能从外部磁盘中调入一个JPEG、GIF、BMP和PNG格式的图像文件加以显示,而且这些文件格式可以相互转换。

  CImage既能处理DIB位图也能处理非DIB位图,但你可以仅用DIB位图来Create或CImage::Load。你也可以使用Attach把一个非DIB位图连接给CImage对象,但你不能使用下列方法,这些方法仅支持DIB位图:GetBits、GetColorTable、GetMaxColorTable、Entries、GetPitch、GetPixelAddress、IsIndexed、SetColorTable。要确定一个连接的位图是否是一个DIB位图,调用IsDibSection。

  由于CImage在不同的Windows操作系统中其某些性能是不一样的,因此在使用时要特别注意。例如,CImage::PlgBlt和CImage::MaskBlt只能在 Windows NT 4.0 或更高版本中使用,但不能运行在Windows 95/98 应用程序中。CImage::AlphaBlend和CImage::TransparentBlt也只能在 Windows 2000/98或其更高版本中使用。即使在Windows 2000运行程序还必须将stdafx.h文件中的WINVER和_WIN32_WINNT的预定义修改成0x0500才能正常使用。 CImage可以在MFC或ATL中使用。当使用CImage创建一个项目时,必须包含atlimage.h文件。

  CImage封装了DIB(设备无关位图)的功能,因而可以让我们能够处理每个位图像素。

  CImage提供了HBITMAP操作符,因此HBITMAP为参数的地方,都可以用CImage来替代。

五、传统的VC++中的图像处理方法与VC++.NET中的图像处理方法

  由于DIB图不依赖于具体设备,因此可以用来永久性地保存图象。DIB一般是以*.BMP文件的形式保存在磁盘中的,有时也会保存在*.DIB文件中。运行在不同输出设备下的应用程序可以通过DIB来交换图象。因而在数字图象处理中会经常用到DIB位图。DIB还可以用一种RLE算法来压缩图像数据,但一般来说DIB是不压缩的。

  在VC++.net之前MFC未提供现成的类来封装DIB,这给MFC用户带来很多不便。因为用户要想使用DIB,首先应该了解DIB的结构。

  在内存中,一个完整的DIB由两部分组成:一个BITMAPINFO结构和一个存储像素阵列的数组。BITMAPINFO描述了位图的大小,颜色模式和调色板等各种属性,其定义为 typedef struct tagBITMAPINFO {
    BITMAPINFOHEADER bmiHeader;
    RGBQUAD bmiColors[1]; //颜色表
} BITMAPINFO;

RGBQUAD结构用来描述颜色,其定义为
typedef struct tagRGBQUAD {
BYTE     rgbBlue; //蓝色的强度
BYTE     rgbGreen; //绿色的强度
BYTE     rgbRed; //红色的强度
BYTE     rgbReserved; //保留字节,为0
} RGBQUAD;

注意,RGBQUAD结构中的颜色顺序是BGR,而不是平常的RGB。

BITMAPINFOHEADER结构包含了DIB的各种信息,其定义为
typedef struct tagBITMAPINFOHEADER{
DWORD     biSize; //该结构的大小
LONG     biWidth; //位图的宽度(以像素为单位)
LONG     biHeight; //位图的高度(以像素为单位)
WORD     biPlanes; //必须为1
WORD     biBitCount //每个像素的位数(1、4、8、16、24或32)
DWORD     biCompression; //压缩方式,一般为0或BI_RGB (未压缩)
DWORD     biSizeImage; //以字节为单位的图象大小(仅用于压缩位图)
LONG     biXPelsPerMeter; //以目标设备每米的像素数来说明位图的水平分辨率
LONG     biYPelsPerMeter; //以目标设备每米的像素数来说明位图的垂直分辨率
DWORD     biClrUsed; /*颜色表的颜色数,若为0则位图使用由biBitCount指定的最大颜色数*/
DWORD     biClrImportant; //重要颜色的数目,若该值为0则所有颜色都重要
} BITMAPINFOHEADER;

  与DDB不同,DIB的字节数组是从图象的最下面一行开始的逐行向上存储的,也即等于把图象倒过来然后在逐行扫描。另外,字节数组中每个扫描行的字节数必需是4的倍数,如果不足要用0补齐。

DIB可以存储在*.BMP或*.DIB文件中。DIB文件是以BITMAPFILEHEADER结构开头的,该结构的定义为
typedef struct tagBITMAPFILEHEADER {
WORD     bfType; //文件类型,必须为“BM”
DWORD     bfSize; //文件的大小
WORD     bfReserved1; //为0
WORD     bfReserved2; //为0
DWORD     bfOffBits; //存储的像素阵列相对于文件头的偏移量
} BITMAPFILEHEADER;

  紧随该结构的是一个BITMAPINFOHEADER结构,然后是RGBQUAD结构组成的颜色表(如果有的话),文件最后存储的是DIB的像素阵列。

  DIB的颜色信息储存在自己的颜色表中,程序一般要根据颜色表为DIB创建逻辑调色板。在输出一幅DIB之前,程序应该将其逻辑调色板选入到相关的设备上下文中并实现到系统调色板中,然后再调用相关的GDI函数(如::SetDIBitsToDevice或::StretchDIBits)输出DIB。在输出过程中,GDI函数会把DIB转换成DDB,这项工作主要包括以下两步:将DIB的颜色格式转换成与输出设备相同的颜色格式;将DIB像素的逻辑颜色索引转换成系统调色板索引。 

  看到这么多结构,你是不是已经眼花缭乱了,然而更不幸的还在后面。以上说的DIB是Windows中的DIB,还有一种DIB是OS/2 DIB,它和Windows DIB的主要区别是位图信息结构(信息头和颜色表结构)。它们的图像数据的存储方式是完全一样的。在OS/2 DIB中,与WIndows DIB的BITMAPFILEHEADER、BITMAPINFOHEADER、RGBQUAD相对应的结构分别是BITMAPCOREHEADER、BITMAPCOREINFO、和RGBTRIPLE。它们的定义分别如下:

typedef struct tagBITMAPCOREHEADER // bmch       
{       
DWORD         bcSize ;              // size of the structure = 12       
WORD          bcWidth ;             // width of image in pixels       
WORD          bcHeight ;           // height of image in pixels       
WORD          bcPlanes ;            // = 1       
WORD          bcBitCount ;          // bits per pixel (1, 4, 8, or 24)       
}       
BITMAPCOREHEADER, * PBITMAPCOREHEADER ;

typedef struct tagBITMAPCOREINFO // bmci
{       
BITMAPCOREHEADER      bmciHeader ;                  // core-header structure       
RGBTRIPLE             bmciColors[1] ;               // color table array       
}       
BITMAPCOREINFO, * PBITMAPCOREINFO ;

typedef struct tagRGBTRIPLE // rgbt       
{       
BYTE     rgbtBlue ;       // blue level       
BYTE     rgbtGreen ;      // green level       
BYTE     rgbtRed ;        // red level       
}       
RGBTRIPLE;

  因此再操作之前你应该先根据BITMAPINFOHEADER的大小来判断是哪一种DIB,然后再进行操作。

  由于MFC未提供一个封装好的易用的DIB类,用户在使用DIB时将面临繁重的Windows API编程任务。不信你看看Microsoft提供的MFC的DibLook例程提就知道了。所以传统的图像处理方法一般都会把这些Win32 SDK中的操作DIB位图的APIs做一个封装,作为一个通用的类来使用,以减少后续算法编写中的编程负担。

  VC++.NET提供了多种常用图像文件格式(如BMP、TIF、GIF、JPEG与PNG等)的输入/输出模块,ATL中的CImage类极大地简化了图像数据的操作,因此VC++.NET中的图像处理应以CImage为基础。
  现在市面上有一些冠名教用VC++.NET做图像处理的书,但是编程方法还是老的一套,没有跳出设备相关位图(DDB)与设备无关位图(DIB)概念的条框,编程方法比较复杂、繁琐、低效。用VC++.NET环境做图像处理,应该以CImage类为基础,完全跳出DDB、DIB概念的条框,才能使得处理方法返朴归真,大为简化。

转载于:https://www.cnblogs.com/meiling/archive/2010/05/13/1734836.html

VC++和VC++.NET中与图像处理有关的几个概念、结构和类相关推荐

  1. 图像处理中的傅里叶变换和频率域滤波概念

    写在前面的话 作者是一名在读的硕士研究僧,方向是机器视觉.由于视觉是一门相对复杂的学科,作者在课堂上学到的东西只是非常浅显的内容,我们老师说是,领我们进了个门.现在打算利用图书馆和网络上的资源进行自学 ...

  2. VC++向txt文件中写入字符串

    有的时候,不管怎样我们从VC++向txt文件中添加的数据都是一堆乱码,不知道怎么回事. 例子: int main() { FILE *stream; stream=fopen("text1. ...

  3. VC实现在ListBox中选择背景位图

    VC实现在ListBox中选择背景位图 本文介绍如何在ListBox中添加更换背景位图,并提供源代码供参考.本文源代码运行效果图如下:   一.基本原理: 构造一个LISTBOX的子类CMYLISTB ...

  4. 让你提前认识软件开发(51):VC++集成开发环境中Linux下Pclint工程的配置方法及常见错误修改

    第3部分 软件研发工作总结 VC++集成开发环境中Linux下Pclint工程的配置方法及常见错误修改 [文章摘要] Pclint是一种C/C++软件代码静态分析工具.它是一种更加严格的编译器,能够发 ...

  5. VC++ 实现VC程序启动时最小化到任务栏(完美解决闪烁问题)

    VC++ 实现VC程序启动时最小化到任务栏(完美解决闪烁问题) 参考文章: (1)VC++ 实现VC程序启动时最小化到任务栏(完美解决闪烁问题) (2)https://www.cnblogs.com/ ...

  6. OpenCV 中的图像处理 004_平滑图像

    本文主要内容来自于 OpenCV-Python 教程 的 OpenCV 中的图像处理 部分,这部分的全部主要内容如下: 改变色彩空间 学习在不同色彩空间之间改变图像.另外学习跟踪视频中的彩色对象. 图 ...

  7. 使用opencv和python进行智能图像处理_使用OpenCV在Python中进行图像处理

    编辑推荐: 本文将先讨论一些图像处理,然后再继续介绍可以方便使用图像处理的不同应用程序/场景,希望对您的学习有所帮助. 本文来自于tecdat ,由火龙果软件Alice编辑.推荐. 介绍 在本教程中, ...

  8. Python中的图像处理(第六章)Python图像量化及采样处理(2)

    Python中的图像处理(第六章)Python图像量化及采样处理(2) 前言 一. Python准备 二. Python仿真 三. 小结 前言 随着人工智能研究的不断兴起,Python的应用也在不断上 ...

  9. 第四章:OpenCV中的图像处理

    第四章:OpenCV中的图像处理 本章节你将学习图像的改变色彩空间.提取对象.图像的几何变换.图像的阈值.平滑图像等OpenCV图像处理的基本内容. 更多内容请关注我的GitHub库:TonyStar ...

最新文章

  1. 柚子的collection
  2. 如何快速直接从Web of Science下载文献,保存到Endnote
  3. php怎么生成卡券签名,小程序卡券签名错误的解决方案
  4. 三、CSS重要的盒子模型知识总结(中篇)
  5. php 管理 mysql 数据库 代码_PHP5对Mysql5的任意数据库表的管理代码示例(三)
  6. 一个用js写的接口http调试程序
  7. python如何导入类里_Python导入模块中的所有类(98)
  8. GIS案例练习-----------第四天
  9. 在iOS开发的Quartz2D使用中实现图片剪切和截屏功能
  10. JSONArray.fromObject(list) list转json报错
  11. JAVAweb开发中Ajax教程
  12. 设计师工作经验_得到我作为设计师的第一份工作
  13. 切西瓜(空间划分问题)
  14. PostgreSQL查询 动态输入参数
  15. Linux 系统维护命令小结
  16. Java 行业的相关就业前景分析
  17. 宁撞金钟一下,不打破鼓三千,IT人要有志气,要进就进大的好的公司
  18. 键指如飞--Mac电脑快捷键学习
  19. 组态服务器协议,西门子1200PLC组态网络时间协议同步
  20. 使用搜狗输入法和搜狗浏览器的感受

热门文章

  1. android 关闭蓝牙打电话功能,Android蓝牙开发【八】hfp接听、挂断电话
  2. windows 文件对话框
  3. C++容器遍历时删除元素
  4. Mysql的undo、redo、bin log分析
  5. stringwriter_Java StringWriter toString()方法与示例
  6. 第三章 染色动力学理论单元测试
  7. 计量经济学建模_浅谈统计学模型(兼计量经济学模型)
  8. ffmpeg 解码视频(h264、mpeg2)输出yuv420p文件
  9. linux 常用命令05 常用的压缩与解压缩文件
  10. linux之多线程(1)