2014-07-24 14:34:19 zzucode 阅读数 6413
  • MFC上位机与STM32下位机通讯精讲

    本课程主要介绍C++类库MFC上位机与STM32单片机的RS232、RS422、RS485、USB、LWIP以太网、CAN等接口进行稳定通信。课程主要从MFC和STM32基础开始,以编写上位机以及下位机为主,非常注重实践。

    9303 人正在学习 去看看 王凯杰
最近老师让做一个处理图像的小软件,用了大概一个星期做出来了成品,MFC上我算是新手,一路摸索过来也算是收获不少吧,现在软件也做完了,给自己总结一下在学习过程中的收获和不足。

首先放出一下软件的运行截图,主要是做了灰度图像的几何变换、正交变换、图像增强、二值化处理、形态学处理、图像分割等功能。代码主要参考了《visual c++数字图象处理技术详解》以及网上的一些技术文章,完整的工程已上传至csdn:http://download.csdn.net/detail/zzucode/7672489

灰度图像处理主要操作的是设备无关位图(DIB),由于mfc本身没有提供DIB的一个完整的类,只是提供了一些API接口和结构体,因此需要自己创建一个DIB类,主要实现位图的载入,保存,绘制及返回位图信息等操作。

首先使用mfc向导创建一个单文档应用程序,不使用unicode编码,然后在源文件中添加DIB类的头文件Dib.h和Dib.cpp,具体的头文件如下:

class CDib 
{
public:
	CDib();
	virtual ~CDib();
	//operations
	public:
	// 用于操作DIB的函数声明
	BOOL   DrawDib(HDC, LPRECT,HGLOBAL, LPRECT,CPalette*);//显示位图
	BOOL   ConstructPalette(HGLOBAL,CPalette* );          //构造逻辑调色板
	LPSTR  GetBits(LPSTR);                                //取得位图数据的入口地址
	DWORD  GetWidth(LPSTR);                               //取得位图的宽度
	DWORD  GetHeight(LPSTR);                              //取得位图的高度
	WORD   GetPalSize(LPSTR);                             //取得调色板的大小
	WORD   GetColorNum(LPSTR);                            //取得位图包含的颜色数目
	WORD   GetBitCount(LPSTR);                            //取得位图的颜色深度
	HGLOBAL CopyObject(HGLOBAL);                          //用于复制位图对象

	BOOL      SaveFile(HGLOBAL , CFile&);                    //存储位图为文件
	HGLOBAL   LoadFile(CFile&);                           //从文件中加载位图
	BOOL      IsEmpty();
	// 在对图像进行处理时,针对位图的字节宽度必须是4的倍数的这一要求,
	//我们设计了函数GetRequireWidth,来处理这种比较特殊的情况
	int     GetReqByteWidth(int );                     //转换后的字节数
	long    GetRectWidth(LPCRECT );                    //取得区域的宽度
	long    GetRectHeight(LPCRECT);                    //取得区域的高度
public:
	void ClearMemory();
	void InitMembers();
public:
	LPBITMAPINFO        	lpbminfo;// 指向BITMAPINFO结构的指针
	LPBITMAPINFOHEADER  	lpbmihrd;	//指向BITMAPINFOHEADER结构的指针
	BITMAPFILEHEADER<span style="white-space:pre">	</span>bmfHeader;  //BITMAPFILEHEADER结构
	LPSTR<span style="white-space:pre">			</span>lpdib;      //指向DIB的指针
	LPSTR<span style="white-space:pre">			</span>lpDIBBits;  // DIB像素指针
	DWORD<span style="white-space:pre">			</span>dwDIBSize;  //DIB大小
	HGLOBAL<span style="white-space:pre">			</span>m_hDi       //DIB对象的句柄
	RGBQUAD*<span style="white-space:pre">		</span>lpRgbQuag;  //指向颜色表的指针
};
DIB类的实现文件太长,就不再贴出来了,《visual c++数字图象处理技术详解》上有完整的源码,有感兴趣的朋友可以自己去看。

将Dib的实现文件添加进来之后,接下来就需要载入图像并在文档客户区显示,首先在工程C**Doc类的头文件中声明一个Dib类的对象并定义一些操作:

