創建基於opencv庫的MFC多文檔圖像處理框架

一、學習參考文件

1、《學習OpenCV》參考書,用OpenCV對圖像進行基本的打開,保存等處理。

2、《MFC多文檔中OpenCV處理圖像打開和保存》http://blog.csdn.net/abcjennifer/article/details/7313711


二、環境搭建

1、安裝VS2013和OpenCV庫

詳細參見:http://blog.csdn.net/lvhao578041381/article/details/18951071

2、在第一次創建的過程出現了LPCTSTRconst char *不能相互轉換的問題。而OpenCV庫中的函數又都不是Unicode的,導致兩種數據類型不能相互轉換。解決辦法:

項目->屬性->配置屬性->字符集->使用多字節字符集

3、在配置之後出現了另外一個問題:error MSB8031: Building an MFC project for a non-Unicode character set MFC在查詢資料後才知道VS2013中把multi-byte character set 支持移除了,解決辦法:

在微軟上下載一個組件Multibyte MFC Library for Visual Studio 2013 安裝完成後基本配置就成功了。


三、框架實現

1、搭建一個多文檔的MFC框架,並按照一般的OpenCV處理程序修改各種目錄


2、在工程中添加Processing.h頭文件和Processing.cpp(將cvload讀到的各種格式的圖像創建爲位圖)

//  Processing.h
//   2010.8.23

#pragma once

#ifndef		PROCESSING
#define		PROCESSING

#include "stdafx.h"
//---------------------------------------------------------

LPBITMAPINFO CtreateMapInfo(IplImage* workImg,int flag);     //創建位圖
 
int  imageType(IplImage* p);								 //返回圖像類型
int  imageClone(IplImage* pi,IplImage** ppo);				 //  複製 IplImage 位圖
int  imageReplace(IplImage* pi,IplImage** ppo);				 //  位圖替換
 
//---------------------------------------------------------
//  常規圖像處理

void Histog(BYTE *buf,int *pg,int Dx,int Dy);
int  BasicGlobalThreshold(int *pg,int start,int end);
int  NextColor(int start,int k,int step);            //  下一彩色號

extern RGBQUAD VgaDefPal[256];

#endif  //PROCESSING
/  Processing.cpp
//    2010.8.23

#include "stdafx.h"
#include "Processing.h"

//---------------------------------------------------------

LPBITMAPINFO CtreateMapInfo(IplImage* workImg,int flag)
{                                           //  建立位圖信息
    BITMAPINFOHEADER BIH={40,1,1,1,8,0,0,0,0,0,0};
	LPBITMAPINFO lpBmi;
	int      wid,hei,bits,colors,i;
	RGBQUAD  ColorTab[256];
  
 	wid =workImg->width;
	hei =workImg->height;
	bits=workImg->depth*workImg->nChannels;

	if (bits>8) colors=0;
	else colors=1<<bits;

	lpBmi=(LPBITMAPINFO) malloc(40+4*colors);
	BIH.biWidth   =wid;
	BIH.biHeight  =hei;
	BIH.biBitCount=(BYTE) bits;
  	memcpy(lpBmi,&BIH,40);                  //  複製位圖信息頭

	if (bits==8) {                          //  256 色位圖
		if (flag==1) {                      //  設置灰階調色板
			for (i=0;i<256;i++) {
				ColorTab[i].rgbRed=ColorTab[i].rgbGreen=
						ColorTab[i].rgbBlue=(BYTE) i;
			}
			memcpy(lpBmi->bmiColors,ColorTab,1024);
		}
		else if (flag==2) {                 //  設置默認調色板
			memcpy(lpBmi->bmiColors,VgaDefPal,1024);
		}
	}
	return(lpBmi);
}

int  imageType(IplImage* p) 
{
  	int	 i,j,k,bpl,n,pg[256];
	BYTE *buf;
  
	k=p->nChannels;
	if (k==1) {                             //  檢查二值圖像
        for (i=0;i<256;i++) pg[i]=0;
		buf=(BYTE*)p->imageData;
		bpl=p->widthStep;
        for (i=0;i<p->height;i++) {
			for (j=0;j<p->width;j++) pg[buf[j]]++;
			buf+=bpl;
		}
        for (i=0,n=0;i<256;i++) {
			if (pg[i]) n++;
		}
        if (n==2) k=-1;                     //  二值圖像
    }
  	return(k);
}

