CImage类
CImage封装了DIB(设备无关位图)的功能,因而可以让我们能够处理每个位图像素。这里介绍GDI+和CImage的一般使用方法和技巧。
|
我们知道,Visual C++的CBitmap类和静态图片控件的功能是比较弱的,它只能显示出在资源中的图标、位图、光标以及图元文件的内容,而不像VB中的Image控件可 以显示出绝大多数的外部图像文件(BMP、GIF、JPEG等)。因此,想要在对话框或其他窗口中显示外部图像文件则只能借助于第三方提供的控件或代码。 现在,MFC和ATL共享的新类CImage为图像处理提供了许多相应的方法,这使得Visual C++在图像方面的缺憾一去不复返了。 CImage封装了DIB(设备无关位图)的功能,因而可以让我们能够处理每个位图像素。它具有下列最酷特性: 1、AlphaBlend支持像素级的颜色混合,从而实现透明和半透明的效果。 2、PlgBlt能使一个矩形区域的位图映射到一个平行四边形区域中,而且还可能使用位屏蔽操作。 3、TransparentBlt在目标区域中产生透明图像,SetTransparentColor用来设置某种颜色是透明色。 4、MaskBlt在目标区域中产生源位图与屏蔽位图合成的效果。 使用CImage的一般方法 使用CImage的一般方法是这样的过程: (1) 打开应用程序的stdafx.h文件添加CImage类的包含文件: #include <atlimage.h> (2) 定义一个CImage类对象,然后调用CImage::Load方法装载一个外部图像文件。 (3) 调用CImage::Draw方法绘制图像。Draw方法具有如下定义: 程序代码:
BOOL Draw( HDC hDestDC, int xDest, int yDest, 其中,hDestDC用来指定绘制的目标设备环境句柄,(xDest, yDest)和pointDest用来指定图像显示的位置,这个位置和源图像的左上角点相对应。nDestWidth和nDestHeight分别指定图 像要显示的高度和宽度,xSrc、ySrc、nSrcWidth和nSrcHeight用来指定要显示的源图像的某个部分所在的位置和大小。 rectDest和rectSrc分别用来指定目标设备环境上和源图像所要显示的某个部分的位置和大小。 需要说明的是,Draw方法综合了StretchBlt、TransparentBlt和AlphaBlend函数的功能。默认时,Draw的功能和 StretchBlt相同。但当图像含有透明色或Alpha通道时,它的功能又和TransparentBlt、AlphaBlend相同。因此,在一般 情况下,我们都应该尽量调用CImage::Draw方法来绘制图像。 例如,下面的示例Ex_Image是实现这样的功能:当选择"文件"ò"打开"菜单命令后,弹出一个文件打开对话框。当选定一个图像文件后,就会在窗口客户区中显示该图像文件内容。这个示例的具体步骤如下: (1) 创建一个默认的单文档程序项目Ex_Image。 (2) 打开stdafx.h文件中添加CImage类的包含文件atlimage.h。 (3) 在view类中添加成员变量CImage m_Image; CEx_ImageView类添加ID_FILE_OPEN的COMMAND事件映射程序,并添加下列代码: 程序代码:
void CImageProcessView::OnFileOpen()
{ // TODO: 在此添加命令处理程序代码 CString strFilter; CSimpleArray<GUID> aguidFileTypes; HRESULT hResult; // 获取CImage支持的图像文件的过滤字符串
hResult = m_Image.GetExporterFilterString(strFilter,aguidFileTypes, _T( "All Image Files") ); if (FAILED(hResult)) { MessageBox(_T("GetExporterFilter调用失败!")); return; } CFileDialog dlg(TRUE, NULL, NULL, OFN_FILEMUSTEXIST, strFilter); if(IDOK != dlg.DoModal()) return; m_Image.Destroy();
// 将外部图像文件装载到CImage对象中 hResult = m_Image.Load(dlg.GetFileName()); if (FAILED(hResult)) { MessageBox(_T("调用图像文件失败!")); return; } // 设置主窗口标题栏内容
CString str; str.LoadString(AFX_IDS_APP_TITLE); AfxGetMainWnd()->SetWindowText(str + _T(" - ") +dlg.GetFileName()); Invalidate(); // 强制调用OnDraw } (4) 定位到CEx_ImageView::OnDraw函数处,添加下列代码: 程序代码:
void CEx_ImageView::OnDraw(CDC* pDC) }
(5) 打开Ex_ImageView.h文件,添加一个公共的成员数据m_Image: 程序代码:
public: (6) 编译并运行。单击"打开"工具按钮,在弹出的对话框中指定一个图像文件后,单击"打开"按钮,其结果如图7.21所示。 ![]() 将图片用其它格式保存 CImage::Save方法能将一个图像文件按另一种格式来保存,它的原型如下: 程序代码:
HRESULT Save( LPCTSTR pszFileName, REFGUID guidFileType= GUID_NULL); 其中,pszFileName用来指定一个文件名,guidFileType用来指定要保存的图像文件格式,当为GUID_NULL时,其文件 格式由 文件的扩展名来决定,这也是该函数的默认值。它还可以是GUID_BMPFile(BMP文件格式)、GUID_PNGFile(PNG文件格式)、 GUID_JPEGFile(JPEG文件格式)和GUID_GIFFile(GIF文件格式)。 例如,下面的过程是在Ex_Image示例基础上进行的,我们在CEx_ImageView类添加ID_FILE_SAVE_AS的COMMAND事件映射程序,并添加下列代码: 程序代码:
void CEx_ImageView::OnFileSaveAs() { // TODO: 在此添加命令处理程序代码 if (m_Image.IsNull()) { MessageBox(_T("你还没有打开一个要保存的图像文件!")); return; } CString strFilter; strFilter ="位图文件|*.bmp|JPEG 图像文件|*.jpg| \ GIF 图像文件|*.gif|PNG 图像文件|*.png||";
CFileDialog dlg(FALSE,NULL,NULL,NULL,strFilter); if ( IDOK != dlg.DoModal()) return; // 如果用户没有指定文件扩展名,则为其添加一个 CString strFileName; CString strExtension; strFileName = dlg.m_ofn.lpstrFile;
if(dlg.m_ofn.nFileExtension == 0) { switch (dlg.m_ofn.nFilterIndex) { case 1: strExtension = "bmp"; break; case 2: strExtension = "jpg"; break; case 3: strExtension = "gif"; break; case 4: strExtension = "png"; break; default: break; } strFileName = strFileName + _T(".") + strExtension; } // 图像保存 HRESULT hResult = m_Image.Save(strFileName); if (FAILED(hResult)) { MessageBox(_T("保存图像文件失败!")); } } 柔化(平滑)和锐化处理
在图像处理中,我们通常用一些数学手段,对图像进行除去噪声、强调或抽取轮廓特征等图像空间的变换。所谓"图像空间的变换"是借助于一个称之为模板的局部像素域来完成的,不同的模板具有不同的图像效果。
1. 柔化(平滑) 图像的柔化是除去图像中点状噪声的一个有效方法。所谓柔化,是指使图像上任何一个像素与其相邻像素的颜色值的大小不会出现陡突的一种处理方法。设在一个3 x 3的模板中其系数为: ![]() 中间有底纹的表示中心元素,即用那个元素作为处理后的元素。很明显,上述模板(称之为Box模板)是将图像上每个像素用它近旁(包括它本身)的9个像素的平均值取代。这样处理的结果在除噪的同时,也降低图像的对比度,使图像的轮廓模糊。为了避免这一缺陷,我们对各点引入加权系数(不都乘1了),将原来的模板改为: ![]() 新的模板可一方面除去点状噪声,同时能较好地保留原图像的对比度,因此该模板得到了广泛的应用。由于这个模板是通过二维高斯(Gauss)函数得到的,故称为高斯模板。 2. 锐化 锐化和柔化恰恰相反,它通过增强高频分量减少图像中的模糊,因此又称为高通滤波。锐化处理在增强图像边缘效果的同时增加了图像的噪声。常用的锐化模板是拉普拉斯模板: ![]() 用此模板处理后的图像,轮廓线条将明显得到增强。轮廓线以外的部分将变得较暗,而轮廓线部分将变得比较明亮。 使用程序对模板进行运算时,要考虑到溢出点的处理。所谓溢出点,指的是大于255或小于0的点。处理时,可令大于255的点取255,而小于0的点取其正值。 3. 实现代码 实现柔化和锐化时,我们先调用CImage::GetPixel来依次读取相应的像素,然后用柔化和锐化模板进行处理,最后调用CImage::SetPixel函数将处理后的像素写回到CImage对象中。具体的代码如下: 程序代码:
void FilterImage(CImage* image, int nType) int i,j;
int nWidth = image->GetWidth(); int nHeight = image->GetHeight(); for (i = 1; i < nWidth-1; i++){ for (j = 1; j < nHeight-1; j++){ int rr = 0, gg = 0, bb = 0; int index = 0; for (int col = -1; col <= 1; col++){ for (int row = -1; row <= 1; row++){ COLORREF clr = image->GetPixel( i+row, j+col); rr += GetRValue(clr) * opTemp[index]; gg += GetGValue(clr) * opTemp[index]; bb += GetBValue(clr) * opTemp[index]; index++; } } rr = (int)(rr*aver); gg = (int)(gg*aver); bb = (int)(bb*aver); // 处理溢出点 if ( rr > 255 ) rr = 255; else if ( rr < 0 ) rr = -rr; if ( gg > 255 ) gg = 255; else if ( gg < 0 ) gg = -gg; if ( bb > 255 ) bb = 255; else if ( bb < 0 ) bb = -bb; // 错位重写以避免前一个像素被新的像素覆盖
image->SetPixel( i-1, j-1, RGB(rr,gg,bb)); } } Invalidate(); // 强制调用OnDraw }
图7.22是使用上述代码将某个图像处理后的结果。 ![]() 变成黑白图片(变为灰度图) 由于许多图像文件使用颜色表来发挥显示设备的色彩显示能力,因而将一张彩色图片变成黑色图片时需要调用CImage::IsIndexed来判断是否使用颜色表,若是则修改颜色表,否则直接将像素进行颜色设置。例如下面的代码: 程序代码:
void CEx_ImageView::MakeBlackAndwhite(CImage* image) { if (image->IsNull()) return; if (!image->IsIndexed()) {
// 直接修改像素颜色 COLORREF pixel; int maxY = image->GetHeight(), maxX = image->GetWidth(); byte r,g,b,avg; for (int x=0; x<maxX; x++) { for (int y=0; y<maxY; y++) { pixel = image->GetPixel(x,y); r = GetRValue(pixel); g = GetGValue(pixel); b = GetBValue(pixel); avg = (int)((r + g + b)/3); image->SetPixelRGB(x,y,avg,avg,avg); } } } else { // 获取并修改颜色表 int MaxColors = image->GetMaxColorTableEntries(); RGBQUAD* ColorTable; ColorTable = new RGBQUAD[MaxColors]; image->GetColorTable(0,MaxColors,ColorTable); for (int i=0; i<MaxColors; i++) { int avg = (ColorTable[i].rgbBlue + ColorTable[i].rgbGreen + ColorTable[i].rgbRed)/3; ColorTable[i].rgbBlue = avg; ColorTable[i].rgbGreen = avg; ColorTable[i].rgbRed = avg; } image->SetColorTable(0,MaxColors,ColorTable); delete(ColorTable); } Invalidate();// 强制调用OnDraw } 至此,我们介绍了GDI+和CImage的一般使用方法和技巧。当然,它们本身还有许多更深入的方法,由于篇幅所限,这里不再一一讨论。 http://www.codeproject.com/KB/graphics/cximage.aspx (cjmxp) |
CImage类的更多相关文章
- 强大的CImage类
这下有了CImage类,处理其他类型的图片不再寻找第三方类库了.加载到对话框背景的代码如下: //从资源里载入背景JPEG图片 HRSRC hRsrc=::FindResource(AfxGetRe ...
- 用CImage类来显示PNG、JPG等图片
系统环境:Windows 7软件环境:Visual Studio 2008 SP1本次目的:实现VC单文档.对话框程序显示图片效果 CImage 是VC.NET中定义的一种MFC/ATL共享类,也是A ...
- CImage类的介绍与使用
CImage类的介绍与使用 程序代码下载处:http://download.csdn.net/source/2098910 下载处:http://hi.baidu.com/wangleitongxin ...
- c++ 中CImage类Load函数,路径中含有空格应对策略!
最近,在写一些东西的时候,需要用到CImage类将JPG各式的图片转换成BMP图片,传入的是图片的绝对地址:如C:\Users\Administrator\Documents\Visual Studi ...
- GDI 总结三: CImage类使用
前言 CImage类是基于GDI+的.可是这里为什么要讲归于GDI? 主要是基于这种考虑: 在GDI+环境中,我们能够直接使用GDI+ ,没多少必要再使用CImage类 可是,假设再 ...
- GDI+ 两个汇总 : 为什么CImage类别是根据GDI+的?
在很多资料上都说CImage类是基于GDI+的,可是为什么是基于GDI+的呢? 由于使用这个类时,并没有增加#include <gdiplus.h> .也没有在程序開始和结束时分别写GDI ...
- 供CImage类显示的半透明PNG文件处理方法
原文链接: http://blog.sina.com.cn/s/blog_4070692f010003gy.html 前补:没想到这个帖子好像挺多人看哪……看来大家都被这个png郁闷的够呛.显示p ...
- CImage类提供了GetBits()函数原理及实现
CImage类提供了GetBits()函数来读取数据区,GetBits()函数返回的是图片最后一行第一个像素的地址,网上有人说返回指针的起始位置是不同的,有些图片返回的是左上角像素的地址,有些是左下角 ...
- c++ MFC图像处理CImage类常用操作代码
原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/9598974.html MFC图像处理CImage类常用操作 CImage类头文件为#inclu ...
随机推荐
- About Us - Tech in Asia - Tech in Asia
About Us - Tech in Asia - Tech in Asia About us Asia is big. Its place in the world, even bigger. Te ...
- line-height具体解释
章:浏览器与Hack].7.3.5 应用:单行文字在垂直方向居中在网页设计中,往往为了突出标题而加入背景图案.如图7-31所看到的. watermark/2/text/aHR0cDovL2Jsb2cu ...
- 关于DataGridViewComboBoxCell修改后提交数据源
最近在项目遇到一个功能实现.是在DataGridView中DataGridViewComboboxColumn列绑定数据源, DisplayMember为数据表的Name列,ValueMember是数 ...
- c++构造析构顺序
class A { public: A(){ cout << "constrcut A" << endl; }; ~A(){ cout << & ...
- java--线程状态
1.新建状态 Thread t1 = new Thread(); 创建之后,就已经有了相应的内存和其他资源,但是还是处于不可运行状态. 2.就绪状态 当一个线程使用.start()启动之后就处于就绪状 ...
- HDOJ 2680 Dijkstra
题目大意: 给你一个有向图,一个起点集合,一个终点,求最短路.... 解题思路: 1.自己多加一个超级源点,把起点集合连接到超级源点上,然后将起点与超级源点的集合的路径长度设为0,这样就称为一个n+1 ...
- Qt学习之路(60): 创建shared library
前段时间说了Qt一些类库的使用,今天来换一下口味,来看一下程序设计的问题.今天来说的是关于共享库 shared library. 如果你打开一些 Windows 应用程序的目录,你会发现有很多程序的 ...
- RESTful最佳实践之基于 jersey 的增删改查
jersey-rest-demo 增删改查 项目地址:https://github.com/CoderDream/jersey-rest-demo 源代码:http://download.csdn.n ...
- char s[]字串和char *s字串有什麼区别?
C語言有兩種字串宣告方式char s[]和char *s,兩者有什麼差異呢? Introduction char s[] = "Hello World"; (只是用字符串常量初始化 ...
- C#由变量捕获引起对闭包
C#由变量捕获引起对闭包的思考 前言 偶尔翻翻书籍看看原理性的东西确实有点枯燥,之前有看到园中有位园友说到3-6年工作经验的人应该了解的.NET知识,其中就有一点是关于C#中的闭包,其实早之前在看 ...