// 特性
public:
	CDib m_dib;	//声明一个DIB对象
	CString m_szPathName;//图片文件路径
// 操作
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对象
public:
	HGLOBAL m_hDIB;
	CPalette *m_palDIB;
	CSize m_sizeDoc;

然后在C**Doc类的实现文件的构造函数中添加

// TODO: 在此添加一次性构造代码
	m_hDIB = NULL;
	m_palDIB = NULL;
	m_sizeDoc = CSize(1,1);
在析构函数中添加

if (m_hDIB != NULL)	//判断是否有dib对象
	{
		::GlobalFree(m_hDIB);
	}

	if (m_palDIB != NULL)	//判断是否有调色板
	{
		delete m_palDIB;
	}
然后重载C**Doc类的OnOpenDocument函数

// TODO:  在此添加您专用的创建代码
	CFile file;
	if (!file.Open(lpszPathName,CFile::modeRead | CFile::shareDenyWrite))
	{
		//只读方式打开文件
		return FALSE;
	}
	DeleteContents();//删除文档中数据,确保载入图像数据之前文档为空
	m_hDIB = m_dib.LoadFile(file);

	m_szPathName = lpszPathName;
	if (m_hDIB == NULL)
	{
		return FALSE;
	}
	SetDib();
	if (m_hDIB == NULL)
	{
		AfxMessageBox("读取图像时出错!");
		return FALSE;
	}
	SetPathName(lpszPathName);//设置文件名称

	return TRUE;
其中setdib函数主要是在载入位图数据后创建调色板,具体代码如下

void CImgProcessDoc::SetDib()
{
	LPSTR lpdib = (LPSTR) ::GlobalLock(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("初始化失败!"); 		
		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;// 返回空
	}
}
这时候编译工程并运行,点击打开一个位图文件就可以将位图文件的信息和数据载入内存,但是打开之后并没有在客户区显示,这时候需要重载C**View类的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());
	}
编译工程并运行,就可以打开文件并显示到程序的客户区了。





2012-06-26 22:05:58 bbdxf 阅读数 3443
  • MFC上位机与STM32下位机通讯精讲

    本课程主要介绍C++类库MFC上位机与STM32单片机的RS232、RS422、RS485、USB、LWIP以太网、CAN等接口进行稳定通信。课程主要从MFC和STM32基础开始,以编写上位机以及下位机为主,非常注重实践。

    9303 人正在学习 去看看 王凯杰

软件使用VC6.0+OpenCV+GDIPlus完成。

 

先看几张截图:

 

1、开始界面:

 

 

2、打开图片:

 

 

3、所有的菜单:

 

 

4、软件下载地址:

 

纯软件:点击打开链接 ( CSDN上传真的不好使啊,问题多多....)

 

纯源码:点我下载(注:8分,不贵,感觉不值的不用下。

 

另,不是我不讲人情,非特殊情况请勿扰,本人只提供源码

 

 

供学习,无责任义务解释和修改工作)

 

 

 

 

 

 

 

 

 

 