int  imageClone(IplImage* pi,IplImage** ppo)  //  複製 IplImage 位圖
{
	if (*ppo) {
		cvReleaseImage(ppo);                //  釋放原來位圖
	}
 	(*ppo) = cvCloneImage(pi);              //  複製新位圖
	return(1);
}

int  imageReplace(IplImage* pi,IplImage** ppo)  //  位圖替換
{
	if (*ppo) 
		cvReleaseImage(ppo);                //  釋放原來位圖
 	(*ppo) = pi;                            //  位圖換名
	return(1);
}

//---------------------------------------------------------
//  VGA 256色默認調色板數據(省略)
//---------------------------------------------------------
//  常規圖像處理(省略)

3、修改**Doc.h和**Doc.cpp文檔

Doc..h文件

// 生成的消息映射函數
protected:
	DECLARE_MESSAGE_MAP()

public:
	IplImage* pImg;										//圖像指針
	int m_Display;
	BOOL Load(IplImage** pp,LPCTSTR csFilename);		//讀入圖片
	BOOL Save(LPCTSTR csFilename, IplImage* pImg);		//保存圖片
	BOOL OnOpenDocument(LPCTSTR lpszPathName);			//打開文檔
#ifdef SHARED_HANDLERS

Doc..cpp文件

// CdemoDoc 構造/析構

CdemoDoc::CdemoDoc()
:pImg(NULL),
m_Display(0)<pre name="code" class="cpp">// CdemoDoc 命令
BOOL CdemoDoc::Load(IplImage** pp, LPCTSTR csFilename)
{
	IplImage* pImg = NULL;

	pImg = cvLoadImage(csFilename, -1);      //  讀圖像文件(DSCV)  
	if (!pImg) return(false);
	cvFlip(pImg);                           //  將圖像進行翻轉,與 DIB 像素結構一致  
	if (*pp) {
		cvReleaseImage(pp);					//若pp指針已有值,則先將其內存釋放,在進行載入
	}
	(*pp) = pImg;
	m_Display = 0;
	return(true);
}

BOOL CdemoDoc::Save(LPCTSTR csFilename, IplImage* pImg)
{
	int   bl;
	cvFlip(pImg);								 //  恢復原 OpenCV 位圖結構  
	bl = cvSaveImage(csFilename, pImg);          //  圖像存盤  
	return(bl);
}

BOOL CdemoDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
	if (!CDocument::OnOpenDocument(lpszPathName))    return false;
	Load(&pImg, lpszPathName);
	if (pImg) return true;
	return false;
}

{// TODO: 在此添加一次性構造代碼}


4、修改**view.h和**view.cpp文檔

view.h文檔

// 實現
public:
	virtual ~CdemoView();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

protected:
	IplImage* saveImg;
	IplImage* workImg;

	LPBITMAPINFO m_lpBmi;

	int     m_CaptFlag;
	int     m_dibFlag;
	int     m_SaveFlag;
	int     m_ImageType;
// 生成的消息映射函數
protected:
	afx_msg void OnFilePrintPreview();
	afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
	afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
	DECLARE_MESSAGE_MAP()

public:
	virtual void OnInitialUpdate();
	afx_msg void OnSize(UINT nType, int cx, int cy);
	afx_msg void OnFileSaveAs();
	afx_msg void OnColorImageRefresh(); 
	afx_msg void OnRefresh();
	afx_msg void OnConservationImage();
	afx_msg void OnUpdateRefresh(CCmdUI *pCmdUI);
	afx_msg void OnColorImageRefrsh();
};

#ifndef _DEBUG  // demoView.cpp 中的調試版本
inline CdemoDoc* CdemoView::GetDocument() const
   { return reinterpret_cast<CdemoDoc*>(m_pDocument); }
#endif
view.cpp文檔

對於菜單欄,可惜刪除不必要的按鈕,然後按照自己的需要添加相應的按鈕。此處主要是搭建基於OpenCV庫的MFC框架,後續圖像處理算法還在添加。對於

IMPLEMENT_DYNCREATE(CdemoView, CScrollView)

