前面的创建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
祝大家一切顺利。