2019-12-28 11:28:06 li123128 阅读数 6
  • MFC上位机与STM32下位机通讯精讲

    本课程主要介绍C++类库MFC上位机与STM32单片机的RS232、RS422、RS485、USB、LWIP以太网、CAN等接口进行稳定通信。课程主要从MFC和STM32基础开始,以编写上位机以及下位机为主,非常注重实践。

    9303 人正在学习 去看看 王凯杰

  运行环境VS2017,需要配置库为:opencv
  
  题目:样本采集小工具
  
  需求:
  
  用MFC和opencv完成样本采集小工具。
  
  界面功能
  
  1、选中原图片集的目录。
  
  2、选择当前是正样本还是负样本?并选中其目录。
  
  3、通过上一张下一张更换原图片集的图片显示。
  
  鼠标点击图片显示区域功能
  
  1、左击图片选中,以鼠标点击处为中心,宽W*高H的区域。
  
  2、鼠标滚轮上滚扩大选中区域。
  
  3、鼠标滚轮下滚缩小选中区域。
  
  4、右击保存选中区域的图片在正样本或负样本的目录下,取决于当前选中正样本还是负样本。
  
  完成界面如图:
  
  第一步:把MFC界面的那些控件都拖动好并且绑定好opencv图形框
  
  在MFC的初始化函数中添加我们的绑定代码:
  
  复制代码
  
  BOOL CpicroiDlg::OnInitDialog()
  
  {
  
  CDialogEx::OnInitDialog();
  
  // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
  
  //  执行此操作
  
  SetIcon(m_hIcon, TRUE);            // 设置大图标
  
  SetIcon(m_hIcon, FALSE);        // 设置小图标
  
  //InitializeSkin(("Minimized.ssk"));//初始化
  
  // TODO: 在此添加额外的初始化代码
  
  namedWindow("ImageShow", CV_WINDOW_KEEPRATIO);          // 用OpenCV创建一个窗口
  
  CRect cWindowRect;
  
  m_PictureControl.GetClientRect(&cWindowRect);           // 获取控件窗口大小
  
  //int nWindowWidth = cWindowRect.Width();
  
  //int nWindowHeight = cWindowRect.Height();
  
  //resizeWindow("ImageShow", 200, 100);
  
  HWND hPictureWindow = (HWND)cvGetWindowHandle("ImageShow");        //  获取OpenCV窗口的句柄
  
  HWND hParentWindow = ::GetParent(hPictureWindow);
  
  ::SetParent(hPictureWindow, GetDlgItem(IDC_PIC)->m_hWnd);   //  关联OpenCV窗口和MFC的控件窗口
  
  ::ShowWindow(hParentWindow, SW_HIDE);
  
  GetDlgItem(IDC_PIC)->ShowWindow(0);                        // 开始不显示图片控件
  
  setMouseCallback("ImageShow", onMouse, 0);
  
  pcom.InsertString(0, "正样本");
  
  pcom.InsertString(1, "负样本");
  
  pcom.SetCurSel(0);
  
  return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
  
  }
  
  复制代码
  
  第二步:选中原图片集的目录
  
  这样接下来操作的图片都从这个目录顺序读取,并且切换上下张
  
  添加好对话框类之后:
  
  双击这个控件,进入相应的编辑函数内部编写事件处理代码:
  
  复制代码
  
  void CpicroiDlg::OnBnClickedMainFilePath()
  
  {
  
  // TODO: 在此添加控件通知处理程序代
  
  CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("image files (*.jpeg; *.jpg; *.bmp;*.png)  All Files (*.*) |*.*||"));
  
  CString m_strPath;
  
  CString m_folderpath;
  
  if (IDOK == dlg.DoModal(www.dajuhezc.cn )) {
  
  m_strPath = dlg.GetPathName();
  
  m_folderpath = dlg.GetFolderPath();
  
  }
  
  string strName = CT2A(m_strPath.GetString());              // CString和string之间的类型转换
  
  string strPathNames = CT2A(m_folderpath.GetString(www.shicaiyl.com));
  
  sourceImage = imread(strName);
  
  nWindowWidth = sourceImage.cols;
  
  nWindowHeight = sourceImage.rows;
  
  resizeWindow("ImageShow", nWindowWidth, nWindowHeight);
  
  if (strName == "")return;
  
  tempImage = sourceImage.clone(www.zhenghongyule.com);
  
  imshow("ImageShow", sourceImage);
  
  GetDlgItem(IDC_PIC)->ShowWindow(www.baihua178.cn);
  
  SetDlgItemText(IDC_MAIN_FILE, m_folderpath);
  
  UpdateWindow();
  
  getFiles1(strPathNames, files);
  
  filesLen = files.size(www.shentuylzc.cn)-1;
  
  for (auto path : files) {
  
  index++;
  
  if (path == strName)break;
  
  }
  
  }
  
  复制代码
  
  同样的也要选择保存的文件路径:
  
  复制代码
  
  void CpicroiDlg::www.jiuhuaylgw.cn OnBnClickedMainFilePath2()
  
  {
  
  // TODO: 在此添加控件通知处理程序代码
  
  if (m_dlgMainFile.DoModal() != IDOK)
  
  return;
  
  CString cstrFile;                //文件全名
  
  string strFile;
  
  cstrFile = m_dlgMainFile.GetFolderPath();
  
  strFile = CT2A(cstrFile.GetString());
  
  SetDlgItemText(IDC_MAIN_FILE2, cstrFile);
  
  UpdateWindow();
  
  getFiles1(strFile, filesPath2);
  
  picIndex = filesPath2.size(www.qiaoheibpt.com);
  
  GetDlgItem(IDC_MAIN_FILE2)->GetWindowTextA(cs_pcomValue);
  
  s_pcomComValue = CT2A(cs_pcomValue.GetString());
  
  }
  
  复制代码
  
  复制代码
  
  void CpicroiDlg::OnBnClickedMainFilePath3()
  
  {
  
  // TODO: 在此添加控件通知处理程序代码
  
  if (m_dlgMainFile.DoModal() != IDOK)
  
  return;
  
  CString strFile;                //文件全名
  
  strFile = m_dlgMainFile.GetFolderPath() + "\\";
  
  SetDlgItemText(IDC_MAIN_FILE3, strFile);
  
  UpdateWindow();
  
  }
  
  复制代码
  
  这样只要选择好了正负样本点击右键就可以自动保存到相应的选择好的目录了
  
  第三步:鼠标控制图像的裁剪和选定
  
  这里我们要实现的是鼠标点击出现一个矩形框,然后用鼠标的滚轮去滚动,让矩形框围绕中心点改变大小,然后点击右键则保存图形
  
  复制代码
  
  void onMouse(int event, int x, int y, int flag, void*) {
  
  //CDC *pDC = GetDC();
  
  //CString str; str.Format(TEXT("%d,%d"), x, y);
  
  //pDC->FillSolidRect(0, 0, 100, 100, GetSysColor(COLOR_WINDOW));
  
  //pDC->TextOut(1, 0, str);
  
  switch (event)
  
  {
  
  case CV_EVENT_LBUTTONDOWN://左键按下
  
  flag = true;
  
  mousFlag = 1;
  
  moux = x;
  
  mouy = y;
  
  if ((x - width / 2) < 0)Lu.x = 0;
  
  else Lu.x = x - width / 2;
  
  if ((y - height / 2) < 0)Lu.y = 0;
  
  else Lu.y = y - height / 2;
  
  if ((x + width / 2) > nWindowWidth - 1)Rd.x = nWindowWidth - 1;
  
  else Rd.x = x + width / 2;
  
  if ((y + height / 2) > nWindowHeight - 1 )Rd.y = nWindowHeight - 1;
  
  else Rd.y = y + height / 2;
  
  lastImage = tempImage.clone();
  
  rectangle(tempImage, Lu, Rd, Scalar(0, 255, 0), 1, 0, 0);
  
  imshow("ImageShow", tempImage);
  
  break;
  
  case CV_EVENT_RBUTTONDOWN://右键按下
  
  {    Rect rect(Lu.x, Lu.y, Rd.x-Lu.x, Rd.y-Lu.y);
  
  g_rect = rect;
  
  }
  
  if (s_pcomComValue == "")
  
  {
  
  MessageBox(AfxGetMainWnd()->m_hWnd, "存放目录未填写","警告", MB_OK);
  
  break;
  
  }
  
  s_save = s_pcomComValue +"\\"+ to_string(picIndex) + ".jpg";
  
  ROI = sourceImage(g_rect);
  
  imwrite(s_save, ROI);
  
  picIndex++;
  
  break;
  
  case CV_EVENT_MOUSEWHEEL:
  
  int mousWhellFlag;
  
  int value;
  
  mousWhellFlag = 1;
  
  value = getMouseWheelDelta(flag);
  
  if (value > 0) {
  
  Lu.x = Lu.x > 0 ? Lu.x -= step : Lu.x;
  
  Lu.y = Lu.y > 0 ? Lu.y -= step : Lu.y;
  
  Rd.x = Rd.x < (nWindowWidth - 1) ? Rd.x += step : (nWindowWidth - 1);
  
  Rd.y = Rd.y < (nWindowHeight - 1) ? Rd.y += step : (nWindowHeight - 1);
  
  }
  
  else {
  
  Lu.x = Lu.x < x ? Lu.x += step : x;
  
  Lu.y = Lu.y < y ? Lu.y += step : y;
  
  Rd.x = Rd.x > x ? Rd.x -= step : x;
  
  Rd.y = Rd.y > y ? Rd.y -= step : y;
  
  }
  
  {    Rect rect(Lu.x, Lu.y, Rd.x - Lu.x, Rd.y - Lu.y); g_rect = rect;    }
  
  tempImage = lastImage.clone();
  
  rectangle(tempImage, Lu, Rd, Scalar(0, 255, 0), 1, 0, 0);
  
  imshow("ImageShow", tempImage);
  
  break;
  
  default:
  
  break;
  
  }
  
  }
  
  复制代码
  
  因为我们裁剪已经画矩形框都不能在原图上画,所以我们复制一份图像显示,所有的操作都是在复制 的临时图像上操作的,然后在根据缓冲刷新,将图像替换就行了
  
  最后说一句,这个是直接显示原图的,如果原图过大只能看到部分,这时候在代码里面加个判断,然后用opencv的图像归一化的函数去改变一下图像大小即可。
  
  因为不想写的很详细,(别问为什么,问就是因为最近很懒!!!),所以我给出了项目源码的百度云在文章的开头