BEGIN_MESSAGE_MAP(CdemoView, CScrollView)
	// 標準打印命令
	ON_COMMAND(ID_FILE_PRINT, &CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CdemoView::OnFilePrintPreview)
	ON_WM_CONTEXTMENU()
	ON_WM_RBUTTONUP()
	ON_COMMAND(ID_FILE_SAVE_AS, &CdemoView::OnFileSaveAs)              //圖像另存的事件
	ON_COMMAND(ID_REFRESH, &CdemoView::OnRefresh)                      //恢復圖像的事件
	ON_COMMAND(ID_CONSERVATION_IMAGE, &CdemoView::OnConservationImage) //保存當前位圖的事件
	ON_UPDATE_COMMAND_UI(ID_REFRESH, &CdemoView::OnUpdateRefresh)
	ON_COMMAND(ID_COLOR_IMAGE_REFRSH, &CdemoView::OnColorImageRefrsh)  //恢復原始圖像的事件
END_MESSAGE_MAP()

// CdemoView 構造/析構

CFile fCapture;
CFileException eCapture;
char pbuf[20];
int  captSetFlag = 0;

CdemoView::CdemoView()
{
	// TODO:  在此處添加構造代碼
	saveImg = NULL;
	workImg = NULL;

	m_lpBmi = 0;

	m_CaptFlag = 0;
	m_dibFlag = 0;
	m_ImageType = 0;

	CSize sizeTotal;
	sizeTotal.cx = sizeTotal.cy = 100;
	SetScrollSizes(MM_TEXT, sizeTotal);

}

CdemoView::~CdemoView()
{
	if (saveImg)
		cvReleaseImage(&saveImg);           //  釋放位圖  
	if (workImg)
		cvReleaseImage(&workImg);

	if (m_lpBmi)
		free(m_lpBmi);                      //  釋放位圖信息  
}

BOOL CdemoView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO:  在此處通過修改
	//  CREATESTRUCT cs 來修改窗口類或樣式

	return CScrollView::PreCreateWindow(cs);
}

// CdemoView 繪製

void CdemoView::OnDraw(CDC* pDC)
{
	CdemoDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO:  在此處爲本機數據添加繪製代碼
	/*if (pDoc->pImg)
	{
		if (pDoc->m_Display == 0)
		{
			saveImg = cvCloneImage(pDoc->pImg);			//要保存的圖片
			workImg = cvCloneImage(pDoc->pImg);			//處理的圖像
			//cvShowImage("test", saveImg);
			m_ImageType = workImg->ID;
		}
	}
	*/
	if (pDoc->pImg)
	{
		if (pDoc->m_Display == 0)
		{
			imageClone(pDoc->pImg, &saveImg);
			m_dibFlag = imageClone(saveImg, &workImg);

			m_ImageType = imageType(workImg);
			m_SaveFlag = m_ImageType;
			pDoc->m_Display = 1;
		}
	}

	if (m_dibFlag) {                        //  DIB 結構改變  
		if (m_lpBmi)
			free(m_lpBmi);
		m_lpBmi = CtreateMapInfo(workImg, m_dibFlag);
		m_dibFlag = 0;

		CSize sizeTotal;
		sizeTotal = CSize(workImg->width, workImg->height);
		SetScrollSizes(MM_TEXT, sizeTotal);
	}
	char* pBits=NULL;
	if (workImg)
		pBits = workImg->imageData;

	if (workImg)
		StretchDIBits(pDC->m_hDC,
		0, 0, workImg->width, workImg->height,
		0, 0, workImg->width, workImg->height,
		pBits, m_lpBmi, DIB_RGB_COLORS, SRCCOPY);
}


// CdemoView 打印


void CdemoView::OnFilePrintPreview()
{
#ifndef SHARED_HANDLERS
	AFXPrintPreview(this);
#endif
}

BOOL CdemoView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// 默認準備
	return DoPreparePrinting(pInfo);
}

void CdemoView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO:  添加額外的打印前進行的初始化過程
}

void CdemoView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO:  添加打印後進行的清理過程
}

void CdemoView::OnRButtonUp(UINT /* nFlags */, CPoint point)
{
	ClientToScreen(&point);
	OnContextMenu(this, point);
}

void CdemoView::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
#ifndef SHARED_HANDLERS
	theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
