這個設計的來源是計算照片中番茄葉片的面積,這其中涉及到灰度變換、葉片輪廓的提取和輪廓內像素點數的計算。基本的流程是讀取圖片->圖片預處理->灰度變換->圖像分析->邊緣檢測->平滑處理->填充->中值濾波->計算像素。原本是通過編寫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=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);
//將圖片繪制到顯示器的制定區域內
ReleaseDC(pDC);
以上准備工作完成,下面就是加載圖片,利用縮放函數縮放至合適的大小後,利用顯示函數顯示在控件的合適區域,雙擊加載按鈕,出現響應函數OnButton1ReadImg() ,加載代碼如下:
CFileDialog dlg(TRUE,_T("*bmp"),NULL,OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY,_T("image 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);//調用顯示圖片函數
以上就實現了圖片顯示在控件的合適位置。關於圖片算法的實現,將出現在下一章節。