2014-12-07 13:14:32 u011619422 阅读数 1182
  • MFC上位机与STM32下位机通讯精讲

    本课程主要介绍C++类库MFC上位机与STM32单片机的RS232、RS422、RS485、USB、LWIP以太网、CAN等接口进行稳定通信。课程主要从MFC和STM32基础开始,以编写上位机以及下位机为主,非常注重实践。

    9303 人正在学习 去看看 王凯杰

首先给出我们的本次实例的demo




然后我们在类视图的头文件中添加成员变量


BOOL bTakeScreen;  //判断是否点击
HBITMAP m_hbmp;  //位图句柄


然后为抓图中整屏添加消息响应函数   代码如下

void CChildView::On32771()
{
// TODO:  在此添加命令处理程序代码


bTakeScreen = TRUE;
m_hbmp = TakeScreen();
Invalidate();
}



TakeScreen函数的代码如下:


HBITMAP CChildView::TakeScreen(){
HWND hwnd = ::GetDesktopWindow();
HDC hScreenDC = ::GetDC(hwnd);
HDC memdc = ::CreateCompatibleDC(hScreenDC);
RECT rect;


::GetWindowRect(hwnd , &rect);


SIZE screensize;
screensize.cx = rect.right - rect.left;
screensize.cy = rect.bottom - rect.top;


HBITMAP bitmap = ::CreateCompatibleBitmap(hScreenDC, screensize.cx, screensize.cy);
HGDIOBJ hOldBmp = ::SelectObject(memdc, bitmap);
::BitBlt(memdc, 0, 0, screensize.cx, screensize.cy, hScreenDC, rect.left, rect.top, SRCCOPY);


::SelectObject(memdc, hOldBmp);
::DeleteObject(memdc);
::ReleaseDC(hwnd, hScreenDC);


return bitmap;

}



  然后在WM_PAINT消息响应函数中添加代码


