VS2017配置opencv3.2在MFC单文档中显示图片
转载:https://blog.****.net/qq_22636145/article/details/70185561
最近微软发布了VS2017,增加了很多更实用的功能,其中让笔者兴奋不已的GPU加速功能。只需要切换一个按键便能享受GPU的加速,让程序的速度几何倍数的加快。
可是vs2017比较刚刚发布很多的第三方库和第三方的工具都没有更新过来。其中包括笔者在标题上提到的Opencv3.2以及笔者以前一直使用的C++第三方GUI库QT。可是笔者着实不想放弃这令人着迷的VS2017。于是千方百计,到处翻资料终于在MFC单文档下显示出了opencv的图片。
一,首先要配置好opencv
因为opencv官网中编译的.dll文件并不支持VS2017。所以我们自己要编译opencv的dll文件。这方面网络上有很多资料,主要的过程是在CMake的软件下用vs2017的编译工具编译opencv的源文件再生成其特定的dll文件便可以直接在VS2017下直接使用opencv了。
二,在MFC单文档下先显示图片
VC++的单文档可以直接显示VC++库里面的CImgae类,首先我们在***View.h中添加一个变量CImage image;这里笔者在private下创建的该变量。然后我们在资源文件中添加一个事件处理将它创建在**View.cpp文件中,函数名任意取。
- void CMFCApplication1View::OnOpenImage()
- {
- // TODO: 在此添加命令处理程序代码
- CFileDialog dlg(TRUE/*, _T(".bmp"), _T("*.bmp"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("位图文件(*.bmp)|*.bmp | JEPG文件(*.jpg) | *.jpg || ")*/);
- if (dlg.DoModal() == IDOK)
- {
- if (!image.IsNull())
- {
- image.Destroy();
- }
- image.Load(dlg.GetPathName());
- //CString cstr = dlg.GetPathName();
- str = CStringA(dlg.GetPathName());
- pic = imread(str, CV_LOAD_IMAGE_COLOR);
- Invalidate();
- }
- }
上面便是该函数的全部实现,然后修改OnDraw()函数,如下:
- void CMFCApplication1View::OnDraw(CDC* pDC)
- {
- CMFCApplication1Doc* pDoc = GetDocument();
- ASSERT_VALID(pDoc);
- if (!pDoc)
- return;
- // TODO: 在此处为本机数据添加绘制代码
- if (!image.IsNull())
- {
- image.Draw(pDC->GetSafeHdc(), 0, 0);
- }
- }
修改完成后便可以运行程序点击按钮便可以显示出图片。
三,实现Mat和CImgae之间的转换。
- #include"CImageMat.h"
- void Mat2CImage(Mat & mat, CImage & cimage)
- {
- if (0 == mat.total())
- {
- return;
- }
- int nChannels = mat.channels();
- if ((1 != nChannels) && (3 != nChannels))
- {
- return;
- }
- int nWidth = mat.cols;
- int nHeight = mat.rows;
- cimage.Destroy();
- cimage.Create(nWidth,nHeight,8*nChannels);
- uchar *pucRow;
- uchar *pucImage = (uchar*)cimage.GetBits();
- int nStep = cimage.GetPitch();
- if (1 == nChannels)
- {
- RGBQUAD* rgbquadColorTable;
- int nMaxColors = 256;
- rgbquadColorTable = new RGBQUAD[nMaxColors];
- cimage.GetColorTable(0, nMaxColors, rgbquadColorTable);
- for (int nColor = 0; nColor < nMaxColors; nColor++)
- {
- rgbquadColorTable[nColor].rgbBlue = (uchar)nColor;
- rgbquadColorTable[nColor].rgbGreen = (uchar)nColor;
- rgbquadColorTable[nColor].rgbRed = (uchar)nColor;
- }
- cimage.SetColorTable(0, nMaxColors, rgbquadColorTable);
- delete[]rgbquadColorTable;
- }
- for (int nRow = 0; nRow < nHeight; nRow++)
- {
- pucRow = (mat.ptr<uchar>(nRow));
- for (int nCol = 0; nCol < nWidth; nCol++)
- {
- if (1 == nChannels)
- {
- *(pucImage + nRow * nStep + nCol) = pucRow[nCol];
- } else if (3 == nChannels)
- {
- for (int nCha = 0; nCha < 3; nCha++)
- {
- *(pucImage + nRow * nStep + nCol * 3 + nCha) = pucRow[nCol * 3 + nCha];
- }
- }
- }
- }
- }
- void CImage2Mat(CImage & cimage, Mat & mat)
- {
- if (true == cimage.IsNull())
- {
- return;
- }
- int nChannels = cimage.GetBPP() / 8;
- if ((1 != nChannels) && (3 != nChannels))
- {
- return;
- }
- int nWidth = cimage.GetWidth();
- int nHeight = cimage.GetHeight(); //重建mat
- if (1 == nChannels)
- {
- mat.create(nHeight, nWidth, CV_8UC1);
- } else if(3 == nChannels)
- {
- mat.create(nHeight, nWidth, CV_8UC3);
- } //拷贝数据
- uchar* pucRow;
- //指向数据区的行指针
- uchar* pucImage = (uchar*)cimage.GetBits(); //指向数据区的指针
- int nStep = cimage.GetPitch(); //每行的字节数,注意这个返回值有正有负
- for (int nRow = 0; nRow < nHeight; nRow++)
- {
- pucRow = (mat.ptr<uchar>(nRow));
- for (int nCol = 0; nCol < nWidth; nCol++)
- {
- if (1 == nChannels)
- {
- pucRow[nCol] = *(pucImage + nRow * nStep + nCol);
- }
- else if (3 == nChannels)
- {
- for (int nCha = 0 ; nCha < 3; nCha++)
- {
- pucRow[nCol * 3 + nCha] = *(pucImage + nRow * nStep + nCol * 3 + nCha);
- }
- }
- }
- }
- }
上面的代码是我在一位大神的博客中找到的,实现了Mat和CImage之间的转换,这和QT中显示opencv的图片原理不谋而合,先以opencv的方式读取图片然后将其转换为CImage在显示到单文档上。如下图:
- // MFCApplication1View.h : CMFCApplication1View 类的接口
- //
- #pragma once
- #include<atlimage.h>
- #include"CImageMat.h"
- #include"PI.h"
- class CMFCApplication1View : public CView
- {
- protected: // 仅从序列化创建
- CMFCApplication1View();
- DECLARE_DYNCREATE(CMFCApplication1View)
- // 特性
- public:
- CMFCApplication1Doc* GetDocument() const;
- // 操作
- public:
- // 重写
- public:
- virtual void OnDraw(CDC* pDC); // 重写以绘制该视图
- virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
- protected:
- virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
- virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
- virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
- // 实现
- public:
- virtual ~CMFCApplication1View();
- #ifdef _DEBUG
- virtual void AssertValid() const;
- virtual void Dump(CDumpContext& dc) const;
- #endif
- private:
- CImage image;
- Mat pic;
- std::string str;
- protected:
- // 生成的消息映射函数
- protected:
- DECLARE_MESSAGE_MAP()
- public:
- afx_msg void OnOpenImage();
- afx_msg void OnImageGray();
- afx_msg void Onrefresh();
- afx_msg void OnHelp();
- afx_msg void OnSaveImgae();
- afx_msg void OnAuthor();
- afx_msg void OnThreshold();
- afx_msg void OnSplit();
- };
- #ifndef _DEBUG // MFCApplication1View.cpp 中的调试版本
- inline CMFCApplication1Doc* CMFCApplication1View::GetDocument() const
- { return reinterpret_cast<CMFCApplication1Doc*>(m_pDocument); }
- #endif
- // MFCApplication1View.cpp : CMFCApplication1View 类的实现
- //
- #include "stdafx.h"
- // SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
- // ATL 项目中进行定义,并允许与该项目共享文档代码。
- #ifndef SHARED_HANDLERS
- #include "MFCApplication1.h"
- #endif
- #include "MFCApplication1Doc.h"
- #include "MFCApplication1View.h"
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #endif
- // CMFCApplication1View
- IMPLEMENT_DYNCREATE(CMFCApplication1View, CView)
- BEGIN_MESSAGE_MAP(CMFCApplication1View, CView)
- // 标准打印命令
- ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
- ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
- ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
- ON_COMMAND(ID_32771, &CMFCApplication1View::OnOpenImage)
- ON_COMMAND(ID_32772, &CMFCApplication1View::OnImageGray)
- ON_COMMAND(ID_32773, &CMFCApplication1View::Onrefresh)
- ON_COMMAND(ID_32775, &CMFCApplication1View::OnHelp)
- ON_COMMAND(ID_32776, &CMFCApplication1View::OnSaveImgae)
- ON_COMMAND(ID_32777, &CMFCApplication1View::OnAuthor)
- ON_COMMAND(ID_Menu, &CMFCApplication1View::OnThreshold)
- ON_COMMAND(ID_32779, &CMFCApplication1View::OnSplit)
- END_MESSAGE_MAP()
- // CMFCApplication1View 构造/析构
- CMFCApplication1View::CMFCApplication1View()
- {
- // TODO: 在此处添加构造代码
- }
- CMFCApplication1View::~CMFCApplication1View()
- {
- }
- BOOL CMFCApplication1View::PreCreateWindow(CREATESTRUCT& cs)
- {
- // TODO: 在此处通过修改
- // CREATESTRUCT cs 来修改窗口类或样式
- return CView::PreCreateWindow(cs);
- }
- // CMFCApplication1View 绘制
- void CMFCApplication1View::OnDraw(CDC* pDC)
- {
- CMFCApplication1Doc* pDoc = GetDocument();
- ASSERT_VALID(pDoc);
- if (!pDoc)
- return;
- // TODO: 在此处为本机数据添加绘制代码
- if (!image.IsNull())
- {
- image.Draw(pDC->GetSafeHdc(), 0, 0);
- }
- }
- // CMFCApplication1View 打印
- BOOL CMFCApplication1View::OnPreparePrinting(CPrintInfo* pInfo)
- {
- // 默认准备
- return DoPreparePrinting(pInfo);
- }
- void CMFCApplication1View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
- {
- // TODO: 添加额外的打印前进行的初始化过程
- }
- void CMFCApplication1View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
- {
- // TODO: 添加打印后进行的清理过程
- }
- // CMFCApplication1View 诊断
- #ifdef _DEBUG
- void CMFCApplication1View::AssertValid() const
- {
- CView::AssertValid();
- }
- void CMFCApplication1View::Dump(CDumpContext& dc) const
- {
- CView::Dump(dc);
- }
- CMFCApplication1Doc* CMFCApplication1View::GetDocument() const // 非调试版本是内联的
- {
- ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMFCApplication1Doc)));
- return (CMFCApplication1Doc*)m_pDocument;
- }
- #endif //_DEBUG
- // CMFCApplication1View 消息处理程序
- void CMFCApplication1View::OnOpenImage()
- {
- // TODO: 在此添加命令处理程序代码
- CFileDialog dlg(TRUE/*, _T(".bmp"), _T("*.bmp"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("位图文件(*.bmp)|*.bmp | JEPG文件(*.jpg) | *.jpg || ")*/);
- if (dlg.DoModal() == IDOK)
- {
- if (!image.IsNull())
- {
- image.Destroy();
- }
- image.Load(dlg.GetPathName());
- //CString cstr = dlg.GetPathName();
- str = CStringA(dlg.GetPathName());
- pic = imread(str, CV_LOAD_IMAGE_COLOR);
- Invalidate();
- }
- }
- void CMFCApplication1View::OnImageGray()
- {
- // TODO: 在此添加命令处理程序代码
- //CImage2Mat(image, pic);
- if (pic.channels() == 1) {
- AfxMessageBox(_T("怕是已经灰度化过了"));
- return;
- }
- //cvtColor(pic, pic, CV_BGR2GRAY);
- pi_gray(pic, pic);
- Mat2CImage(pic, image);
- Invalidate();
- }
- void CMFCApplication1View::Onrefresh()
- {
- // TODO: 在此添加命令处理程序代码
- pic = imread(str, CV_LOAD_IMAGE_COLOR);
- Mat2CImage(pic, image);
- Invalidate();
- }
- void CMFCApplication1View::OnHelp()
- {
- // TODO: 在此添加命令处理程序代码
- AfxMessageBox(_T("VS2017下的单文档基于Opencv3.2的基本图形处理!"));
- }
- void CMFCApplication1View::OnSaveImgae()
- {
- // TODO: 在此添加命令处理程序代码
- CFileDialog dlg(FALSE);
- {
- if (dlg.DoModal() == IDOK)
- {
- string savePath = CStringA(dlg.GetPathName());
- imwrite(savePath, pic);
- string info = "图片已存储到:" + savePath + "了!";
- CString cstr(info.c_str());
- AfxMessageBox(cstr);
- }
- }
- }
- void CMFCApplication1View::OnAuthor()
- {
- // TODO: 在此添加命令处理程序代码
- AfxMessageBox(_T("作者:pedro\n时间:2017.4.15"));
- }
- void CMFCApplication1View::OnThreshold()
- {
- if (pic.channels() > 1)
- {
- AfxMessageBox(_T("怕是没有输入单通道图像!"));
- return;
- }
- // TODO: 在此添加命令处理程序代码
- threshold(pic, pic, 0, 255, THRESH_OTSU);
- Mat2CImage(pic, image);
- Invalidate();
- }
- void CMFCApplication1View::OnSplit()
- {
- // TODO: 在此添加命令处理程序代码
- if (pic.channels() < 3)
- {
- AfxMessageBox(_T("怕是没有输入彩色图像!"));
- return;
- }
- vector<Mat> mats;
- split(pic, mats);
- imshow("Blue", mats[0]);
- imshow("Green", mats[1]);
- imshow("Red", mats[2]);
- }