这个设计的来源是计算照片中番茄叶片的面积,这其中涉及到灰度变换、叶片轮廓的提取和轮廓内像素点数的计算。基本的流程是读取图片->图片预处理->灰度变换->图像分析->边缘检测->平滑处理->填充->中值滤波->计算像素。原本是通过编写C++的类实现图像的处理,但是在实现的过程中,发现这个类的编写实在是超出本人能力,特别是涉及到调色板的部分,十分头疼。后来发现了OpenCV,顿觉眼前一亮,它是一个跨平台的计算机视觉库,实现了图像处理和计算机视觉的算法,几乎把我们要用到的算法都写好了,直接调用函数就行了。
首先,需要安装OpenCV,然后将它的库函数添加到VC6.0的目录下,具体方法是Tool->option->directoties,在source file中添加OpenCV中的SRC文件,在Library file下添加BIN文件,在Include file下添加各Include,编译的时候要将lib文件添加进去,具体的路径是project->setting->link,添加的链接库是cv.lib cvaux.lib highgui.lib cvcam.lib cxcore.lib 。
好了下面就是coding了,本程序是用MFC编写的,界面比较简单,内容只有一个图片显示窗口,一个加载图片按钮,一个计算面积按钮,一个下拉选项用来选择过滤阀值,三个显示数据控件。首先添加一个picture控件,ID定义为IDC_ShowImg,用于显示图片。添加一个按钮用于加载图片。MFC是以消息为基础,事件为驱动的,所以,要实现某个功能,则必须有对应的消息和相应函数。用picture控件的好处是并不局限于只能添加位图,其他如jpg的图片也是可以的。还有一个问题,加载了图片显示在控件的哪个部分呢,所以还需要另外一个函数,用于控制放置图片的位置及进行图片的缩放,肯定是不能让图片原状态显示,因此,首先在dlg类中添加一个void类型的ResizeImage(IplImage *img)函数,将图片缩放至最大边256,code如下:
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的正中部位,需要计算坐标
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);
代码包括清空图片区域,用于加载下一副图片。然后加载显示函数,用于对加载图片进行显示,在dlg类中添加void类型的函数ShowImage(IplImage *img, UINT ID),其中img指向要显示的图片,ID是要显示的控件的ID,本例中就是IDC_ShowImg,然后写下如下代码,首先获取显示区域大小,然后借助设备描述表进行显示:
CDC *pDC=GetDlgItem(ID)->GetDC();//获得显示空间的DC
HDC hDC=pDC->GetSafeHdc();
//获取hDC进行绘图操作
CRect rect;
GetDlgItem(ID)->GetClientRect(&rect);
int rw=rect.right-rect.left;
int rh=;
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);
//将图片绘制到显示器的制定区域内
ReleaseDC(pDC);
以上准备工作完成,下面就是加载图片,利用缩放函数缩放至合适的大小后,利用显示函数显示在控件的合适区域,双击加载按钮,出现响应函数OnButton1ReadImg() ,加载代码如下:
CFileDialog dlg(TRUE,_T("*bmp"),NULL,OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY,_T("p_w_picpath files(*.bmp;*.jpg)|*.bmp;*.jpg|All Files(*.*)|*.*||"),NULL);
//选项图片的约定
dlg.m_ofn.lpstrTitle=_T("Open Image");//打开文件对话框的标题名
if(dlg.DoModal()!=IDOK)
//判断是否已经获得图片
return;
CString mPath=dlg.GetPathName();
IplImage* ipl=cvLoadImage(mPath,1);
IplImage* pic=cvLoadImage(mPath,0);
if(!ipl)
return;
if(TheImage)
//对上一幅显示的图片清零
cvZero(TheImage);
//cvNamedWindow("origin",CV_WINDOW_AUTOSIZE);
//cvShowImage("origin",ipl);
ResizeImage(ipl);//对读入的图片进行缩放使其长宽最大值刚好为256,再复制到TheImage中
ShowImage(TheImage,IDC_ShowImg);//调用显示图片函数
以上就实现了图片显示在控件的合适位置。关于图片算法的实现,将出现在下一章节。
















