VS2017配置opencv3.2在MFC單文檔中顯示圖片

最近微軟發佈了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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章