void CChildView::OnPaint() 
{
CPaintDC dc(this); // 用于绘制的设备上下文

// TODO:  在此处添加消息处理程序代码



if (bTakeScreen){
CBitmap *pbitmap;
pbitmap = CBitmap::FromHandle(m_hbmp);
CDC memdc;
memdc.CreateCompatibleDC(&dc);


CBitmap *pOldBitmap = memdc.SelectObject(pbitmap);
BITMAP bmp;
pbitmap->GetBitmap(&bmp);
dc.BitBlt(10, 10, bmp.bmWidth, bmp.bmHeight, &memdc, 0, 0, SRCCOPY);


memdc.SelectObject(pOldBitmap);


}


// 不要为绘制消息而调用 CWnd::OnPaint()
}


如果要实现屏幕的时候响应,可以在上面的抓屏响应函数中添加定时器来完成



2019-05-08 10:50:43 qq_34801642 阅读数 1702
  • MFC上位机与STM32下位机通讯精讲

    本课程主要介绍C++类库MFC上位机与STM32单片机的RS232、RS422、RS485、USB、LWIP以太网、CAN等接口进行稳定通信。课程主要从MFC和STM32基础开始,以编写上位机以及下位机为主,非常注重实践。

    9303 人正在学习 去看看 王凯杰


