精华内容
下载资源
问答
  • Mfc图像处理框架 VC编程 图像显示与处理Cimage显示OPencv处理
  • Opencv+MFC框架图像处理

    2019-01-03 10:01:14
    本次项目采用Opencv+MFC框架,通过对源代码的学习和借鉴,完成了对图像进行点处理、邻域处理、二值化、二值图像处理、形态学处理、彩色图像处理、综合处理、视频采集播放这些常用功能。
  • opencv+MFC图像处理程序

    2017-01-12 13:47:48
    使用opncv2.49和VS2010,利用MFC框架做的图像处理软件
  • 一、学习参考文件 ...2、《MFC多文档中OpenCV处理图像打开和保存》,http://blog.csdn.net/abcjennifer/article/details/7313711 二、环境搭建 1、安装VS2013和OpenCV库 详细参见:http://blog.csdn.net/lvhao

    一、学习参考文件

    1、《学习OpenCV》参考书,用OpenCV对图像进行基本的打开,保存等处理。

    2、《MFC多文档中OpenCV处理图像打开和保存》http://blog.csdn.net/abcjennifer/article/details/7313711


    二、环境搭建

    1、安装VS2013和OpenCV库

    详细参见:http://blog.csdn.net/lvhao578041381/article/details/18951071

    2、在第一次创建的过程出现了LPCTSTRconst char *不能相互转换的问题。而OpenCV库中的函数又都不是Unicode的,导致两种数据类型不能相互转换。解决办法:

    项目->属性->配置属性->字符集->使用多字节字符集

    3、在配置之后出现了另外一个问题:error MSB8031: Building an MFC project for a non-Unicode character set MFC在查询资料后才知道VS2013中把multi-byte character set 支持移除了,解决办法:

    在微软上下载一个组件Multibyte MFC Library for Visual Studio 2013 安装完成后基本配置就成功了。


    三、框架实现

    1、搭建一个多文档的MFC框架,并按照一般的OpenCV处理程序修改各种目录


    2、在工程中添加Processing.h头文件和Processing.cpp(将cvload读到的各种格式的图像创建为位图)

    //  Processing.h
    //   2010.8.23
    
    #pragma once
    
    #ifndef		PROCESSING
    #define		PROCESSING
    
    #include "stdafx.h"
    //---------------------------------------------------------
    
    LPBITMAPINFO CtreateMapInfo(IplImage* workImg,int flag);     //创建位图
     
    int  imageType(IplImage* p);								 //返回图像类型
    int  imageClone(IplImage* pi,IplImage** ppo);				 //  复制 IplImage 位图
    int  imageReplace(IplImage* pi,IplImage** ppo);				 //  位图替换
     
    //---------------------------------------------------------
    //  常规图像处理
    
    void Histog(BYTE *buf,int *pg,int Dx,int Dy);
    int  BasicGlobalThreshold(int *pg,int start,int end);
    int  NextColor(int start,int k,int step);            //  下一彩色号
    
    extern RGBQUAD VgaDefPal[256];
    
    #endif  //PROCESSING
    /  Processing.cpp
    //    2010.8.23
    
    #include "stdafx.h"
    #include "Processing.h"
    
    //---------------------------------------------------------
    
    LPBITMAPINFO CtreateMapInfo(IplImage* workImg,int flag)
    {                                           //  建立位图信息
        BITMAPINFOHEADER BIH={40,1,1,1,8,0,0,0,0,0,0};
    	LPBITMAPINFO lpBmi;
    	int      wid,hei,bits,colors,i;
    	RGBQUAD  ColorTab[256];
      
     	wid =workImg->width;
    	hei =workImg->height;
    	bits=workImg->depth*workImg->nChannels;
    
    	if (bits>8) colors=0;
    	else colors=1<<bits;
    
    	lpBmi=(LPBITMAPINFO) malloc(40+4*colors);
    	BIH.biWidth   =wid;
    	BIH.biHeight  =hei;
    	BIH.biBitCount=(BYTE) bits;
      	memcpy(lpBmi,&BIH,40);                  //  复制位图信息头
    
    	if (bits==8) {                          //  256 色位图
    		if (flag==1) {                      //  设置灰阶调色板
    			for (i=0;i<256;i++) {
    				ColorTab[i].rgbRed=ColorTab[i].rgbGreen=
    						ColorTab[i].rgbBlue=(BYTE) i;
    			}
    			memcpy(lpBmi->bmiColors,ColorTab,1024);
    		}
    		else if (flag==2) {                 //  设置默认调色板
    			memcpy(lpBmi->bmiColors,VgaDefPal,1024);
    		}
    	}
    	return(lpBmi);
    }
    
    int  imageType(IplImage* p) 
    {
      	int	 i,j,k,bpl,n,pg[256];
    	BYTE *buf;
      
    	k=p->nChannels;
    	if (k==1) {                             //  检查二值图像
            for (i=0;i<256;i++) pg[i]=0;
    		buf=(BYTE*)p->imageData;
    		bpl=p->widthStep;
            for (i=0;i<p->height;i++) {
    			for (j=0;j<p->width;j++) pg[buf[j]]++;
    			buf+=bpl;
    		}
            for (i=0,n=0;i<256;i++) {
    			if (pg[i]) n++;
    		}
            if (n==2) k=-1;                     //  二值图像
        }
      	return(k);
    }
    
    int  imageClone(IplImage* pi,IplImage** ppo)  //  复制 IplImage 位图
    {
    	if (*ppo) {
    		cvReleaseImage(ppo);                //  释放原来位图
    	}
     	(*ppo) = cvCloneImage(pi);              //  复制新位图
    	return(1);
    }
    
    int  imageReplace(IplImage* pi,IplImage** ppo)  //  位图替换
    {
    	if (*ppo) 
    		cvReleaseImage(ppo);                //  释放原来位图
     	(*ppo) = pi;                            //  位图换名
    	return(1);
    }
    
    //---------------------------------------------------------
    //  VGA 256色默认调色板数据(省略)
    //---------------------------------------------------------
    //  常规图像处理(省略)
    

    3、修改**Doc.h和**Doc.cpp文档

    Doc..h文件

    // 生成的消息映射函数
    protected:
    	DECLARE_MESSAGE_MAP()
    
    public:
    	IplImage* pImg;										//图像指针
    	int m_Display;
    	BOOL Load(IplImage** pp,LPCTSTR csFilename);		//读入图片
    	BOOL Save(LPCTSTR csFilename, IplImage* pImg);		//保存图片
    	BOOL OnOpenDocument(LPCTSTR lpszPathName);			//打开文档
    #ifdef SHARED_HANDLERS

    Doc..cpp文件

    // CdemoDoc 构造/析构
    
    CdemoDoc::CdemoDoc()
    :pImg(NULL),
    m_Display(0)<pre name="code" class="cpp">// CdemoDoc 命令
    BOOL CdemoDoc::Load(IplImage** pp, LPCTSTR csFilename)
    {
    	IplImage* pImg = NULL;
    
    	pImg = cvLoadImage(csFilename, -1);      //  读图像文件(DSCV)  
    	if (!pImg) return(false);
    	cvFlip(pImg);                           //  将图像进行翻转,与 DIB 像素结构一致  
    	if (*pp) {
    		cvReleaseImage(pp);					//若pp指针已有值,则先将其内存释放,在进行载入
    	}
    	(*pp) = pImg;
    	m_Display = 0;
    	return(true);
    }
    
    BOOL CdemoDoc::Save(LPCTSTR csFilename, IplImage* pImg)
    {
    	int   bl;
    	cvFlip(pImg);								 //  恢复原 OpenCV 位图结构  
    	bl = cvSaveImage(csFilename, pImg);          //  图像存盘  
    	return(bl);
    }
    
    BOOL CdemoDoc::OnOpenDocument(LPCTSTR lpszPathName)
    {
    	if (!CDocument::OnOpenDocument(lpszPathName))    return false;
    	Load(&pImg, lpszPathName);
    	if (pImg) return true;
    	return false;
    }

    {// TODO: 在此添加一次性构造代码}

    
    4、修改**view.h和**view.cpp文档
    

    view.h文档

    // 实现
    public:
    	virtual ~CdemoView();
    #ifdef _DEBUG
    	virtual void AssertValid() const;
    	virtual void Dump(CDumpContext& dc) const;
    #endif
    
    protected:
    	IplImage* saveImg;
    	IplImage* workImg;
    
    	LPBITMAPINFO m_lpBmi;
    
    	int     m_CaptFlag;
    	int     m_dibFlag;
    	int     m_SaveFlag;
    	int     m_ImageType;
    // 生成的消息映射函数
    protected:
    	afx_msg void OnFilePrintPreview();
    	afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
    	afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
    	DECLARE_MESSAGE_MAP()
    
    public:
    	virtual void OnInitialUpdate();
    	afx_msg void OnSize(UINT nType, int cx, int cy);
    	afx_msg void OnFileSaveAs();
    	afx_msg void OnColorImageRefresh(); 
    	afx_msg void OnRefresh();
    	afx_msg void OnConservationImage();
    	afx_msg void OnUpdateRefresh(CCmdUI *pCmdUI);
    	afx_msg void OnColorImageRefrsh();
    };
    
    #ifndef _DEBUG  // demoView.cpp 中的调试版本
    inline CdemoDoc* CdemoView::GetDocument() const
       { return reinterpret_cast<CdemoDoc*>(m_pDocument); }
    #endif
    view.cpp文档

    对于菜单栏,可惜删除不必要的按钮,然后按照自己的需要添加相应的按钮。此处主要是搭建基于OpenCV库的MFC框架,后续图像处理算法还在添加。对于

    IMPLEMENT_DYNCREATE(CdemoView, CScrollView)
    
    BEGIN_MESSAGE_MAP(CdemoView, CScrollView)
    	// 标准打印命令
    	ON_COMMAND(ID_FILE_PRINT, &CScrollView::OnFilePrint)
    	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CScrollView::OnFilePrint)
    	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CdemoView::OnFilePrintPreview)
    	ON_WM_CONTEXTMENU()
    	ON_WM_RBUTTONUP()
    	ON_COMMAND(ID_FILE_SAVE_AS, &CdemoView::OnFileSaveAs)              //图像另存的事件
    	ON_COMMAND(ID_REFRESH, &CdemoView::OnRefresh)                      //恢复图像的事件
    	ON_COMMAND(ID_CONSERVATION_IMAGE, &CdemoView::OnConservationImage) //保存当前位图的事件
    	ON_UPDATE_COMMAND_UI(ID_REFRESH, &CdemoView::OnUpdateRefresh)
    	ON_COMMAND(ID_COLOR_IMAGE_REFRSH, &CdemoView::OnColorImageRefrsh)  //恢复原始图像的事件
    END_MESSAGE_MAP()
    
    // CdemoView 构造/析构
    
    CFile fCapture;
    CFileException eCapture;
    char pbuf[20];
    int  captSetFlag = 0;
    
    CdemoView::CdemoView()
    {
    	// TODO:  在此处添加构造代码
    	saveImg = NULL;
    	workImg = NULL;
    
    	m_lpBmi = 0;
    
    	m_CaptFlag = 0;
    	m_dibFlag = 0;
    	m_ImageType = 0;
    
    	CSize sizeTotal;
    	sizeTotal.cx = sizeTotal.cy = 100;
    	SetScrollSizes(MM_TEXT, sizeTotal);
    
    }
    
    CdemoView::~CdemoView()
    {
    	if (saveImg)
    		cvReleaseImage(&saveImg);           //  释放位图  
    	if (workImg)
    		cvReleaseImage(&workImg);
    
    	if (m_lpBmi)
    		free(m_lpBmi);                      //  释放位图信息  
    }
    
    BOOL CdemoView::PreCreateWindow(CREATESTRUCT& cs)
    {
    	// TODO:  在此处通过修改
    	//  CREATESTRUCT cs 来修改窗口类或样式
    
    	return CScrollView::PreCreateWindow(cs);
    }
    
    // CdemoView 绘制
    
    void CdemoView::OnDraw(CDC* pDC)
    {
    	CdemoDoc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    	if (!pDoc)
    		return;
    
    	// TODO:  在此处为本机数据添加绘制代码
    	/*if (pDoc->pImg)
    	{
    		if (pDoc->m_Display == 0)
    		{
    			saveImg = cvCloneImage(pDoc->pImg);			//要保存的图片
    			workImg = cvCloneImage(pDoc->pImg);			//处理的图像
    			//cvShowImage("test", saveImg);
    			m_ImageType = workImg->ID;
    		}
    	}
    	*/
    	if (pDoc->pImg)
    	{
    		if (pDoc->m_Display == 0)
    		{
    			imageClone(pDoc->pImg, &saveImg);
    			m_dibFlag = imageClone(saveImg, &workImg);
    
    			m_ImageType = imageType(workImg);
    			m_SaveFlag = m_ImageType;
    			pDoc->m_Display = 1;
    		}
    	}
    
    	if (m_dibFlag) {                        //  DIB 结构改变  
    		if (m_lpBmi)
    			free(m_lpBmi);
    		m_lpBmi = CtreateMapInfo(workImg, m_dibFlag);
    		m_dibFlag = 0;
    
    		CSize sizeTotal;
    		sizeTotal = CSize(workImg->width, workImg->height);
    		SetScrollSizes(MM_TEXT, sizeTotal);
    	}
    	char* pBits=NULL;
    	if (workImg)
    		pBits = workImg->imageData;
    
    	if (workImg)
    		StretchDIBits(pDC->m_hDC,
    		0, 0, workImg->width, workImg->height,
    		0, 0, workImg->width, workImg->height,
    		pBits, m_lpBmi, DIB_RGB_COLORS, SRCCOPY);
    }
    
    
    // CdemoView 打印
    
    
    void CdemoView::OnFilePrintPreview()
    {
    #ifndef SHARED_HANDLERS
    	AFXPrintPreview(this);
    #endif
    }
    
    BOOL CdemoView::OnPreparePrinting(CPrintInfo* pInfo)
    {
    	// 默认准备
    	return DoPreparePrinting(pInfo);
    }
    
    void CdemoView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
    	// TODO:  添加额外的打印前进行的初始化过程
    }
    
    void CdemoView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
    	// TODO:  添加打印后进行的清理过程
    }
    
    void CdemoView::OnRButtonUp(UINT /* nFlags */, CPoint point)
    {
    	ClientToScreen(&point);
    	OnContextMenu(this, point);
    }
    
    void CdemoView::OnContextMenu(CWnd* /* pWnd */, CPoint point)
    {
    #ifndef SHARED_HANDLERS
    	theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
    #endif
    }
    
    
    // CdemoView 诊断
    
    #ifdef _DEBUG
    void CdemoView::AssertValid() const
    {
    	CScrollView::AssertValid();
    }
    
    void CdemoView::Dump(CDumpContext& dc) const
    {
    	CScrollView::Dump(dc);
    }
    
    CdemoDoc* CdemoView::GetDocument() const // 非调试版本是内联的
    {
    	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CdemoDoc)));
    	return (CdemoDoc*)m_pDocument;
    }
    #endif //_DEBUG
    
    
    // CdemoView 消息处理程序
    
    void CdemoView::OnInitialUpdate()
    {
    	CScrollView::OnInitialUpdate();
    
    	CSize sizeTotal;
    	// TODO: calculate the total size of this view  
    	sizeTotal.cx = sizeTotal.cy = 100;
    	SetScrollSizes(MM_TEXT, sizeTotal);
    }
    
    void CdemoView::OnSize(UINT nType, int cx, int cy)
    {
    	CScrollView::OnSize(nType, cx, cy);
    
    	if (workImg) {                          //  刷新窗口画面  
    		CSize  sizeTotal;
    		sizeTotal = CSize(workImg->width, workImg->height);
    		SetScrollSizes(MM_TEXT, sizeTotal);   //  设置滚动条  
    	}
    }
    
    void CdemoView::OnFileSaveAs()
    {
    	CString csBMP = "BMP Files(*.BMP)|*.BMP|";
    	CString csJPG = "JPEG Files(*.JPG)|*.JPG|";
    	CString csTIF = "TIF Files(*.TIF)|*.TIF|";
    	CString csPNG = "PNG Files(*.PNG)|*.PNG|";
    	CString csDIB = "DIB Files(*.DIB)|*.DIB|";
    	CString csPBM = "PBM Files(*.PBM)|*.PBM|";
    	CString csPGM = "PGM Files(*.PGM)|*.PGM|";
    	CString csPPM = "PPM Files(*.PPM)|*.PPM|";
    	CString csSR = "SR  Files(*.SR) |*.SR|";
    	CString csRAS = "RAS Files(*.RAS)|*.RAS||";
    
    	CString csFilter = csBMP + csJPG + csTIF + csPNG + csDIB
    		+ csPBM + csPGM + csPPM + csSR + csRAS;
    
    	CString name[] = { "", "bmp", "jpg", "tif", "png", "dib",
    		"pbm", "pgm", "ppm", "sr", "ras", "" };
    
    	CString strFileName;
    	CString strExtension;
    
    	CFileDialog FileDlg(false, NULL, NULL, OFN_HIDEREADONLY, csFilter);
    	//  文件存盘对话框  
    	if (FileDlg.DoModal() == IDOK) {         //  选择了文件名  
    		strFileName = FileDlg.m_ofn.lpstrFile;
    		if (FileDlg.m_ofn.nFileExtension == 0) {  //  无文件后缀  
    			strExtension = name[FileDlg.m_ofn.nFilterIndex];
    			strFileName = strFileName + '.' + strExtension;
    			//  加文件后缀  
    		}
    
    		CdemoDoc* pDoc = GetDocument();
    		ASSERT_VALID(pDoc);
    		pDoc->Save(strFileName, workImg);   //  当前画面存盘  
    	}
    }
    
    void CdemoView::OnColorImageRefresh()
    {
    	CdemoDoc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    	pDoc->m_Display = 0;
    	Invalidate();
    }
    
    void CdemoView::OnRefresh()
    {
    	// TODO:  在此添加命令处理程序代码
    	m_dibFlag = imageClone(saveImg, &workImg);
    	m_ImageType = m_SaveFlag;
    	Invalidate();
    }
    
    void CdemoView::OnUpdateRefresh(CCmdUI *pCmdUI)
    {
    	// TODO:  在此添加命令更新用户界面处理程序代码
    	pCmdUI->Enable((m_CaptFlag != 1) && (m_ImageType != -3));
    }
    
    
    void CdemoView::OnConservationImage()
    {
    	// TODO:  在此添加命令处理程序代码
    	imageClone(workImg, &saveImg);
    	m_SaveFlag = m_ImageType;
    }
    
    
    void CdemoView::OnColorImageRefrsh()
    {
    	// TODO:  在此添加命令处理程序代码
    	CdemoDoc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    	pDoc->m_Display = 0;
    	Invalidate();
    }

    通过上述几个步骤,先添加processing.h和processing.cpp文件,里面包含对图像进行位图转换的函数,然后修改Doc和View文件,在Doc进行文件打开和图像读取的操作,在View进行图像的相关操作。




    展开全文
  • 本科毕设时,为了进行演示曾按照网上的方法搭建了一个基于MFC多文档视图界面(MDI)的图像处理框架程序。但是由于对于windows编程的原理不甚了解,过程中遇到了很多细节上的问题,因此整理一下整个过程,便于以后...

    MFC多文档视图界面(MDI)搭建图像处理框架程序总结

    前言:本科毕设时,为了进行演示曾按照网上的方法搭建了一个基于MFC多文档视图界面(MDI)的图像处理框架程序。但是由于对于windows编程的原理不甚了解,过程中遇到了很多细节上的问题,因此整理一下整个过程,便于以后利用。以后有机会详细了解windows程序的运行机制等。

    用Visual C++工程向导创建一个名为“CImageProcess”的多文档/视图框架程序,最终的应用程序界面如下图。

    图一

    在建立工程时可以选择不建立默认的文档和视图类,自行使用“类生成向导”建立支持不同格式的文档和视图类,如下图。对于本例,选择建立CScrollView类和CDocument类,名为“CBmpView”类和“CBmpDoc”类。

    图二

    然后在CImageProcess.cpp中增加头文件CBmpView.h和CBmpDoc.h,CBmpView.h中也要添加CBmpDoc.h。
    这个时候的程序还不支持任何文档格式,在本例中我希望该程序能够支持bmp格式的图片。为此首先要在Resource.h中定义对应bmp格式字符串的宏IDR_BMPTYPE,如下图。

    图三

    并在XXX.rc2资源文件中增加对应bmp文档格式即IDR_BMPTYPE宏的字符串:

    图四

    然后就可以建立对应bmp格式的文档模板,修改CCImageProcessApp::InitInstance()函数。如下图
    图五

    因为从文档模板new CMultiDocTemplate中的参数可以看出,CBmpDoc和CBmpView分别为对应bmp文件的文档类和视图类。为了让程序支持bmp文件的读取和显示,我们需要重载CBmpDoc文档类和CBmpView视图类。

    首先需要在CBmpView.h中声明文档指针CBmpDoc* GetDocument(),然后在CBmpView.cpp中定义GetDocument()函数。如下图

    图六
    图七

    而CBmpView::OnDraw(CDC* pDC)则利用第三方类CDib来完成图形的绘制,许多其他用到的CDib类的文件中也需要添加头文件CDib.h。为了完善滚动条的出现,以及窗口的显示等可以在CBmpView::OnInitialUpdate()进行加载操作并获取尺寸信息。为了在不同函数间传递位图,可以在CBmpView视图类中添加一个CDib的成员变量CDIB DibToDraw,专门由于绘图显示。这样也能解决拖动子窗口时内存占用暴涨的bug。

    图八

    至此基本完成了框架程序的搭建。

    为了使程序在打开时不自动新建一个文档视图,可以在CImageProcess.cpp中增加语句如下

    图九

    为了优化打开多个窗口时的显示效果,可以在ChildFram.h中添加virtual void ActivateFrame(int nCmdShow = -1)函数,然后在该函数的定义中添加移动窗口的语句。

    图十

    窗口的宽度和高度等信息可以在CImgProcApp::InitInstance()中用语句获得。

    图十一

    为了增加新的菜单项,首先修改.rc资源文件中menu部分,在Resource.h中增加新菜单项对应的宏,然后在CCImageProcessApp类中增加对应菜单项的响应函数定义及实现。最后在CImageProcessApp.cpp中将宏和响应函数联系起来,如下图。

    图十二

    展开全文
  • 之前,失败了无数次,把我给整疯了,这次终于成功了! 现在将搭建的方法发到博客上...现在开始搭建框架 新建MFC应用程序 应用程序类型设置 把文件DIb.h和Dib.cpp拷贝到项目文件夹下 把dib.h添加到项目的“.

    之前,失败了无数次,把我给整疯了,这次终于成功了!

    现在将搭建的方法发到博客上。

    最终解决的途径

    跳出思维局限,不要拘泥于某一个版本,比如vs2019或者vs2017,说不定vs2015就可以呢?

    这次vs2015就成功了!

    首先安装vs2015社区版

    下载的时候记得勾选Visual C++

    >>官方下载器地址

    现在开始搭建框架

    新建MFC应用程序

    应用程序类型设置

    把文件DIb.h和Dib.cpp拷贝到项目文件夹下

    把dib.h添加到项目的“解决方案”下的“头文件”

    把dib.cpp文件添加到项目的“解决方案”下的“源文件”

    修改代码部分

    重要提示:

    每一个类都有一个头文件(.h)和源文件(.cpp)

    一定要看清楚,不要加错了

    ----------------------------------Doc.h--------------------------------------------

    修改一

    找到 #pragma once

    在下面添加

    #include "Dib.h"

    修改二

    找到特性和操作,直接替换

    // 特性
    public:
    	CDib m_dib;
    // 操作
    public:
    	HGLOBAL GetHObject() const	//获取Dib对象的句柄
    		{ return m_hDIB; }
    	CPalette* GetDocPal() const	//获取调色板指针
    		{ return m_palDIB; }
    	CSize GetDocDimension() const//获取调色板大小
    		{ return m_sizeDoc; }
    	void UpdateObject(HGLOBAL hDIB);//更新dib对象

    修改三

    找到实现

    // 实现
    public:
    	void SetDib();				//初始化dib对象
    protected:
    	HGLOBAL m_hDIB;
    	CPalette*  m_palDIB;
    	CSize m_sizeDoc;

    -----------------------doc类重写函数(打开、保存文件)的添加----------------------------

    类视图,打开属性

    在此添加Open、Save函数(不可手动复制添加)

    -------------------------------------Doc.cpp-----------------------------------------

    找到构造函数

    // TODO: 在此添加一次性构造代码
    	m_hDIB = NULL;// 初始化变量
    	m_palDIB = NULL;
    	m_sizeDoc = CSize(1,1);

    找到析构函数

            if (m_hDIB != NULL)// 判断是否有DIB对象
    	{		
    		::GlobalFree((HGLOBAL) m_hDIB);
    	}
    	
    	
    	if (m_palDIB != NULL)// 判断调色板是否存在
    	{
    		delete m_palDIB;
    	}

    找到OnOpenDocument函数

            if (!CDocument::OnOpenDocument(lpszPathName))
    		return FALSE;
    
    	// TODO:  在此添加您专用的创建代码
    	CFile file;
    	if (!file.Open(lpszPathName, CFile::modeRead | 
    		CFile::shareDenyWrite))// 打开文件
    	{					
    		return FALSE;// 返回FALSE
    	}	
    	DeleteContents();
    	m_hDIB=m_dib.LoadFile(file);
    	if(m_hDIB==NULL)// 调用LoadFile()读取图象
    	{			
    		return FALSE;
    	}		
    	SetDib();// 初始化DIB
    	if (m_hDIB == NULL)	// 判断读取文件是否成功
    	{		
    		AfxMessageBox(L"读取图像时出错");// 提示出错				
    		return FALSE;// 返回FALSE
    	}		
    	SetPathName(lpszPathName);// 设置文件名称		
    	SetModifiedFlag(FALSE);// 初始化修改标记为FALSE		
    	return TRUE;// 返回TRUE

    找到OnSaveDocument函数

            // TODO: 在此添加专用代码和/或调用基类
    	CFile file;
    	if(!file.Open(lpszPathName, CFile::modeCreate |// 打开文件
    	CFile::modeReadWrite | CFile::shareExclusive))
    	{
    		return FALSE;// 返回FALSE
    	}
    	BOOL bSuccess = FALSE;	
    	bSuccess = m_dib.SaveFile(m_hDIB, file);	// 保存图象	
    	file.Close();// 关闭文件	
    	SetModifiedFlag(FALSE);// 重置脏标记为FALSE
    	if (!bSuccess)
    	{			
    		AfxMessageBox(L"保存BMP图象时出错");// 提示出错
    	}	
    	return bSuccess;
    	//return CDocument::OnSaveDocument(lpszPathName);

    现在检查Doc类是否已经存在SetDib函数和UpdateObject函数

    若不存在,则手动添加,随后粘贴代码

    若存在,直接复制粘贴如下代码到Doc.cpp文件中,并修改类名部分

    类名根据项目名称的不同而不同

    void C********Doc::SetDib() //这个函数需要手动添加,前面的类名要与项目一致
    {
    	LPSTR lpdib = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);	
    	
    	if (m_dib.GetWidth(lpdib) > INT_MAX ||m_dib.GetHeight(lpdib) > INT_MAX)// 判断图象是否过大
    	{
    		::GlobalUnlock((HGLOBAL) m_hDIB);				
    		::GlobalFree((HGLOBAL) m_hDIB);	// 释放DIB对象			
    		m_hDIB = NULL;// 设置DIB为空		
    		AfxMessageBox(L"初始化失败"); 		
    		return;
    	}	
    	m_sizeDoc = CSize((int)m_dib.GetWidth(lpdib), (int)m_dib.GetHeight(lpdib));// 设置文档大小	
    	::GlobalUnlock((HGLOBAL) m_hDIB);	
    	m_palDIB = new CPalette;// 创建新调色板		
    	if (m_palDIB == NULL)// 判断是否创建成功
    	{		
    		::GlobalFree((HGLOBAL) m_hDIB);	// 失败		
    		m_hDIB = NULL;// 设置DIB对象为空
    		return;
    	}	
    	// 调用CreateDIBPalette来创建调色板
    	if (m_dib.ConstructPalette(m_hDIB, m_palDIB) == NULL)
    	{				
    		delete m_palDIB;// 删除				
    		m_palDIB = NULL;// 设置为空	
    		return;// 返回空
    	}
    }
    void C********Doc::UpdateObject(HGLOBAL hDIB)   //这个函数需要手动添加,类名要修改
    {
    	if (m_hDIB != NULL)               // 判断DIB是否为空
    	{		
    		::GlobalFree((HGLOBAL) m_hDIB);// 非空,则清除
    	}	
    	m_hDIB = hDIB;                     // 替换成新的DIB对象	
    }

    ---------------------------View.cpp----------------------------

    找到OnDraw函数

    看到这里

    删去注释,解除封印

    看到这一行,在下面添加代码

            // TODO: 在此处为本机数据添加绘制代码
    	HGLOBAL hDIB = pDoc->GetHObject();
    	
    	// 判断DIB是否为空
    	if (hDIB != NULL)
    	{
    		LPSTR lpDibSection = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
    		
    		// 获取DIB宽度
    		int cxDIB = (int) pDoc->m_dib.GetWidth(lpDibSection);
    		
    		// 获取DIB高度
    		 int cyDIB = (int) pDoc->m_dib.GetHeight(lpDibSection);
    		::GlobalUnlock((HGLOBAL) hDIB);
    		CRect rcDIB;
    		rcDIB.top = rcDIB.left = 0;
    		rcDIB.right = cxDIB;
    		rcDIB.bottom = cyDIB;
    		CRect rcDest= rcDIB;	
    		// 输出DIB
    		pDoc->m_dib.DrawDib(pDC->m_hDC, &rcDest, pDoc->GetHObject(),
    			&rcDIB, pDoc->GetDocPal());
    	}

    在确保项目文件夹下已有stdafx.h”“stdafx.cpp存在时,编译执行

    效果

     

     

     

     

    展开全文
  • MFC平台的图像处理

    2019-01-03 10:06:15
    本次项目采用Opencv+MFC框架,通过对源代码的学习和借鉴,完成了对图像进行点处理、邻域处理、二值化、二值图像处理、形态学处理、彩色图像处理、综合处理、视频采集播放这些常用功能。
  • 图像处理程序框架MFC相关知识点

    千次阅读 2014-05-20 10:14:18
    MFC基础类库定义了设备环境对象类----CDC类。 CDC与CGdiObject的关系 说道CDC类就不能不提一下GdiObject---图形对象类。 在Windows应用程序中,设备环境与图形对象共同工作,协同完成绘图显示工作。就像画家绘画一样...

    CDC:Windows使用与设备无关的图形设备环境(DC :Device Context) 进行显示 。

    MFC基础类库定义了设备环境对象类----CDC类。
    CDC与CGdiObject的关系
    说道CDC类就不能不提一下GdiObject---图形对象类。 在Windows应用程序中,设备环境与图形对象共同工作,协同完成绘图显示工作。就像画家绘画一样,设备环境好比是画家的画布,图形对象好比是画家的画笔。用画笔在画布上绘画,不同的画笔将画出不同的画来。选择合适的图形对象和绘图对象,才能按照要求完成绘图任务。
    有关CDC类的继承


    父类:从 CObject 直接继承而来。继承了CObject类的各种特性,如动态创建等等。
    子类:CClientDC-------代表操作窗口的DC ,是比较常用的一个子类
    CMetaFileDC ------响应Meta File的DC ,Meta File是一些GDI消息。
    CPaintDC-------响应WM_PAINT消息的DC。
    CWindowDC ------代表整个屏幕的DC


    CDC类的数据成员
    数据成员只有两个:
    HDC m_hDC : CDC对象使用的输出设备上下文
    HDC m_hAttribDC : CDC对象使用的属性设备上下文
    二者在CDC对象创建时指向相同的设备上下文。

     

    CDC类:定义设备环境对象类 


    CDC::BitBlt 从源设备环境拷贝一个位图到当前设备环境中

    BOOL BitBlt(int x,int y,int nWidth,int nHeight,CDC* pSrcDC,int xSrc,int ySrc,DWORD dwRop);
    参数:x,y为目的矩形的左上角坐标;nWidth,nHeight为目的矩形的宽度和高度;pSrcDC是指向源设备环境的指针;xSrc,ySrc源位图左上角的坐标;dwRop为光栅操作码。

    CDC::CreateCompatibleDC 创建一个与pDC指定的设备相兼容的内存设备环境

    virtual BOOL CreateCompatibleDC(CDC* pDC);
    参数:pDC 设备环境指针
    返回值:若成功,返回非0;否则返回0

    CDC::Detach 将设备环境从CDC对象中分离开来

    HDC Detach()
    返回值:分离的设备环境


    CDC::DrawEdge 绘制矩形边框或边框的一部分

    BOOL DrawEdge(LPRECT lpRect,UINT nEdge,UINT nFlags);
    参数lpRect指向矩形的RECT结构的指针;nEdge指定矩形内外边界的风格,必须是一个内边界标志和外边界标志的组合,取值为:
    BDR_RAISEDINNER:内边界凸出;
    BDR_SUNKENINNER:内边界凹下;
    BDR_RAISEDOUTER:外边界凸出;
    BDR_SUNKENOUTER:外边界凹下;
    nFlags指定边界的类型,取值为:
    BF_RECT:矩形的所有四边;
    BF_LEFT:矩形的左边;
    BF_BOTTOM:矩形的底边;
    BF_RIGHT:矩形的右边;
    BF_TOP:矩形的上边;
    BF_TOPLEFT:矩形的上边和左边;
    BF_TOPRIGHT:矩形的上边和右边;
    BF_BOTTOMLEFT:矩形的下边和左边;
    BF_BOTTOMRIGHT:矩形的下边和右边。
    返回值:若成功,返回非0;否则返回0。

    CDC::DrawFocusRect 画一个说明输入焦点的矩形

    void DrawFocusRect(LPCRECT lpRect);
    参数:lpRect 指向绘制矩形的逻辑坐标的RECT结构或CRect对象。 

    CDC::FillSolidRect 用指定单颜色填充矩形 
    void FillSolidRect(LPCRECT lpRect,COLORREF clr);
    void FillSolidRect(int x,int y,int cx,int cy,COLORREF clr);
    参数:lpRect指定要填充的矩形;clr填充的颜色
    x,y矩形的左上角坐标,cx、cy为矩形宽度和高度

    CDC::FromHandle 在给予一个设备环境句柄时返回一个CDC对象指针 
    static CDC* PASCAL FromHandle(HDC hDC);
    参数:hDC 设备环境句柄
    返回值:CDC对象指针

    CDC::PaintRgn 用当前画刷填充一个CRgn对象的区域 
    BOOL PaintRgn(CRgn* pRgn);
    参数:指向一个CRgn对象的指针
    返回值:若成功,返回非0;否则返回0

    CDC::Rectangle 用当前画笔画一个矩形,并用当前画刷填充为实心矩形 
    BOOL Rectangle(int x1,int y1,int x2,int y2);
    BOOL Rectangle(LPCRECT lpRect);
    参数:x1、y1为矩形左上角坐标,x2、y2为矩形右下角坐标
    lpRect为RECT结构或CRect对象
    返回值:若成功,返回非0;否则返回0

    CDC::RestoreDC 将设备环境恢复成先前的状态 
    virtual BOOL RestoreDC(int nSaveDC);
    参数:nSaveDC设备环境先前状态的整数标识
    返回值:若成功,返回非0;否则返回0

    CDC::RoundRect 用当前画笔画一个圆角矩形,并用当前画刷填充 
    BOOL RoundRect(int x1,int y1,int x2,int y2,int x3,int y3);
    BOOL RoundRect(LPCRECT lpRect,POINT point);
    参数:x1、y1为左上角坐标,x2、y2为右下角坐标,x3、y3为画圆角的椭圆的逻辑宽度和高度
    lpRect为RECT结构或CRect对象,point中的x、y为画圆角的椭圆的逻辑宽度和高度
    返回值:若成功,返回非0;否则返回0

    CDC::SaveDC 保存设备环境的当前状态 
    virtual int SaveDC();
    返回值:若成功,返回标识保存设备环境的整数;若错误返回0

    CDC::SelectStockObject 将一个预定义的库存对象装入设备环境 
    virtual CGdiObject* SelectStockObject(int nIndex);
    参数:nIndex库存对象的索引值,常用取值:
    BLACK_BRUSH 黑色画刷; DKGRAY_BRUSH 深灰色画刷;
    GRAY_BRUSH 灰色画刷; LTGRAY_BRUSH 浅灰色画刷;
    WHITE_BRUSH 白色画刷; HOLLOW_BRUSH 中空画刷;
    NULL_BRUSH 空画刷;
    BLACK_PEN 黑色画笔; WHITE_PEN 白色画笔;
    NULL_PEN 空画笔;
    SYSTEM_FONT 系统字体;
    返回值:被替换的CGdiObject对象的指针,若调用失败,返回NULL

    CDC::SetMapMode设置映射模式,映射模式定义了将逻辑单位转换为设备单位的单位量,并定义了X和Y的方向
    virtual int SetMapMode(int nMapMode);
    返回值:上一个映射模式。

     

    CDC::SelectObject 将一个对象选入设备环境,替代同一类型的先前对象 
    CPen* SelectObject(CPen* pPen);
    CBrush* SelectObject(CBrush* pBrush);
    virtual CFont* SelectObject(CFont* pFont);
    CBitmap* SelectObject(CBitmap* pBitmap);
    int SelectObject(CRgn* pRgn);
    参数:要选入的新对象的指针
    返回值:先前的旧对象的指针

     

    CDC::SetBkMode 设置背景模式 
    int SetBkMode(int nBkMode);
    参数:nBkMode为要设置的背景模式,取值可以为:
    OPAQUE 在绘制文本前用当前背景色填充背景,这是缺省的背景模式
    TRANSPARENT 绘制前不改变背景(即文字背景透明)
    返回值:先前的背景模式

     

    CDC::MoveTo 设置画图的起点位置 
    CPoint MoveTo(int x,int y);
    CPoint MoveTo(POINT point);
    参数:x、y为新位置的坐标;point为新位置坐标
    返回值:先前位置的坐标

     

    CDC::LineTo 从当前位置到指定点画直线 
    BOOL LineTo(int x,int y);
    BOOL LineTo(POINT point);
    参数:x、y为直线末端的坐标;point为直线末端的坐标
    返回值:若成功,返回非0;否则返回0
    该函数通常与MoveTo()函数合起来完成画线工作。 

    CDC::SetTextColor 设置文本颜色 
    virtual COLORREF SetTextColor(COLORREF crColor);
    参数:crColor指定文本颜色
    返回值:先前的文本颜色

    CDC::TextOut 用当前字体在指定位置写一字符串 
    virtual BOOL TextOut(int x,int y,LPCTSTR lpszString,int nCount);
    BOOL TextOut(int x,int y,const CString& str);
    参数:x,y文本左上角坐标;lpszString指示要输出的字符串;nCount为字符串中字节数;str为要输出的CString对象
    返回值:若成功,返回非0;否则返回0

     

    CDC::SetBkColor 设置当前背景色 
    virtual COLORREF SetBkColor(COLORREF crColor);
    参数:crColor为新背景色
    返回值:先前背景色;若错误,返回值为0x80000000

     

    CDC::GetTextExtent 使用当前字体计算一行文本的宽度和高度 
    CSize GetTextExtent(LPCTSTR lpszString,int nCount)const;
    CSize GetTextExtent(const CString& str)const;
    参数:lpszString指向一个字符串,nCount字符串中字符数
    str 一个字符串对象
    返回值:字符串文本的宽度和高度(以逻辑单位表示)

    CDC::GetTextMetrics 检取当前字体的规格 
    BOOL GetTextMetrics(LPTEXTMETRIC lpMetrics)const;
    参数:lpMetrics 指向用于接收字体规格的TEXTMETRIC结构
    返回值:若成功,返回非0;否则返回0

     

    CDC::DrawText 在指定的矩形内绘制格式化的文本 
    virtual int DrawText(LPCTSTR lpszString,int nCount,LPRECT lpRect,UINT nFormat);
    int DrawText(const CString& str,LPRECT lpRect,UINT nFormat);
    参数:lpszString指示要输出的字符串;nCount为字符串中字节数;lpRect指示文本所在的矩形;str为要输出的CString对象;nFormat为格式化文本的方式,常用取值:
    DT_BOTTOM 文本底对齐,必须和DT_SINGLELINE联用;
    DT_CENTER 居中显示文本; DT_LEFT 文本左对齐;
    DT_RIGHT 文本右对齐; DT_TOP 正文与行顶部对齐(仅指单个行);
    DT_NOCLIB 绘制时不加裁减;DT_SINGLELINE 单行显示;
    DT_VCENTER 指定在垂直方向上居中显示文本(仅只单个行); 
    DT_WORDBREAK 若单词超过矩形边界,行将在单词间断开
    返回值:若调用成功,返回文本的高度

     

     

     

    OnInitialUpdate概括

    视图窗口完全建立后第一个被框架调用的函数。框架在第一次调用OnDraw前会调用OnInitialUpdate,因此OnInitialUpdate是设置滚动视图的逻辑尺寸和映射模式的最合适的地方。

    时间上,两者先后顺序不同,构造函数生成本类的对象,但没有产生窗口,OnCreate后窗口产生, 然后才是视图的OnInitialUpDate,一般在这里对视图的显示做初始化。简单点,就是OnCreate只是产生VIEW的基本结构和变量而在OnInitialUpDate(),主要初始化视图中控件等。对各个变量进行初始化操作。

    例子。我们要在视图中添加一个buttoncombobox控件

    2OnCreate函数中写法如下编辑

    int CFormView::OnCreate(LPCREATESTRUCT lpCreateStruct)

    {

    if (CView::OnCreate(lpCreateStruct) == -1)

    return -1;

    // TODO: Add your specialized creation code here

    CRect rect(20,20,100,50);

    m_ctrlButton.Create("Button1",WS_CHILD|WS_VISIBLE,rect,this,NULL);

    //创建按扭控件

    CFont *pFont=CFont::FromHandle((HFONT)::GetStockObject(ANSI_VAR_FONT));

    CRect rect1(150,20,350,100);

    m_combobox.Create(WS_CHILD|WS_VISIBLE|CBS_SIMPLE|CBS_NOINTEGRALHEIGHT|WS_VSCROLL,rect1,this,NULL);

    return 0;

    }

    3OnInitialUpDate中写法编辑

    void CFormView::OnInitialUpdate()

    {

    CView::OnInitialUpdate();

    // TODO: Add your specialized code here and/or call the base class

    //初始化组合框控件

    m_combobox.AddString("Mondy");

    m_combobox.AddString("Tuesday");

    m_combobox.AddString("Wednesday");

    m_combobox.AddString("Thursday");

    m_combobox.AddString("Saturday");

    m_combobox.AddString("Sunday");

    }

    MFC程序设计中,按照传统的设计,如果处理WM_PAINT消息,一般会派生一个OnPaint函数,映射到WM_PAINT消息上进行绘图处理。但是很多程序中并没有出现OnPaint,一个OnDraw函数做了更多的绘图操作。而在消息映射的列表中,也没有见到WM_PAINTOnDraw的映射。

    实际上,OnDraw不是OnPaint的映射,出现OnDraw,是为了实现各种不同的设备上的绘图一致性。

    首先,读者需要明白的是,WM_PAINT消息是为了绘制屏幕而出现的因此,在OnPaint中,我们只能存取屏幕DC,进行绘制,常见的代码是:

    void MyWnd::OnPaint()

    {

    CPaintDC dc(this);

    //draw code here

    }

    这里的CPaintDC构造函数自动调用BeginPaint,获得一个屏幕DC,并附加在dc对象上。当dc对象析构时,系统自动调用EndPaint并使invalidated rectangle变成validated状态,从而结束绘制。(注意,重复创建CPaintDC实例会失败也因为如此)

    如果我们在OnPaint中绘制,那么在打印机上绘制我们就需要再写一个OnPrint函数,重新绘制。这样,程序设计者就需要维护两套代码。为了简化操作,MFC框架把大部分绘制操作都放在OnDraw中,OnPaintOnPrint只构造相应的DC,然后分别调用OnDraw.也就是说,OnDraw适用于所有的设备,而OnPaint只适用于屏幕。

    大家在设计过程中必须注意:OnDraw是被基类OnPaint主动调用的,如果你继承了OnPaint,你应该要么调用基类的OnPaint(此前不得创建CPaintDC实例,也不得调用BeginPaint),要么自己创建CPaintDC实例,并调用OnDraw.

     

     

    MFC中OnDraw与OnPaint的区别 :


    OnPaint是WM_PAINT消息的消息处理函数,在OnPaint中调用OnDraw,一般来说,用户自己的绘图代码应放在OnDraw中。 

    OnPaint()是CWnd的类成员,负责响应WM_PAINT消息。OnDraw()是CVIEW的成员函数,没有响应消息的功能.当视图变得无效时(包括大小的改变,移动,被遮盖等等),Windows发送WM_PAINT消息。该视图的OnPaint 处理函数通过创建CPaintDC类的DC对象来响应该消息并调用视图的OnDraw成员函数.OnPaint最后也要调用OnDraw,因此一般在OnDraw函数中进行绘制。


    The WM_PAINT message is sent when the UpdateWindow or RedrawWindow member function is called. 

    在OnPaint中,将调用BeginPaint,用来获得客户区的显示设备环境,并以此调用GDI函数执行绘图操作。在绘图操作完成后,将调用EndPaint以释放显示设备环境。而OnDraw在BeginPaint与EndPaint间被调用。 

    1) 在mfc结构里OnPaint是CWnd的成员函数. OnDraw是CView的成员函数. 
    2) OnPaint()调用OnDraw(),OnPrint也会调用OnDraw(),所以OnDraw()是显示和打印的共同操作。 

    OnPaint是WM_PAINT消息引发的重绘消息处理函数,在OnPaint中会调用OnDraw来进行绘图。OnPaint中首先构造一个CPaintDC类得实例,然后一这个实例为参数来调用虚函数OnPrepareDC来进行一些绘制前的一些处理,比设置映射模式,最后调用OnDraw。而OnDraw和OnPrepareDC不是消息处理函数。所以在不是因为重绘消息所引发的OnPaint导致OnDraw被调用时,比如在OnLButtonDown等消息处理函数中绘图时,要先自己调用OnPrepareDC。 
    至于CPaintDC和CClientDC根本是两回事情 CPaintDC是一个设备环境类,在OnPaint中作为参数传递给OnPrepareDC来作设备环境的设置。真正和CClientDC具有可比性的是CWindowDC,他们一个是描述客户区域,一个是描述整个屏幕。 
    如果是对CVIEW或从CVIEW类派生的窗口绘图时应该用OnDraw。 

    OnDraw()和OnPaint()有什么区别呢? 
    首先:我们先要明确CView类派生自CWnd类。而OnPaint()是CWnd的类成员,同时负责响应WM_PAINT消息。OnDraw()是CVIEW的成员函数,并且没有响应消息的功能。这就是为什么你用VC成的程序代码时,在视图类只有OnDraw没有OnPaint的原因。而在基于对话框的程序中,只有OnPaint。 
    其次:我们在第《每天跟我学MFC》3的开始部分已经说到了。要想在屏幕上绘图或显示图形,首先需要建立设备环境DC。其实DC是一个数据结构,它包含输出设备(不单指你17寸的纯屏显示器,还包括打印机之类的输出设备)的绘图属性的描述。MFC提供了CPaintDC类和CWindwoDC类来实时的响应,而CPaintDC支持重画。当视图变得无效时(包括大小的改变,移动,被遮盖等等),Windows 将 WM_PAINT 消息发送给它。该视图的OnPaint 处理函数通过创建 CPaintDC 类的DC对象来响应该消息并调用视图的 OnDraw 成员函数。通常我们不必编写重写的 OnPaint 处理成员函数。 
    ///CView默认的标准的重画函数 


    void CView::OnPaint() //VIEWCORE.CPP 


    CPaintDC dc(this); 
    OnPrepareDC(&dc)
     
    OnDraw(&dc); //
    调用了OnDraw 

    ///CView
    默认的标准的OnPrint函数 
    void CView::OnPrint(CDC* pDC, CPrintInfo*) 

    ASSERT_VALID(pDC); 
    OnDraw(pDC); // Call Draw 


    既然OnPaint最后也要调用OnDraw,因此我们一般会在OnDraw函数中进行绘制。下面是一个典型的程序。 
    ///视图中的绘图代码首先检索指向文档的指针,然后通过DC进行绘图调用。 
    void CMyView::OnDraw( CDC* pDC ) 


    CMyDoc* pDoc = GetDocument(); 
    CString s = pDoc->GetData(); 
    GetClientRect( &rect ); // Returns a CString CRect rect; 
    pDC->SetTextAlign( TA_BASELINE | TA_CENTER ); 
    pDC->TextOut( rect.right / 2, rect.bottom / 2, s, s.GetLength() ); 

    最后:现在大家明白这哥俩之间的关系了吧。因此我们一般用OnPaint维护窗口的客户区(例如我们的窗口客户区加一个背景图片),用OnDraw维护视图的客户区(例如我们通过鼠标在视图中画图)。当然你也可以不按照上面规律来,只要达到目的并且没有问题,怎么干都成。补充:我们还可以利用Invalidate(),ValidateRgn(),ValidateRect()函数强制的重画窗口,具体的请参考MSDN吧。 

    OnDraw中可以绘制用户区域。OnPaint中只是当窗口无效时重绘不会保留CClientDC绘制的内容。 

    这两个函数有区别也有联系: 

    1、区别:OnDraw是一个纯虚函数,定义为virtual void OnDraw( CDC* pDC ) = 0; 而OnPaint是一个消息响应函数,它响应了WM_PANIT消息,也是是窗口重绘消息。 

    2、联系:我们一般在视类中作图的时候,往往不直接响应WM_PANIT消息,而是重载OnDraw纯虚函数,这是因为在CVIEW类中的WM_PANIT消息响应函数中调用了OnDraw函数,如果在CMYVIEW类中响应了WM_PAINT消息,不显式地调用OnDraw函数的话,是不会在窗口重绘的时候调用OnDraw函数的。 

    应用程序中几乎所有的绘图都在视图的 OnDraw 成员函数中发生,必须在视图类中重写该成员函数。(鼠标绘图是个特例,这在通过视图解释用户输入中讨论。) 


    OnDraw 重写: 
    通过调用您提供的文档成员函数获取数据。 
    通过调用框架传递给 OnDraw 的设备上下文对象的成员函数来显示数据。 
    当文档的数据以某种方式更改后,必须重绘视图以反映该更改。默认的 OnUpdate 实现使视图的整个工作区无效。当视图变得无效时,Windows 将 WM_PAINT 消息发送给它。该视图的 OnPaint 处理函数通过创建 CPaintDC 类的设备上下文对象来响应该消息并调用视图的 OnDraw 成员函数。 

    当没有添加WM_PAINT消息处理时,窗口重绘时,由OnDraw来进行消息响应...当添加WM_PAINT消息处理时,窗口重绘时,WM_PAINT消息被投递,由OnPaint来进行消息响应.这时就不能隐式调用OnDraw了.必须显式调用( CDC *pDC=GetDC(); OnDraw(pDC); ).. 
    隐式调用:当由OnPaint来进行消息响应时,系统自动调用CView::OnDraw(&pDC). 


    想象一下,窗口显示的内容和打印的内容是差不多的,所以,一般情况下,统一由OnDraw来画。窗口前景需要刷新时,系统会会调用到OnPaint,而OnPaint一般情况下是对DC作一些初始化操作后,调用OnDraw()。 


    OnEraseBkGnd(),是窗口背景需要刷新时由系统调用的。明显的一个例子是设置窗口的背景颜色(你可以把这放在OnPaint中去做,但是会使产生闪烁的现象)。 
    至于怎么界定背景和前景,那要具体问题具体分析了,一般情况下,你还是很容易区别的吧。 

    的确,OnPaint()用来响应WM_PAINT消息,视类的OnPaint()内部根据是打印还是屏幕绘制分别以不同的参数调用OnDraw()虚函数。所以在OnDraw()里你可以区别对待打印和屏幕绘制。 
    其实,MFC在进行打印前后还做了很多工作,调用了很多虚函数,比如OnPreparePrint()等。 

     

    展开全文
  • 一、课程背景数字图像处理技术的发展涉及信息科学、计算机科学、数学、物理学以及生物学等学科,因此数理及相关的边缘学科对图像处理科学的发展有越来越大的影响。近年来,数字图像处理技术日趋成熟,它广泛应用于...
  • 遥感图像处理系统MFC

    2019-03-27 21:34:46
    遥感图像处理系统的MFC框架,注意只是框架,软件内部函数还需要自己去写
  • 一、课程背景数字图像处理技术的发展涉及信息科学、计算机科学、数学、物理学以及生物学等学科,因此数理及相关的边缘学科对图像处理科学的发展有越来越大的影响。近年来,数字图像处理技术日趋成熟,它广泛应用于...
  • 数字图像处理技术的发展涉及信息科学、计算机科学、数学、物理学以及生物学等学科,因此数理及相关的边缘学科对图像处理科学的发展有越来越大的影响。近年来,数字图像处理技术日趋成熟,它广泛应用于空间探测、...
  • MFC下编写的对话框程序,打开摄像头/视频文件/图像文件。基于opencv下的Mat类,避免了内存管理问题。此代码为开发图像/视频处理软件开发提供良好的参考。
  • VS2019 配置MFC VS2019打开VS2017工程 || VS2017下载 VS2019 MFC 令人迷惑的错误 Visual Studio MFC创建新项目失败 ...数字图像处理MFC框架搭建方法 MFC 添加对话框 MFC 根据Radio选择算法 ...
  • 1,单纯用C/C++语言进行图像处理,苦于各种图像读写保存的库的加载调用,或者说实在不想用MFC,不想用CImage等,但是又没有办法; 2,想用高级语言,比如C#/JAVA等,因为他们有强大的图像加载保存API,可以直接方便...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 157
精华内容 62
关键字:

mfc图像处理框架