在MFC中使用OpenCV(OpenCV教程_基础篇。2.8节例子程序)
1、创建新项目
我的项目取名为MFC_OpenCV_1,在创建项目的第三步中“您希望使用MFC库吗?”,选择“作为静态的DLL”,其他步骤都选默认选项。
2、设置OpenCV环境变量
工程—>设置—>“C/C++”选项卡,在“分类”选项中,选择“预编译器”,在“附加包含路径”中填写OpenCV的路径(用英文字符的逗号隔开),如我的路径为:
C:/Program Files/OpenCV/cv/include,
C:/Program Files/OpenCV/cxcore/include,
C:/Program Files/OpenCV/otherlibs/_graphics/include,
C:/Program Files/OpenCV/otherlibs/highgui
工程—>设置—>“连接”选项卡,在“分类”选项中,选择“输入”,在“对象/库模板”中输入:cv.lib cxcore.lib highgui.lib (空格隔开)
“附加库路径”中输入:C:/Program Files/OpenCV/lib
值得注意的是,因为OpenCV的版本不同,在../OpenCV/lib路径下的lib文件也有微小区别,比如有的版本中各个lib文件中多加了一个d,故在“对象/库模板”中就要输入:cvd.lib cxcored.lib highguid.lib (空格隔开),如何知道呢?编译一下就明白了!
3、分步创建例程
在File View面板中的MFC_OpenCV_1.h中的#include "resource.h"下面添加一下代码:
#include "cv.h" #include "HighGUI.h" #define IMAGE_WIDTH 256 //这里说明程序用到的程序必须是256*256大小的图片,否则会有错。 #define IMAGE_HEIGHT 256 //可以在这里改变图片参数,以适应自己用到图片的大小 #define IMAGE_CHANNELS 3
在Class View窗口中,为CMFC_OpenCV_1Dlg头文件中添加成员变量(双击CMFC_OpenCV_1Dlg即可打开):
public: IplImage* TheImage;
再添加一下代码:
protected: BITMAPINFO* bmi; BITMAPINFOHEADER* bmih; RGBQUAD* palette; unsigned int buffer[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256];
双击对话框初始化函数OnInitDialog(),在// TODO: Add extra initialization here下面添加代码:
//创建IPL图像 CvSize ImgSize; ImgSize.width = IMAGE_WIDTH; ImgSize.height = IMAGE_HEIGHT; TheImage = cvCreateImage(ImgSize,IPL_DEPTH_8U,IMAGE_CHANNELS); //在对话框中显示一幅创建的图像 if (TheImage->nChannels == 1) //灰度图像 { float dx = TheImage->width/256.0f; for (int w = 0; w<TheImage->width;w++) { for (int h = 0;h<TheImage->height;h++) { //复制数据到IPL TheImage->imageData[TheImage->height*w+h] = (char)(w/dx); } } } else if (TheImage->nChannels == 3) //对RGB图像 { IplImage* temp = cvCreateImage(ImgSize,IPL_DEPTH_8U,1); int h,w; float dx = temp->width/256.0f; for (w= 0; w<temp->width;w++) { for (h=0;h<temp->height;h++) { temp->imageData[temp->height*w+h] = (char)(w/dx); } } cvSetImageCOI(TheImage,1);//选择蓝色通道 cvCopy(temp,TheImage); for (w= 0; w<temp->width;w++) { for (h=0;h<temp->height;h++) { temp->imageData[temp->height*w+h] = (char)(256- w/dx); } } cvSetImageCOI(TheImage,2);//选择绿色通道 cvCopy(temp,TheImage); for (w= 0; w<temp->width;w++) { for (h=0;h<temp->height;h++) { temp->imageData[temp->height*w+h] = (char)(w/dx); } } cvSetImageCOI(TheImage,3);//选择红色通道 cvCopy(temp,TheImage); cvReleaseImage(&temp); } //初始化BMP显示缓存 bmi = (BITMAPINFO* )buffer; bmih = &(bmi->bmiHeader); memset(bmih,0,sizeof(*bmih)); bmih->biSize = sizeof(BITMAPINFOHEADER); bmih->biWidth =IMAGE_WIDTH; bmih->biHeight = -IMAGE_HEIGHT; bmih->biPlanes = 1; bmih->biCompression = BI_RGB; bmih->biBitCount = 8*TheImage->nChannels; palette= bmi->bmiColors; if (TheImage->nChannels == 1) { for (int i= 0;i<256;i++) { palette[i].rgbBlue= palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i; palette[i].rgbReserved = 0; } }
为CMFC_OpenCV_1Dlg添加成员函数:
public:
void DisplayMyData();
并添加代码:
void CMFC_OpenCV_1Dlg::DisplayMyData() { CPaintDC dc(this); CDC* pDC=&dc; int res=StretchDIBits( pDC->GetSafeHdc(), //hdc 0, //XDest 0, //YDest int(IMAGE_WIDTH), //nDestWidth int(IMAGE_HEIGHT), //nDestHeight 0, //XSrc 0, //YSrc IMAGE_WIDTH, //src x dims IMAGE_HEIGHT, //src y dims TheImage->imageData,//array of DIB bits (BITMAPINFO*)bmi, //bitmap infomation DIB_RGB_COLORS, //RGB or palette indexes SRCCOPY); //光栅操作码 //更新窗口,重新绘制 RedrawWindow( NULL, NULL, RDW_INVALIDATE ); }
然后在OnPaint()函数中调用它:
。。。。。。。 else { DisplayMyData(); CDialog::OnPaint(); }
然后在类CMFC_OpenCV_1的成员函数InitInstance()中调用释放图像内存的函数
if (nResponse == IDOK) { // TODO: Place code here to handle when the dialog is // dismissed with OK cvReleaseImage(&dlg.TheImage); }
4、读入图像并显示处理
添加一个新类,用类向导:
右击MFC_OpenCV_1 classes—>new class,选择Generic Class,类名为MyIplClass,如图:
然后双击CMFC_OpenCV_1APP,在打开的头文件中,#include "resource.h" // main symbols下方添加头文件:
#include "MyIplClass.h"
同时将这里原来的代码:
#include "cv.h" #include "HighGUI.h" #define IMAGE_WIDTH 256//这里说明程序用到的程序必须是256*256大小的图片,否则会有错。 #define IMAGE_HEIGHT 256 //可以在这里改变图片参数,以适应自己用到图片的大小 #define IMAGE_CHANNELS 3
转移到新建的类MyIplClass的头文件中,代码如下:
// MyIplClass.h: interface for the MyIplClass class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_MYIPLCLASS_H__64EAB832_8C9A_4B0B_B3DD_48F44840B147__INCLUDED_) #define AFX_MYIPLCLASS_H__64EAB832_8C9A_4B0B_B3DD_48F44840B147__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include "cv.h" #include "HighGUI.h" #define IMAGE_WIDTH 256//这里说明程序用到的程序必须是256*256大小的图片,否则会有错。 #define IMAGE_HEIGHT 256 //可以在这里改变图片参数,以适应自己用到图片的大小 #define IMAGE_CHANNELS 3 class MyIplClass { 。。。。。。
为MyIplClass添加成员变量:
public:
IplImage* m_Ipl;
分别在MyIplClass的构造函数和析构函数中添加代码:
MyIplClass::MyIplClass() { //Create the IPL image m_Ipl = cvCreateImage(cvSize(IMAGE_WIDTH,IMAGE_HEIGHT),IPL_DEPTH_8U,IMAGE_CHANNELS); } MyIplClass::~MyIplClass() { cvReleaseImage(&m_Ipl); //释放内存 }
在为MyIplClass添加两个成员函数:
public:
void GetIplData(IplImage* ipl);
void LoadBMP(CString FileName);
并添加代码:
void MyIplClass::GetIplData(IplImage* ipl) { memcpy(ipl->imageData,m_Ipl->imageData,m_Ipl->imageSize); } void MyIplClass::LoadBMP(CString FileName) { //调用OpenCV中的highgui库函数cvLoadImage读取图像 m_Ipl = cvLoadImage(FileName,1); }
现在在Resource View面板中,打开ID为IDD_MFC_OPENCV_1_DIALOG的界面,添加一个按钮,设置属性值:
ID:IDC_PROCESS,标题:Process
双击该按钮,在自动生成的OnProcess函数中添加代码如下:
void CMFC_OpenCV_1Dlg::OnProcess() { // TODO: Add your control notification handler code here MyIplClass *Img = new MyIplClass; CString filename; //this file should be part of the OpenCV kit filename = "F://StdSoft//OpenCV//fruits.bmp"; Img->LoadBMP(filename); Img->GetIplData(TheImage); Img->ProcessIpl(TheImage); delete Img; RedrawWindow(NULL,NULL,RDW_INVALIDATE); //Force update of dialog }
现在要对前面读入的图像进行边缘化处理,为MyIplClass添加成员函数:
public:
void ProcessIpl(IplImage* Img);
并为该函数添加代码:
void MyIplClass::ProcessIpl(IplImage *Img) { 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(Img,gray,CV_BGR2GRAY); //Run the edge detector on gryscale cvCanny(gray,edge,30,100,3); cvCvtColor(edge,Img,CV_GRAY2BGR); //save result //这句解除后有错,http://www.opencv.org.cn/forum/viewtopic.php?f=1&t=5108&start=0&st=0&sk=t&sd=a // cvCopyImage(Img,m_Ipl); //release image cvReleaseImage(&gray); cvReleaseImage(&edge); }
再在CMFC_OpenCV_1Dlg的OnProcess()函数中,在 Img->GetIplData(TheImage);下方调用该处理函数:
Img->ProcessIpl(TheImage);
搞定!运行结果如下: