[MFC] 梳理一个简单的图片处理桌面软件中用到的MFC控件技巧
前言
前些天应好友之拖,帮忙设计一个简单的图像处理的小软件。朋友把核心算法封装好了,但是是用openCV类似于console的编程环境,要我在此基础上改成MFC桌面程序。下图是做成之后的效果:
我是两年前稍微学了点MFC的知识,这两年中基本没有涉及,因为诸多相同的需求都可以用C#来搞定。这个本来也是想用C#来弄,可是我朋友用了openCV的相关函数封装了核心的“美颜算法”,我就只好重温经典了!
本文只涉及开发该小软件中与MFC控件相关的操作技巧,不提供朋友的“美颜算法”,还请各位见谅!
工程中技术点小结
1、打开与保存文件:
1 void CDonutDlg::OnBnClickedButtonRead() 2 { 3 BOOL isOpen = TRUE; //是否打开(否则为保存) 4 CString defaultDir = "E:\\FileTest"; //默认打开的文件路径 5 CString fileName = ""; //默认打开的文件名 6 CString filter = "文件 (*.png; *.jpg; *.bmp)|*.png;*.jpg;*.bmp||"; //文件过虑的类型 7 CFileDialog openFileDlg(isOpen, defaultDir, fileName, OFN_HIDEREADONLY | OFN_READONLY, filter, NULL); 8 openFileDlg.GetOFN().lpstrInitialDir = "E:\\FileTest\\donut.jpg"; 9 INT_PTR result = openFileDlg.DoModal(); 10 CString filePath = defaultDir + "\\donut.jpg"; 11 if (result == IDOK) { 12 filePath = openFileDlg.GetPathName(); 13 LoadPicture(filePath);//加载图片保存在全局变量m_image中 14 UpdatePicture();//显示图片 15 } 16 //CWnd::SetDlgItemTextW(IDC_EDIT_SRC, filePath); 17 // TODO: 在此添加控件通知处理程序代码 18 }
1 void CDonutDlg::OnBnClickedButtonSave() 2 { 3 BOOL isOpen = FALSE; //是否打开(否则为保存) 4 CString defaultDir = "E:\\FileTest"; //默认打开的文件路径 5 CString fileName = "donut.jpg"; //默认打开的文件名 6 CString filter = "文件 (*.png; *.jpg; *.bmp)|*.png;*.jpg;*.bmp||"; //文件过虑的类型 7 CFileDialog openFileDlg(isOpen, defaultDir, fileName, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, filter, NULL); 8 openFileDlg.GetOFN().lpstrInitialDir = "E:\\FileTest\\donut.jpg"; 9 INT_PTR result = openFileDlg.DoModal(); 10 CString filePath = defaultDir + "\\" + fileName; 11 if (result == IDOK) { 12 filePath = openFileDlg.GetPathName(); 13 SavePicture(filePath); 14 } 15 //CWnd::SetDlgItemTextW(IDC_EDIT_DEST, filePath); 16 // TODO: 在此添加控件通知处理程序代码 17 }
2、滚动条和文本显示:
- 一共有6个slider监听,每次slider滑动就会触发该函数,在该函数内获取slider当前位置,然后通过映射公式得到文本框内该显示的数据
1 void CDonutDlg::OnNMCustomdrawSliderSmooth(NMHDR *pNMHDR, LRESULT *pResult) 2 { 3 LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR); 4 // TODO: 在此添加控件通知处理程序代码 5 int nPos = m_SliderSmooth.GetPos(); //获得滑块的当前位置 6 //另外做一个编辑框 显示所调节的数据; 7 CString str = ""; m_SliderSmoothValue = 1;//1-31整数 8 m_SliderSmoothValue = (int)floor(nPos / 6.25) * 2 + 1; 9 if (m_SliderSmoothValue == 33)m_SliderSmoothValue = 31; 10 str.Format("%2d", m_SliderSmoothValue); 11 SetDlgItemText(IDC_EDIT_SMOOTH, str); 12 *pResult = 0; 13 }
- 但是如果想在鼠标抬起后更新图片就要用下面的监听事件了:
1 void CDonutDlg::OnNMReleasedcaptureSliderSmooth(NMHDR *pNMHDR, LRESULT *pResult) 2 { 3 // TODO: 在此添加控件通知处理程序代码 4 UpdatePicture(); 5 *pResult = 0; 6 }
3、更新状态——刷新图片(将openCV格式转换为MFC能显示格式)+ ListBox显示处理信息 + CHECK_BUTTON基本用法
1 #include "CvvImage.h" 2 void CDonutDlg::UpdatePicture() 3 { 4 double t = 0; 5 CString str; 6 7 if (fb.setImage(m_SourceImage) == false)//这个一定要 8 { 9 return; 10 } 11 12 //6个参数在全局定义DonutDlg.h中 13 //在DonutDlg的构造函数中初始化 14 //int m_SliderSmoothValue;//1-31整数 15 //double m_SliderEyeSizeValue;//0.8-1 16 //double m_SliderSharpenValue;//0-2 17 //double m_SliderRValue;//0.5-1.5 18 //double m_SliderGValue;//0.5-1.5 19 //double m_SliderBValue;//0.5-1.5 20 t = (double)cvGetTickCount();//用来计算算法执行时间 21 22 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX; 23 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX; 24 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX; 25 m_image = fb.getResult(); 26 27 t = (double)cvGetTickCount() - t;//相减为算法执行的时间 28 str.Format("%lf", t/((double)cvGetTickFrequency()*1000)); 29 m_ListBox.InsertString(m_ListBox.GetCount(), "美颜时间..."); 30 m_ListBox.InsertString(m_ListBox.GetCount(), str); 31 32 33 CDC* pDC = GetDlgItem(IDC_STATIC_PIC)->GetDC(); 34 HDC hDC = pDC->GetSafeHdc(); 35 IplImage img = m_image; 36 CvvImage cimg; 37 cimg.CopyOf(&img);//上面几步是将Mat转换为CvvImage,但是opencv2无CvvImage需要从网上下载CvvImage源码加入工程 38 CRect rect; 39 40 CStatic* pStatic = (CStatic*)GetDlgItem(IDC_STATIC_PIC); 41 pStatic->GetClientRect(&rect); 42 pStatic->GetDC()->FillSolidRect(rect.left, rect.top, rect.Width(), rect.Height(), RGB(192, 192, 192));//刷一张背景(否则每次会出现重叠现象) 43 44 45 if (BST_UNCHECKED == ((CButton*)GetDlgItem(IDC_CHECK_FILL))->GetCheck()) 46 { 47 if ((rect.Height()*1.0 / rect.Width() - m_image.rows*1.0 / m_image.cols)>0) 48 { 49 double new_width = rect.Width(); 50 double new_height = rect.Height()*1.0*m_image.rows / m_image.cols; 51 double extern_height = (rect.Height() - new_height) / 2;//为了居中,整个左上角的贴图向下平移的距离 52 rect.SetRect(0, extern_height, new_width, extern_height + new_height);//cols列--高,cows行--宽 53 } 54 else 55 { 56 double new_width = rect.Width()*1.0*m_image.cols / m_image.rows; 57 double new_height = rect.Height(); 58 double extern_width = (rect.Width() - new_width) / 2; 59 rect.SetRect(extern_width, 0, new_width + extern_width, new_height); 60 } 61 } 62 cimg.DrawToHDC(hDC, &rect); 63 ReleaseDC(pDC); 64 65 #ifdef SHOW_IMAGE 66 if (BST_CHECKED == ((CButton*)GetDlgItem(IDC_CHECK_SHOW_CONSOLE))->GetCheck()) 67 { 68 do{ 69 namedWindow("show the source imag!"); 70 imshow("show the source imag!", m_image); 71 } while (0); 72 } 73 #endif 74 }
小结
现在总结一遍才发现这个东西这么简单,我当时竟然花了2夜+1天!看样子还是要多多总结,特别像MFC这种小知识点特别多,不要因为其简单就不总结,也许多年以后你要用到,还得再重新趟一遍坑就浪费时间了!http://pan.baidu.com/s/1pJ5W6CV(私有)
@beautifulzzzz
2015-10-31 持续更新中~