最近微軟發佈了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]);
}
轉:https://blog.csdn.net/qq_22636145/article/details/70185561