一、背景

  由于OpenCV常用的界面只是单纯的打开图像窗口,相关界面控件和工具较少且不美观,故使用MFC制作界面,而用OpenCV单纯做图像处理。此时便需要在MFC中显示OpenCV所用的图片。

二、方法

1、嵌套。直接将OpenCV窗口嵌套到MFC的Pictrue Control控件中。此方法既能直接显示图片,也可直接使用OpenCV的鼠标按键事件,但对于鼠标滚轮事件只能使用MFC本地的滚轮函数。
2、转换。将OpenCV读取或处理的图片转换格式,使之成为MFC的Pictrue Control控件可显示的图片格式。此方法每刷新一次图片便需要转换格式一次,比较麻烦,且只能使用MFC的鼠标事件。
3、保存。将OpenCV读取或处理的图片保存为本地图片,然后用MFC读取图片的方法读取并显示。此方法是笨方法,在特定情况下使用,保存和读取图片比较耗时,但无需转换格式,同样只能使用MFC的鼠标事件。

三、实现

3.1 嵌套OpenCV窗口显示图片

1、新建MFC应用程序。
在这里插入图片描述
2、配置OpenCV运行环境。
在这里插入图片描述
3、添加MFC的Pictrue Control控件
在这里插入图片描述
4、编写代码。只需修改MFCApplication1Dlg.cpp文件。
在这里插入图片描述
添加的代码:

//在MFCApplication1Dlg.cpp添加库文件
#include "opencv2/opencv.hpp"
using namespace cv;

//在MFCApplication1Dlg.cpp的CMFCApplication1Dlg::OnInitDialog()函数中添加如下代码:

// TODO: 在此添加额外的初始化代码
	namedWindow("ImageShow");//创建OpenCV窗口
	HWND hWnd = (HWND)cvGetWindowHandle("ImageShow");//嵌套opencv窗口
	HWND hParent = ::GetParent(hWnd);
	::SetParent(hWnd, GetDlgItem(IDC_STATIC)->m_hWnd);
	::ShowWindow(hParent, SW_HIDE);
	Mat mat = imread("E:\\vs\\image\\11.png");//opencv读取图片
	imshow("ImageShow", mat);//opencv显示图片
	waitKey(1);

全部代码:

// MFCApplication1Dlg.cpp: 实现文件
//

#include "stdafx.h"
#include "MFCApplication1.h"
#include "MFCApplication1Dlg.h"
#include "afxdialogex.h"

#include "opencv2/opencv.hpp"
using namespace cv;

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CMFCApplication1Dlg 对话框



CMFCApplication1Dlg::CMFCApplication1Dlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_MFCAPPLICATION1_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMFCApplication1Dlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
END_MESSAGE_MAP()


// CMFCApplication1Dlg 消息处理程序

BOOL CMFCApplication1Dlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码
	namedWindow("ImageShow");//创建OpenCV窗口
	HWND hWnd = (HWND)cvGetWindowHandle("ImageShow");//嵌套opencv窗口
	HWND hParent = ::GetParent(hWnd);
	::SetParent(hWnd, GetDlgItem(IDC_STATIC)->m_hWnd);
	::ShowWindow(hParent, SW_HIDE);
	Mat mat = imread("E:\\vs\\image\\11.png");//opencv读取图片
	imshow("ImageShow", mat);//opencv显示图片
	waitKey(1);

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CMFCApplication1Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CMFCApplication1Dlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMFCApplication1Dlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

5、运行结果
在这里插入图片描述

3.2 转换格式显示OpenCV图片

1、新建MFC应用程序(同上)
2、配置OpenCV环境(同上)
3、添加Pictrue Control控件(同上)
4、编写程序
添加的代码:

//在MFCApplication2Dlg.h添加库文件及函数声明
#include "opencv2/opencv.hpp"
using namespace cv;
void MatToCImage(Mat &mat, CImage &cImage);

