一、學習參考文件
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、在第一次創建的過程出現了LPCTSTR與const 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進行圖像的相關操作。