前面的創建MFC工程和頁面的設計,這一篇就不在多聊,以後有時間會把這一步單獨做一個介紹。本篇直接從代碼開始:
因爲實現邊緣檢測,所以先在EdgesProcess.h中把頭文件添加進來。如下圖:
在MFC應用程序中我們經常使用類視圖,在這裏面可以添加函數和變量。如圖:
之後在類視圖中CEdgesProcessDlg右鍵添加變量TheImage,變量類型爲IplImage*,變量類型是可以手動添加和修改的。如圖:
之後還是在類視圖中雙擊OnInitDialog(),在提示:“// TODO: Add extra initialization here”的下面添加 TheImage 的初始化代碼:
CvSize ImgSize;
ImgSize.height = IMAGE_HEIGHT;
ImgSize.width = IMAGE_WIDTH;
TheImage = cvCreateImage( ImgSize, IPL_DEPTH_8U, IMAGE_CHANNELS );
然後按照相同的方法添加函數void ShowImage( IplImage* img, UINT ID ) 和 void ResizeImage(IplImage* img)
void CEdgesProcessDlg::ResizeImage(IplImage* img)
{
// 讀取圖片的寬和高
int w = img->width;
int h = img->height;
// 找出寬和高中的較大值者
int max = (w > h)? w: h;
// 計算將圖片縮放到TheImage區域所需的比例因子
float scale = (float) ( (float) max / 256.0f );
// 縮放後圖片的寬和高
int nw = (int)( w/scale );
int nh = (int)( h/scale );
// 爲了將縮放後的圖片存入 TheImage 的正中部位,需計算圖片在 TheImage 左上角的期望座標值
int tlx = (nw > nh)? 0: (int)(256-nw)/2;
int tly = (nw > nh)? (int)(256-nh)/2: 0;
// 設置 TheImage 的 ROI 區域,用來存入圖片 img
cvSetImageROI( TheImage, cvRect( tlx, tly, nw, nh) );
// 對圖片 img 進行縮放,並存入到 TheImage 中
cvResize( img, TheImage );
// 重置 TheImage 的 ROI 準備讀入下一幅圖片
cvResetImageROI( TheImage );
}
void CEdgesProcessDlg::ShowImage( IplImage* img, UINT ID ) // ID 是Picture Control控件的ID號
{
CDC* pDC = GetDlgItem( IDC_ShowImg )->GetDC(); // 獲得顯示控件的 DC
HDC hDC = pDC ->GetSafeHdc(); // 獲取 HDC(設備句柄) 來進行繪圖操作
CRect rect;
GetDlgItem(IDC_ShowImg)->GetClientRect( &rect );
int rw = rect.right - rect.left; // 求出圖片控件的寬和高
int rh = rect.bottom - rect.top;
int iw = img->width; // 讀取圖片的寬和高
int ih = img->height;
int tx = (int)(rw - iw)/2; // 使圖片的顯示位置正好在控件的正中
int ty = (int)(rh - ih)/2;
SetRect( rect, tx, ty, tx+iw, ty+ih );
CvvImage cimg;
cimg.CopyOf( img ); // 複製圖片
cimg.DrawToHDC( hDC, &rect ); // 將圖片繪製到顯示控件的指定區域內
cvWaitKey(0);
ReleaseDC( pDC );
}
還在類視圖中,雙擊 OnPaint,在 if(IsIconic())…的 else 裏添加以下代碼,用來重繪窗口:
CDialog::OnPaint(); // 重繪對話框
CDialog::UpdateWindow(); // 更新windows窗口,如果無這步調用,圖片顯示還會出現問題
ShowImage( TheImage, IDC_ShowImg ); // 重繪圖片函數
在CEdgesprocessApp下雙擊Initnstance,在兩個“// TODO: Place code here to handle when the dialog is…”下面添加:
cvReleaseImage( &dlg.TheImage );
接下來,要轉到GUI界面了,就是最直觀的圖形界面:添加兩個按鈕的點擊事件:OnBnClickedReadimg和OnBnClickedEdgesDetcet。直接雙擊按鈕就可以了。添加以下代碼:
void CEdgesProcessDlg::OnBnClickedReadimg()
{
// TODO: 在此添加控件通知處理程序代碼
IplImage* ipl = cvLoadImage( "E:\\beijing.bmp", 1 ); // 讀取圖片、緩存到一個局部變量 ipl 中
if( !ipl ) // 判斷是否成功載入圖片
return;
if( TheImage ) // 對上一幅顯示的圖片數據清零
cvZero( TheImage );
ResizeImage( ipl ); // 對讀入的圖片進行縮放,使其寬或高最大值者剛好等於 256,再複製到 TheImage 中
ShowImage( TheImage, IDC_ShowImg ); // 調用顯示圖片函數
cvReleaseImage( &ipl ); // 釋放 ipl 佔用的內存
}
void CEdgesProcessDlg::OnBnClickedEdgedetect()
{
// TODO: 在此添加控件通知處理程序代碼
IplImage *gray = 0, *edge = 0;
gray = cvCreateImage( cvSize(IMAGE_WIDTH, IMAGE_HEIGHT), IPL_DEPTH_8U, 1 );
edge = cvCreateImage( cvSize(IMAGE_WIDTH, IMAGE_HEIGHT), IPL_DEPTH_8U, 1 );
cvCvtColor( TheImage, gray, CV_BGR2GRAY );
cvCanny( gray, edge, 30, 100, 3 );
cvCvtColor( edge, TheImage, CV_GRAY2BGR );
ShowImage( TheImage, IDC_ShowImg ); // 調用顯示圖片函數
cvReleaseImage( &gray );
cvReleaseImage( &edge );
}
效果圖:
參考:
http://www.laganiere.name/opencv1Tut/index.shtml
http://blog.csdn.net/chenyusiyuan/article/details/4744097
祝大家一切順利。