//在MFCApplication2Dlg.cpp最后添加函数定义:
void MatToCImage(Mat &mat, CImage &cImage)
{
	//create new CImage  
	int width = mat.cols;
	int height = mat.rows;
	int channels = mat.channels();

	cImage.Destroy(); //clear  
	cImage.Create(width, height, 8 * channels); //默认图像像素单通道占用1个字节  

	//copy values  
	uchar* ps;
	uchar* pimg = (uchar*)cImage.GetBits(); //A pointer to the bitmap buffer  
	int step = cImage.GetPitch();

	for (int i = 0; i < height; ++i)
	{
		ps = (mat.ptr<uchar>(i));
		for (int j = 0; j < width; ++j)
		{
			if (channels == 1) //gray  
			{
				*(pimg + i * step + j) = ps[j];
			}
			else if (channels == 3) //color  
			{
				for (int k = 0; k < 3; ++k)
				{
					*(pimg + i * step + j * 3 + k) = ps[j * 3 + k];
				}
			}
		}
	}
}

//在CMFCApplication2Dlg::OnPaint()画出图片:
    UpdateWindow();//刷新窗口
	Mat mat = imread("E:\\vs\\image\\11.png");//opencv读取图片
	//resize(mImage, mImage, Size(), 0.3, 0.3);
	CRect rect;//定义矩形类  
	CWnd *pWnd = GetDlgItem(IDC_STATIC);//获取控件句柄  
	pWnd->GetClientRect(&rect);	//获取句柄指向控件区域的大小  
	CDC *pDc = pWnd->GetDC();//获取picture的DC  
	int win_w = rect.Width(), win_h = rect.Height();//获取窗口宽高
	int img_w = mat.cols, img_h = mat.rows;//获取图片宽高
	CImage ImageCam;
	MatToCImage(mat, ImageCam);//转换图片格式
	pDc->SetStretchBltMode(COLORONCOLOR);
	ImageCam.Draw(pDc->m_hDC, 0, 0, win_w, win_h, 0, 0, win_w, win_h);//画出图片
	ReleaseDC(pDc);

MFCApplication2Dlg.h全部代码:


// MFCApplication2Dlg.h: 头文件
//

#pragma once
#include "opencv2/opencv.hpp"
using namespace cv;


// CMFCApplication2Dlg 对话框
class CMFCApplication2Dlg : public CDialogEx
{
// 构造
public:
	CMFCApplication2Dlg(CWnd* pParent = nullptr);	// 标准构造函数

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_MFCAPPLICATION2_DIALOG };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持


// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
};

void MatToCImage(Mat &mat, CImage &cImage);

MFCApplication2Dlg.cpp全部代码:


// MFCApplication2Dlg.cpp: 实现文件
//

#include "stdafx.h"
#include "MFCApplication2.h"
#include "MFCApplication2Dlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CMFCApplication2Dlg 对话框



CMFCApplication2Dlg::CMFCApplication2Dlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_MFCAPPLICATION2_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMFCApplication2Dlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CMFCApplication2Dlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
END_MESSAGE_MAP()


// CMFCApplication2Dlg 消息处理程序

BOOL CMFCApplication2Dlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CMFCApplication2Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CMFCApplication2Dlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}

	UpdateWindow();//刷新窗口
	Mat mat = imread("E:\\vs\\image\\11.png");//opencv读取图片
	//resize(mImage, mImage, Size(), 0.3, 0.3);
	CRect rect;//定义矩形类  
	CWnd *pWnd = GetDlgItem(IDC_STATIC);//获取控件句柄  
	pWnd->GetClientRect(&rect);	//获取句柄指向控件区域的大小  
	CDC *pDc = pWnd->GetDC();//获取picture的DC  
	int win_w = rect.Width(), win_h = rect.Height();//获取窗口宽高
	int img_w = mat.cols, img_h = mat.rows;//获取图片宽高
	CImage ImageCam;
	MatToCImage(mat, ImageCam);//转换图片格式
	pDc->SetStretchBltMode(COLORONCOLOR);
	ImageCam.Draw(pDc->m_hDC, 0, 0, win_w, win_h, 0, 0, win_w, win_h);//画出图片
	ReleaseDC(pDc);
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMFCApplication2Dlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void MatToCImage(Mat &mat, CImage &cImage)
{
	//create new CImage  
	int width = mat.cols;
	int height = mat.rows;
	int channels = mat.channels();

	cImage.Destroy(); //clear  
	cImage.Create(width, height, 8 * channels); //默认图像像素单通道占用1个字节  

	//copy values  
	uchar* ps;
	uchar* pimg = (uchar*)cImage.GetBits(); //A pointer to the bitmap buffer  
	int step = cImage.GetPitch();

	for (int i = 0; i < height; ++i)
	{
		ps = (mat.ptr<uchar>(i));
		for (int j = 0; j < width; ++j)
		{
			if (channels == 1) //gray  
			{
				*(pimg + i * step + j) = ps[j];
			}
			else if (channels == 3) //color  
			{
				for (int k = 0; k < 3; ++k)
				{
					*(pimg + i * step + j * 3 + k) = ps[j * 3 + k];
				}
			}
		}
	}
}