#endif
}


// CdemoView 診斷

#ifdef _DEBUG
void CdemoView::AssertValid() const
{
	CScrollView::AssertValid();
}

void CdemoView::Dump(CDumpContext& dc) const
{
	CScrollView::Dump(dc);
}

CdemoDoc* CdemoView::GetDocument() const // 非調試版本是內聯的
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CdemoDoc)));
	return (CdemoDoc*)m_pDocument;
}
#endif //_DEBUG


// CdemoView 消息處理程序

void CdemoView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();

	CSize sizeTotal;
	// TODO: calculate the total size of this view  
	sizeTotal.cx = sizeTotal.cy = 100;
	SetScrollSizes(MM_TEXT, sizeTotal);
}

void CdemoView::OnSize(UINT nType, int cx, int cy)
{
	CScrollView::OnSize(nType, cx, cy);

	if (workImg) {                          //  刷新窗口畫面  
		CSize  sizeTotal;
		sizeTotal = CSize(workImg->width, workImg->height);
		SetScrollSizes(MM_TEXT, sizeTotal);   //  設置滾動條  
	}
}

void CdemoView::OnFileSaveAs()
{
	CString csBMP = "BMP Files(*.BMP)|*.BMP|";
	CString csJPG = "JPEG Files(*.JPG)|*.JPG|";
	CString csTIF = "TIF Files(*.TIF)|*.TIF|";
	CString csPNG = "PNG Files(*.PNG)|*.PNG|";
	CString csDIB = "DIB Files(*.DIB)|*.DIB|";
	CString csPBM = "PBM Files(*.PBM)|*.PBM|";
	CString csPGM = "PGM Files(*.PGM)|*.PGM|";
	CString csPPM = "PPM Files(*.PPM)|*.PPM|";
	CString csSR = "SR  Files(*.SR) |*.SR|";
	CString csRAS = "RAS Files(*.RAS)|*.RAS||";

	CString csFilter = csBMP + csJPG + csTIF + csPNG + csDIB
		+ csPBM + csPGM + csPPM + csSR + csRAS;

	CString name[] = { "", "bmp", "jpg", "tif", "png", "dib",
		"pbm", "pgm", "ppm", "sr", "ras", "" };

	CString strFileName;
	CString strExtension;

	CFileDialog FileDlg(false, NULL, NULL, OFN_HIDEREADONLY, csFilter);
	//  文件存盤對話框  
	if (FileDlg.DoModal() == IDOK) {         //  選擇了文件名  
		strFileName = FileDlg.m_ofn.lpstrFile;
		if (FileDlg.m_ofn.nFileExtension == 0) {  //  無文件後綴  
			strExtension = name[FileDlg.m_ofn.nFilterIndex];
			strFileName = strFileName + '.' + strExtension;
			//  加文件後綴  
		}

		CdemoDoc* pDoc = GetDocument();
		ASSERT_VALID(pDoc);
		pDoc->Save(strFileName, workImg);   //  當前畫面存盤  
	}
}

void CdemoView::OnColorImageRefresh()
{
	CdemoDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	pDoc->m_Display = 0;
	Invalidate();
}

void CdemoView::OnRefresh()
{
	// TODO:  在此添加命令處理程序代碼
	m_dibFlag = imageClone(saveImg, &workImg);
	m_ImageType = m_SaveFlag;
	Invalidate();
}

void CdemoView::OnUpdateRefresh(CCmdUI *pCmdUI)
{
	// TODO:  在此添加命令更新用戶界面處理程序代碼
	pCmdUI->Enable((m_CaptFlag != 1) && (m_ImageType != -3));
}


void CdemoView::OnConservationImage()
{
	// TODO:  在此添加命令處理程序代碼
	imageClone(workImg, &saveImg);
	m_SaveFlag = m_ImageType;
}


void CdemoView::OnColorImageRefrsh()
{
	// TODO:  在此添加命令處理程序代碼
	CdemoDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	pDoc->m_Display = 0;
	Invalidate();
}

通過上述幾個步驟,先添加processing.h和processing.cpp文件,裏面包含對圖像進行位圖轉換的函數,然後修改Doc和View文件,在Doc進行文件打開和圖像讀取的操作,在View進行圖像的相關操作。




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