使用CImage进行图像处理

article/2025/10/16 5:40:22
MFC和ATL共享的新类CImage为图像处理提供了许多相应的处理方法

CImage类

我们知道,Visual C++的CBitmap类和静态图片控件的功能是比较弱的,它只能显示出在资源中的图标、位图、光标以及图元文件的内容,而不像VB中的Image控件可 以显示出绝大多数的外部图像文件(BMP、GIF、JPEG等)。因此,想要在对话框或其他窗口中显示外部图像文件则只能借助于第三方提供的控件或代码。 现在,MFC和ATL共享的新类CImage为图像处理提供了许多相应的方法,这使得Visual C++在图像方面的缺憾一去不复返了。
CImage类概述
CImage是MFC和ATL共享的新类,它能从外部磁盘中调入一个JPEG、GIF、BMP和PNG格式的图像文件加以显示,而且这些文件格式可以 相互转换。由于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封装了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,
int nDestWidth, int nDestHeight, int xSrc, int ySrc,
int nSrcWidth, int nSrcHeight );
BOOL Draw( HDC hDestDC, const RECT& rectDest, const RECT& rectSrc );
BOOL Draw( HDC hDestDC, int xDest, int yDest );
BOOL Draw( HDC hDestDC, const POINT& pointDest );
BOOL Draw( HDC hDestDC, int xDest, int yDest,
int nDestWidth, int nDestHeight );
BOOL Draw( HDC hDestDC, const RECT& rectDest );

  其中,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.GetPathName());//许多教程上都写错了 都写的是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)
{
CImageProcessDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!m_Image.IsNull()) {
m_Image.Draw(pDC->m_hDC,0,0);}
}

  (5) 打开Ex_ImageView.h文件,添加一个公共的成员数据m_Image:

程序代码:

public:
CImage m_Image;

  (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)
{
if (image->IsNull())
return;
int smoothGauss[9] = {1,2,1,2,4,2,1,2,1}; // 高斯模板
int sharpLaplacian[9] = {-1,-1,-1,-1,9,-1,-1,-1,-1}; // 拉普拉斯模板
int opTemp[9];
float aver; // 系数
if ( nType > 1) nType = 0;
switch( nType ){
case 0: // 高斯模板 平滑
aver = (float)(1.0/16.0);
memcpy( opTemp, smoothGauss, 9*sizeof(int));
break;
case 1: // 拉普拉斯模板 锐化
aver = 1.0;
memcpy( opTemp, sharpLaplacian, 9*sizeof(int));
break;
}
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.ylzx8.cn/duomeiti/image/1197349.html

 


http://chatgpt.dhexx.cn/article/nETalyci.shtml

相关文章

用CImage类来显示PNG、JPG等图片

系统环境&#xff1a;Windows 7 软件环境&#xff1a;Visual Studio 2008 SP1 本次目的&#xff1a;实现VC单文档、对话框程序显示图片效果 CImage 是VC.NET中定义的一种MFC/ATL共享类&#xff0c;也是ATL的一种工具类&#xff0c;它提供增强型的&#xff08;DDB和DIB&#xff…

CImage类(外部图像文件(BMP、GIF、JPEG等)

CImage类 我们知道&#xff0c;Visual C的CBitmap类和静态图片控件的功能是比较弱的&#xff0c;它只能显示出在资源中的图标、位图、光标以及图元文件的内容&#xff0c;而不像VB中的Image控件可 以显示出绝大多数的外部图像文件(BMP、GIF、JPEG等)。因此&#xff0c;想要在对…

CImage的一般使用方法和技巧

Visual C的CBitmap类的功能是比较弱的,它只能显示出在资源中的图标、位图、光标以及图元文件的内容&#xff0c;而不像VB中的Image控件可以显示出绝大多数的外部图像文件(BMP、GIF、JPEG等)。如果想要在对话框或其他窗口中显示外部图像文件则只能借助于第三方提供的控件或代码,…

图像处理(C++ CImage class)学习笔记

基础篇 A. 图像三原色及灰度值 A1. 彩色图像的三原色 图像三原色 — R&#xff1a;红色red — G&#xff1a;绿色green — B&#xff1a;蓝色blue三原色的取值范围&#xff1a;0&#xff08;无&#xff09;~255&#xff08;满&#xff09; — 红色&#xff1a;R255 G0 B0 —…

Cimage

本系列文章由zhmxy555编写&#xff0c;转载请注明出处。 http://blog.csdn.net/zhmxy555/article/details/7422922 作者&#xff1a;毛星云 邮箱&#xff1a; happylifemxyqq.com 欢迎邮件交流编程心得 我们知道&#xff0c;Visual C中的CBitmap类的功能简直太弱小了&am…

【无标题】c++ MFC图像处理CImage类常用操作代码

原文作者&#xff1a;aircraft 原文地址&#xff1a;https://www.cnblogs.com/DOMLX/p/9598974.html 我看了一下发现关于c下的CImage图像处理类 的图像处理相关的介绍真的是比较少&#xff0c;因为我要做大二的数据结构的课程设计&#xff0c;要用纯c语言去实现&#xff08;老…

C++,CImage类的建立方法(可以打开图像和保存)

建立CImage类&#xff08;以vs2015为例&#xff09; 一&#xff0c; 新建一个MFC项目&#xff1a;名字为 image3 二&#xff0c; 单个文档&#xff0c;MFC标准&#xff0c;然后完成。 三&#xff0c;打开应用程序的 stdafx.h 文件添加 CImage 类的包含文件&#xff1a; #incl…

VB.net 进程通信中FindWindow、FindWindowEX、SendMessage函数的理解

目录 一、代码背景 二、主要工具 三、函数解析 1、FindWindow&#xff1a; 2、 FindWindowEx&#xff1a; 3、SendMessage&#xff1a; 四、具体代码示例&#xff1a; 1、第一部分功能&#xff1a; A、接收端&#xff1a; B、发送端 C、运行测试 2.第二部分功能&…

C#-FindWindow的用法

C# FindWindow用法 函数功能&#xff1a;该函数获得一个顶层窗口的句柄&#xff0c;该窗口的类名和窗口名与给定的字符串相匹配。 这个函数不查找子窗口。在查找时不区分大小写。 函数型&#xff1a;HWND FindWindow&#xff08;LPCTSTR IpClassName&#xff0c;LPCTSTR IpWi…

vb.net中FindWindow方法的使用

问题描述 遇到的问题是&#xff0c;需要判断MsgBox是否已经弹出&#xff0c;如果已经弹出就不要重复弹出了。 解决方案&#xff1a; 利用FindWindow方法判断MsgBox是否已经出现 MsgBox的本质就是一个窗体&#xff0c;有标题和内容&#xff0c;可以使用FindWindow这个API函数去…

C# FindWindow的用法

找了一大堆C#怎么用FindWindowAPI函数不多说,请看步骤. 创建好WinForm窗口,如果不会创建的话,在图下面有. 项目名字和位置这个自己设置,下面那个框架,目前现在出5.0了,为了演示实例,就4.6吧. 创建完成后,把自己窗口设置一下

FindWindow ,GetWindowThreadProcessId , OpenProcess 和ReadProcessMemory

文章目录 FindWindow函数功能&#xff1a;函数声明&#xff1a;第一个参数第二个参数返回值注意&#xff1a;GetWindowThreadProcessId函数功能函数声明第一个参数&#xff1a;第二个参数&#xff1a;返回值代码实现OpenProcess函数功能&#xff1a;函数声明&#xff1a;第一个…

【CV系列】主动轮廓模型snake及其应用

DATE: 2019.5.30 前言 主动轮廓模型(Active Contour Model)&#xff0c;又被称为Snake&#xff0c;是由Andrew Blake教授提出的一种目标轮廓描述方法&#xff0c;主要应用于基于形状的目标分割。该模型的优越之处在于它对于范围广泛的一系列视觉问题给出了统一的解决方法,在最…

图像分割之Snake主动轮廓模型(Matlab代码)

示例演示 如果在中文搜索的话&#xff0c;一般会找到《数字图像处理-图像分割&#xff1a;Snake主动轮廓模型 Matlab代码及运行结果》。里面有句代码&#xff0c;千万别用&#xff0c;否则出不来效果。&#xff08;别问我怎么知道的&#xff09; % 转化为双精度型 %I im2doub…

Snake活动轮廓模型Matlab实现

1. Snake模型 人为地在图像感兴趣的区域&#xff08;ROI&#xff09;上给出初始轮廓曲线&#xff0c;最小化一个能量函数&#xff0c;使轮廓曲线在图像中运动&#xff08;变形&#xff09;&#xff0c;最终逼近该区域的边界。 设v(s)[x(s),y(s)]为活动轮廓线&#xff0c;s∈[0,…

snake主动轮廓模型

模型&#xff1a;一条可变形的参数曲线及相应的能量函数&#xff0c;以最小化能量函数为目标&#xff0c;控制参数曲线变形&#xff0c;具有最小能量的闭合曲线即是目标轮廓。 snake模型调和了上层知识和底层图像特征矛盾。 上层知识指物体形状。表示内部力。 底层图像特征是局…

Snake活动轮廓模型

1. Snake模型 人为地在图像感兴趣的区域&#xff08;ROI&#xff09;上给出初始轮廓曲线&#xff0c;最小化一个能量函数&#xff0c;使轮廓曲线在图像中运动&#xff08;变形&#xff09;&#xff0c;最终逼近该区域的边界。 设v(s)[x(s),y(s)]为活动轮廓线&#xff0c;s∈[0,…

基于边缘的主动轮廓模型——从零到一用python实现snake

从零到一实现snake算法 1、Snake算法原理2、基于曲线演化的实现方法2.1演化方程推导2.2离散化过程2.3 代码实现 3、基于水平集的实现方法4、讨论与分析源码地址[snake](https://github.com/woshimami/snake) 1、Snake算法原理 Kass等人1最早于1988年提出了主动轮廓模型&#x…

主动轮廓模型snake

原理概述 snake模型将图像分割问题转换为求解能量泛函最小值的问题。主要思路是构造能量函数进行迭代后&#xff0c;轮廓曲线由初始位置逐渐向使能量函数最小&#xff08;局部极小&#xff09;的图像边缘逼近&#xff0c;最终分割出目标。 曲线理论 假设一条光滑封闭曲线 C …

腾讯电脑管家,vs安装文件报成木马,还能信吗?

今天在公司安装vs2013&#xff0c;安装过程中腾讯公司的产品“电脑管家”提示有新版本&#xff0c;没有犹豫的点了升级&#xff0c;完成后直接在管家主界面上点了“全面体检”按钮&#xff0c;这一点不要紧&#xff0c;报告有一个木马&#xff0c;看紧看一下“详情”&#xff0…