5、运行结果
在这里插入图片描述

3.3 OpenCV图片保存后显示

1、新建MFC应用程序(同上)
2、配置OpenCV环境(同上)
3、添加Pictrue Control控件(同上)
4、编写程序
添加的代码:

//在CMFCApplication2Dlg添加库文件:
#include "opencv2/opencv.hpp"
using namespace cv;

//在CMFCApplication2Dlg::OnPaint()画出图片:
    Mat mat = imread("E:\\vs\\image\\11.png");//opencv读取图片
	imwrite("E:\\vs\\image\\11_new.png", mat);//保存opencv图片

	CImage img;
	img.Load(L"E:\\vs\\image\\11_new.png");//mfc读取图片
	int img_w = img.GetWidth(), img_h = img.GetHeight();//获取图片宽高

	UpdateWindow();//刷新窗口
	CRect rect;//定义矩形类  
	CWnd *pWnd = GetDlgItem(IDC_STATIC);//获取控件句柄  
	pWnd->GetClientRect(&rect);	//获取句柄指向控件区域的大小  
	CDC *pDc = pWnd->GetDC();//获取picture的DC  
	int win_w = rect.Width(), win_h = rect.Height();//获取窗口宽高
	pDc->SetStretchBltMode(COLORONCOLOR);
	img.Draw(pDc->m_hDC, 0, 0, win_w, win_h, 0, 0, win_w, win_h);//画出图片
	ReleaseDC(pDc);

全部代码:

// MFCApplication3Dlg.cpp: 实现文件
//

#include "stdafx.h"
#include "MFCApplication3.h"
#include "MFCApplication3Dlg.h"
#include "afxdialogex.h"

#include "opencv2/opencv.hpp"
using namespace cv;

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CMFCApplication3Dlg 对话框



CMFCApplication3Dlg::CMFCApplication3Dlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_MFCAPPLICATION3_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMFCApplication3Dlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CMFCApplication3Dlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
END_MESSAGE_MAP()


// CMFCApplication3Dlg 消息处理程序

BOOL CMFCApplication3Dlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CMFCApplication3Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CMFCApplication3Dlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}

	Mat mat = imread("E:\\vs\\image\\11.png");//opencv读取图片
	imwrite("E:\\vs\\image\\11_new.png", mat);//保存opencv图片

	CImage img;
	img.Load(L"E:\\vs\\image\\11_new.png");//mfc读取图片
	int img_w = img.GetWidth(), img_h = img.GetHeight();//获取图片宽高

	UpdateWindow();//刷新窗口
	CRect rect;//定义矩形类  
	CWnd *pWnd = GetDlgItem(IDC_STATIC);//获取控件句柄  
	pWnd->GetClientRect(&rect);	//获取句柄指向控件区域的大小  
	CDC *pDc = pWnd->GetDC();//获取picture的DC  
	int win_w = rect.Width(), win_h = rect.Height();//获取窗口宽高
	pDc->SetStretchBltMode(COLORONCOLOR);
	img.Draw(pDc->m_hDC, 0, 0, win_w, win_h, 0, 0, win_w, win_h);//画出图片
	ReleaseDC(pDc);
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMFCApplication3Dlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


5、运行结果
在这里插入图片描述

没有更多推荐了,返回首页