VS环境下基于MFC读取显示图像更改背景图像.docx
《VS环境下基于MFC读取显示图像更改背景图像.docx》由会员分享,可在线阅读,更多相关《VS环境下基于MFC读取显示图像更改背景图像.docx(15页珍藏版)》请在冰豆网上搜索。
VS环境下基于MFC读取显示图像更改背景图像
一、创建MFC
首先创建一个MFC对话框应用程序(Dialog-basedApplication)如下:
在VS2005和2008里,我们可以用一个Solution来组合几个Project(每个Project基本上只包含一个Program),当我们要构建一个多Program的应用时(例如一个客户端程序加一个服务器应用程序),利用Solution可以将这些Projects组合起来、并且共享文件和函数库。
通常需要为Solution创建一个主路径,其中包含了所有Projects的路径。
不过在这篇文章里,我们只构建一个简单的Project,所以在创建MFC的NewProject对话框里,不用勾选“Createdirectoryforsolution”这个选项。
点击OK--Next进入下一步,在这里我们创建一个Dialog-basedApplication,大部分选项按默认设置就行,不过最下面的“UseUnicodelibraries”最好去掉。
如果勾选了这个选项,程序代码就会使用16bit的Unicode字符集来编码,但是很多函数虽然使用char*(ASCIIstings)类型字符,而将字符串从Unicode转换到ASCII是非常麻烦的。
使用Unicode在编译时可能会遇到下列错误:
cannotconvertparameter1from'CString'to'constchar*'
cannotconvertfrom'constchar[11]'to'LPCWSTR'这意味着在Unicode和Multi-byte字符串的转换中出现了问题。
在上一篇学习笔记中,就提到“成员函数LoadBMP其输入参数类型应为constchar*”,那应该只是一个治标的方法,这里的去掉“UseUnicodelibraries”选项,才是治本之道。
往后的几步设置,可以根据自己的需要来操作,我的设置如下:
二、编写代码
在ResourceView面板->mymfc(工程名称)->mymfc.rc->Dialog双击IDD_MYMFC_DIALOG,可以看到一个初始的GUI界面,往里面添加两个Button和一个Picture控件,如下:
选中单个控件、右击选择属性(Properties),可以看到控件的ID号,这个号可以自行编辑,例如Picture控件的ID号我设置为 IDC_ShowImg,这个ID号在后面的图像显示函数中要用到。
首先在项目属性中加载lib文件:
菜单Project->Properties->ConfigurationProperties->Linker–>Input->additionaldependencies中加入cxcore200.libcv200.libhighgui200.lib。
然后在mymfc.h的#include"resource.h" 下加入如下代码:
#include"cv.h"
#include"highgui.h"
#defineIMAGE_WIDTH256
#defineIMAGE_HEIGHT256
#defineIMAGE_CHANNELS3
在ClassView面板右击CmymfcDlg,选择Add–>AddVariable,添加一个IplImage*类型的变量TheImage;再点击CmymfcDlg,在下面窗口的列表中双击OnInitDialog,在“//TODO:
Addextrainitializationhere”下面添加TheImage的初始化代码:
CvSizeImgSize;
ImgSize.height=IMAGE_HEIGHT;
ImgSize.width=IMAGE_WIDTH;
TheImage=cvCreateImage(ImgSize,IPL_DEPTH_8U,IMAGE_CHANNELS);然后双击OnPaint,在if(IsIconic())…的else里添加以下代码,用来重绘窗口:
CDialog:
:
OnPaint(); //重绘对话框
CDialog:
:
UpdateWindow(); //更新windows窗口,如果无这步调用,图片显示还会出现问题
ShowImage(TheImage,IDC_ShowImg); //重绘图片函数接着在CmymfcApp下面的成员列表中双击InitInstance,在两个“//TODO:
Placecodeheretohandlewhenthedialogis…”下面添加:
cvReleaseImage(&dlg.TheImage);即按下“OK”或“Cancel”时,释放TheImage占用的内存。
接下来就是写读取和处理图片的功能函数了。
回到mymfc的GUI编辑界面中,右击按钮ReadImg,选择AddEventHandler,建立按钮点击的消息响应程序:
句柄名设置为OnBnClickedReadimg,主要的响应操作包括弹出对话框选择图片文件、读入图片文件、对图片统一缩放至256*256的大小、显示图像,代码如下:
//TODO:
Addyourcontrolnotificationhandlercodehere
CFileDialogdlg(
TRUE,_T("*.bmp"),NULL,
OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY,
_T("imagefiles(*.bmp;*.jpg)|*.bmp;*.jpg|AllFiles(*.*)|*.*||"),NULL
); //选项图片的约定
dlg.m_ofn.lpstrTitle=_T("OpenImage"); //打开文件对话框的标题名
if(dlg.DoModal()!
=IDOK) //判断是否获得图片
return;
CStringmPath=dlg.GetPathName(); //获取图片路径
IplImage*ipl=cvLoadImage(mPath,1); //读取图片、缓存到一个局部变量ipl中
if(!
ipl) //判断是否成功载入图片
return;
if(TheImage) //对上一幅显示的图片数据清零
cvZero(TheImage);
ResizeImage(ipl); //对读入的图片进行缩放,使其宽或高最大值者刚好等于256,再复制到TheImage中
ShowImage(TheImage,IDC_ShowImg); //调用显示图片函数
cvReleaseImage(&ipl); //释放ipl占用的内存
其中包含了两个新的成员函数ResizeImage和ShowImage,前者的作用是对读入的不同大小的图像进行缩放,再通过设置ROI的方式将图像存入256*256的TheImage中;后者是将图像TheImage显示到图片显示控件IDC_ShouImg窗口的正中部位。
为了实现这两个功能,首先在ClassView面板右击CmymfcDlg,选择Add–>AddFunction,创建两个函数:
voidShowImage(IplImage*img,UINTID)和voidResizeImage(IplImage*img)。
以下是这两个函数的实现代码:
voidCmymfcDlg:
:
ResizeImage(IplImage*img)
{
//读取图片的宽和高
intw=img->width;
inth=img->height;
//找出宽和高中的较大值者
intmax=(w>h)?
w:
h;
//计算将图片缩放到TheImage区域所需的比例因子
floatscale=(float)((float)max/256.0f);
//缩放后图片的宽和高
intnw=(int)(w/scale);
intnh=(int)(h/scale);
//为了将缩放后的图片存入TheImage的正中部位,需计算图片在TheImage左上角的期望坐标值
inttlx=(nw>nh)?
0:
(int)(256-nw)/2;
inttly=(nw>nh)?
(int)(256-nh)/2:
0;
//设置TheImage的ROI区域,用来存入图片img
cvSetImageROI(TheImage,cvRect(tlx,tly,nw,nh));
//对图片img进行缩放,并存入到TheImage中
cvResize(img,TheImage);
//重置TheImage的ROI准备读入下一幅图片
cvResetImageROI(TheImage);
}
voidCmymfcDlg:
:
ShowImage(IplImage*img,UINTID) //ID是PictureControl控件的ID号
{
CDC*pDC=GetDlgItem(ID)->GetDC(); //获得显示控件的DC
HDChDC=pDC->GetSafeHdc(); //获取HDC(设备句柄)来进行绘图操作
CRectrect;
GetDlgItem(ID)->GetClientRect(&rect);
intrw=rect.right-rect.left; //求出图片控件的宽和高
intrh=rect.bottom-rect.top;
intiw=img->width; //读取图片的宽和高
intih=img->height;
inttx=(int)(rw-iw)/2; //使图片的显示位置正好在控件的正中
intty=(int)(rh-ih)/2;
SetRect(rect,tx,ty,tx+iw,ty+ih);
CvvImagecimg;
cimg.CopyOf(img); //复制图片
cimg.DrawToHDC(hDC,&rect); //将图片绘制到显示控件的指定区域内
ReleaseDC(pDC);
}函数ResizeImage是参考了学习笔记(5)中单窗口显示多幅图像的函数cvShowMultiImages修改而成的,函数ShowImage则是参考了帖子《OpenCV如何把图像显示到MFC的picture控件上》的代码,另外下面几个帖子也可以参考:
1、《MFCpicturecontrol畫框的問題》
2、《MFCpicturecontrol控件实现(隐藏)文字显示》
3、《MFC在PictureControl中显示图片(jpg)遇到的问题》
4、《vc怎样在picturecontrol中显示jpg,jif,bmp格式图象》
5、《使用PictureControl显示BMP图片》
最后是要对读入的图像做简单的Canny边缘处理,为此,建立一个按钮EdgeDetect,相应的响应代码如下:
voidCmymfcDlg:
:
OnBnClickedEdgedetect()
{
//TODO:
Addyourcontrolnotificationhandlercodehere
IplImage*gray=0,*edge=0;
gray=cvCreateImage(cvSize(IMAGE_WIDTH,IMAGE_HEIGHT),IPL_DEPTH_8U,1);
edge=cvCreateImage(cvSize(IMAGE_WIDTH,IMAGE_HEIGHT),IPL_DEPTH_8U,1);
cvCvtColor(TheImage,gray,CV_BGR2GRAY);
cvCanny(gray,edge,30,100,3);
cvCvtColor(edge,TheImage,CV_GRAY2BGR);
ShowImage(TheImage,IDC_ShowImg); //调用显示图片函数
cvReleaseImage(&gray);
cvReleaseImage(&edge);
}这里主要是参考了《OpenCV教程-基础篇》P33的代码,不过并没有像书中那样创建新的MyIplClass类来进行图像的读取和处理操作。
我觉得这篇文章中直接对TheImage进行处理可能不大妥当,按照教程那样新建一个类来处理才是比较稳妥吧。
这里涉及到函数返回对象实例的过程、深拷贝和浅拷贝、拷贝构造、动态内存的使用、opencv相关接口的代码等方面,以后还要进一步深入学习和理解!
最后我们还可以在ResourceView面板->mymfc(工程名称)->mymfc.rc->Version中修改程序的产品版本、名称等信息。
本文来自CSDN博客,转载请标明出处:
本文来自CSDN博客,转载请标明出处:
下面讲述如何更改背景图像,两种方法,第一种方法较为好用,方便,第二种方法读入图像、显示时会出现图像显示不完全。
先载入一张图片,ID为IDB_BITMAP2
TestDlg.h中:
CBrushm_brBk;//在public中定义
TestDlg.cpp中:
在初始化函数OnInitDialog()中加入:
BOOLCTestDlg:
:
OnInitDialog()
{
CDialog:
:
OnInitDialog();
CBitmapbmp;
bmp.LoadBitmap(IDB_BITMAP2);
m_brBk.CreatePatternBrush(&bmp);
bmp.DeleteObject();
returnTRUE;//returnTRUEunlessyousetthefocustoacontrol
}
再打开类向导,找到WM_CTLCOLOR消息,重载得对应函数OnCtlColor(),
具体操作方法为:
在类视图窗口,打开c**Dlg的属性,上面有一栏按钮,映射、消息等等,点击消息按钮,找到WM_CTLCOLOR,添加命令即可
添加如下:
HBRUSHCTestDlg:
:
OnCtlColor(CDC*pDC,CWnd*pWnd,UINTnCtlColor)
{
HBRUSHhbr=CDialog:
:
OnCtlColor(pDC,pWnd,nCtlColor);
if(pWnd==this)
{
returnm_brBk;
}
returnhbr;
}
按照上面的方法一路COPY下来运行,OK!
并且由于图片是做为背景显示的,所以再添的按钮都能很好的显示出来,非常方便。
总结一下其中出现的变量和函数。
CBrush:
类CBrush封装了Windows图形设备接口(GDI)中的画刷,画刷也就是采取什么方案填充图形的背景的工具。
OnInitDialog():
用于对对话框类的变量的初始化(注意:
是在产生对话框之前就初始化),是WM_INITDIALOG消息产生的消
息处理函数,覆盖该函数可改变对话框初始设置。
用法:
virtualBOOLOnInitDialog();返回值指定对话框是否对它的一个控件设置输入焦点。
如果OnInitDialog返回非零
值,Windows将输入焦点设在对话框的第一个控件上,只有在对话框明确将输入焦点设在某控件上,应用返回0。
CBitmap:
类CBitmap封装了Windows图形设备接口(GDI)中的位图,并且提供操纵位图的成员函数。
LoadBitmap():
CBitmap类的一个成员函数,从应用的可执行文件中加载一个命名的位图资源来初始化位图对象。
用法:
BOOLLoadBitmap(LPCTSTRlpszRecourceName);BOOLLoadBitmap(UINTnIDResource);返回值调用成功时返回非零值,
否则为0。
参数lpszResourceName指向一个包含了位图资源名字的字符串(该字符串以null结尾)。
NIDResource指定位图资源
中资源的ID号。
本函数从应用的可执行文件中加载由lpszResourceName指定名字或者由nIDResource指定的ID号标志的位图资
源。
加载的位图被附在Cbitmap对象上。
如果由lpszResourceName指定名字的对象不存在,或者没有足够的内存加载位图,函
数将返回0。
可以调用函数CgdiObject:
:
DeleteObject删除由LoadBitmap加载的位图,否则Cbitmap的析构函数将删除该位图对象。
CreatePatternBrush():
CBrush类的一个成员函数,用位图指定的模式初始化画刷。
用法:
BOOLCreatePatternBrush(CBitmap*pBitmap);返回值调用成功时返回非零值,否则为0。
参数pBitmap指定一个位图。
本
函数用位图指定的模式初始化画刷。
此画刷随后就可用于任何支持光栅操作的设备上下文。
由bBitmap指定的位图一般用以下
的函数初始化:
CBitmap:
:
CreateBitmap、CBitmap:
:
CreateBitmapIndirect、CBitmap:
:
LoadBitmap或Cbitmap:
:
CreateCompatibleBitmap。
DeleteObject():
CgdiObject类的一个成员函数,从内存中删除附加给CGdiObject的WindowsGDI对象,释放与此对象相关
的系统存储空间。
GdiObject类为各种Windows图形设备接口(GDI)对象,如位图、区域、画刷、画笔、调色板、字体等提供
了一些基本类。
我们不会直接构造一个CGdiObject对象,而是使用某一个派生类如CPen或CBrush创建。
用法:
BOOLDeleteObject();如果GDI对象被成功删除,则返回非零值,否则为0。
通过释放附加的GDI对象占有的系统存储来删除它
们。
与CGdiObject对象有关的存储不受此调用的影响。
如果CGdiObject对象正被选入设备上下文中,则应用不可对此对象调用
DeleteObject,。
当一个模式画刷被删除时,与之相关联的位图不被删除。
位图必须被独立删除。
HBRUSH:
数据类型,用于定义画刷句柄。
在Windows环境中,句柄是用来标识项目的,这些项目包括:
module,task,
instance,file,blockofmemory,menu,control,font,resource,icon,cursor,string,GDIobject等,包括
bitmap,brush,metafile,palette,pen,region以及设备描述表devicecontext。
实际上,句柄是一个标识符,用来表示
对象或者项目,是一个32位的正整数。
应用程序几乎总是通过调用一个Windows函数来获得一个句柄,之后其他的Windows函数
就可以使用这个句柄,以引用相应的对象。
WM_CTLCOLOR消息:
WM_CTLCOLOR是一个由控制(Control)发送给它父窗口的通知消息(Notificationmessage)。
利用向导映射
该消息产生函数:
HBRUSHCAboutDlg:
:
OnCtlColor(CDC*pDC,CWnd*pWnd,UINTnCtlColor);参数pDC是TestDlg的设备上下
文,pWnd是TestDlg中发送该消息的control指针,nCtlColor是Control的类型编码。
WM_CTLCOLOR是系统在绘制控件的时候自
动发送的,如果需要自定义,就截取这个消息并重载它的响应函数,用classWizard添加WM_CTLCOLOR消息然后编辑其
OnCtlColor函数。
这样Windows向应用程序发送消息WM_CTLCOLOR,应用程序处理WM_CTLCOLOR消息并返回一个用来绘画窗体背
景的刷子句柄
====================================
//放在OnPaint()里
{//设置背景图片
CRect rect;
GetClientRect(&rect);
CDC *pDC=GetDC();
CDC memdc;
memdc.CreateCompatibleDC(pDC);
CBitmap bitmap;
//从资源中载入位图
bitmap.LoadBitmap(IDB_BITMAP1);
memdc.SelectObject(bitmap);
pDC->BitBlt(0,0,rect.Width(),rect.Height(),&memdc,0,0,SRCCOPY);
}
对于VC++文档、视结构中的视图,从用户的角度来看,只是可以改变大小、位置的普通窗口,同