OpenCV統計米粒數目-計算聯通區域的個數及聯通區域內畫素的個數
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
基於對話方塊的程式。
實現介面:
開啟圖片的訊息響應函式:
void CcountRiceDlg::OnBnClickedOpen(){ // TODO: 在此新增控制元件通知處理程式程式碼 TCHAR szFilters[]=_T("BMP Files (*.bmp)|*.png|All Files (*.*)|*.*||"); CFileDialog dlg(TRUE,_T("All Files(*.*)"),_T("*.*"),OFN_OVERWRITEPROMPT,szFilters); if (dlg.DoModal()) { CString path=dlg.GetPathName(); int sizeOfString = (path.GetLength() + 1 ); LPCTSTR lpsz = new TCHAR[sizeOfString]; lpsz =(LPCTSTR)path; CRect outputRect; GetDlgItem(IDC_ORIGIN_PIC)->GetWindowRect(&outputRect); //檢索指定的對話方塊中的控制元件控制代碼;返回指定視窗的邊框矩形的尺寸 if (m_cvImage->Load(lpsz)) { m_hasLoadImg=true ; m_cvImage->Show(GetDlgItem(IDC_ORIGIN_PIC)->GetDC()->GetSafeHdc(),0,0,outputRect.Width(),outputRect.Height()); } }}
圖片處理的訊息響應函式:
void CcountRiceDlg::OnBnClickedProcess(){ // TODO: 在此新增控制元件通知處理程式程式碼 if (!m_hasLoadImg) { OnBnClickedOpen(); } CvvImage* tmp=new CvvImage; CvvImage* backImage=new CvvImage; IplConvKernel* element=cvCreateStructuringElementEx(4,4,1,1,CV_SHAPE_ELLIPSE,0);//形態學結構指標[建立結構元素,4列4行,橢圓形】 tmp->CopyOf(*m_cvImage); backImage->CopyOf(*m_cvImage); cvErode(m_cvImage->GetImage(),tmp->GetImage(),element,10);//腐蝕 cvDilate(tmp->GetImage(),backImage->GetImage(),element,10);//這裡得到的backImage是背景影象 cvSub(m_cvImage->GetImage(),backImage->GetImage(),tmp->GetImage(),0);//用原始影象減去背景影象,tmp是結果影象 cvThreshold(tmp->GetImage(),backImage->GetImage(),50,255,CV_THRESH_BINARY);//這裡得到的backImage是二值圖 CvMemStorage* stor=cvCreateMemStorage(0); CvSeq * cont=cvCreateSeq(CV_SEQ_ELTYPE_POINT,sizeof(CvSeq),sizeof(CvPoint),stor); IplImage* dst; dst = cvCreateImage( cvGetSize(backImage->GetImage()), backImage->GetImage()->depth, 1 ); cvCvtColor(backImage->GetImage(), dst, CV_BGR2GRAY );//3通道->1通道 int numberOfObject=cvFindContours(dst,stor,&cont,sizeof(CvContour),CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE,cvPoint(0,0)); double maxArea=0; double tmpArea=0; CvSeq* maxAreaRice=0; double maxLength=0; double tmpLength=0; CvSeq* maxLengthRice=0; //cvThreshold(dst,dst,0,255,CV_THRESH_BINARY);//在畫輪廓前先把影象變成白色 IplImage* dst_contours = cvCreateImage( cvGetSize(dst), dst->depth, dst->nChannels); cvThreshold( dst_contours, dst_contours ,0, 0, CV_THRESH_BINARY ); //在畫輪廓前先把影象變成黑色。 threshold=0,pixel>0,pixel = 0. for (;cont;cont=cont->h_next) { tmpArea=fabs(cvContourArea(cont,CV_WHOLE_SEQ)); if(tmpArea>maxArea) { maxArea=tmpArea; maxAreaRice=cont; } tmpLength=cvArcLength(cont); if (tmpLength>maxLength) { maxLength=tmpLength; maxLengthRice=cont; } if (tmpArea>10) { cvDrawContours(dst_contours,cont,CV_RGB(0,0,255),CV_RGB(255,0,0),0,1,8,cvPoint(0,0));//在影象上繪製外部和內部輪廓. //【影象,第一個輪廓指標,外輪廓的顏色,內輪廓的顏色,畫輪廓的最大層數(如果是0,只繪製contour),線條粗細,線條型別,按給定值移動所有點的座標 】 } } CRect outputRect; GetDlgItem(IDC_PROCESSED_PIC)->GetWindowRect(&outputRect); m_ProcessedImage->CopyOf(dst_contours,1); CRect rect; SetRect( rect, 0, 0, outputRect.Width(),outputRect.Height() ); m_ProcessedImage->DrawToHDC(GetDlgItem(IDC_PROCESSED_PIC)->GetDC()->GetSafeHdc(),&rect); m_result.Format(_T("米粒數目為: %d 個\n米粒最大面積: %f\n米粒最大周長: %f"),numberOfObject,maxArea,maxLength); UpdateData(FALSE); cvReleaseImage(&dst); cvReleaseImage(&dst_contours); cvReleaseMemStorage(&stor);}
退出按鈕的訊息響應,過載了一下 Dialog的 OnCancel 函式:
void CcountRiceDlg::OnBnClickedExit(){ // TODO: 在此新增控制元件通知處理程式程式碼 CDialog::OnCancel();}
記得在解構函式裡面釋放圖片哦~
CcountRiceDlg::~CcountRiceDlg(){ if (m_cvImage) { delete m_cvImage; } if (m_ProcessedImage) { delete m_ProcessedImage; }}
在 DoDataExchange 函式裡面, DDX_Text(pDX, IDC_RESULT, m_result);
是將 CString 型別的m_result 將 控制元件 IDC_RESULT 關聯起來~然後,就可以在static text 顯示字串了。。。。。
控制元件和變數的關聯是在 DoDataExchange 中顯示的 : DDX_Text(pDX, IDC_RESULT, m_result);
方法VC classwizard -- member variables 。vs 中是在控制元件上右擊--新增變數~~~是吧
在 OnInitDialog()
中新增~
m_cvImage=new CvvImage;
m_ProcessedImage=new CvvImage;
m_hasLoadImg=false;
在OnPaint() 的
else 中新增:
CDialog::OnPaint(); CRect outputRect; GetDlgItem(IDC_PROCESSED_PIC)->GetWindowRect(&outputRect); m_ProcessedImage->Show(GetDlgItem(IDC_PROCESSED_PIC)->GetDC()->GetSafeHdc(),0,0,outputRect.Width(),outputRect.Height()); GetDlgItem(IDC_ORIGIN_PIC)->GetWindowRect(&outputRect); CRect rect; SetRect( rect, 0, 0, outputRect.Width(),outputRect.Height() ); m_cvImage->DrawToHDC(GetDlgItem(IDC_ORIGIN_PIC)->GetDC()->GetSafeHdc(),&rect);
【paint 函式什麼時候被呼叫呢?當註釋掉 OnBnClickedOpen() 中顯示圖片用的是show函式 時,沒有影響~~~~
WM_PAINT訊息僅用於以下兩種情況:
1. 當用戶移動視窗或顯示視窗,或使用者改變視窗的大小,或滾動視窗使用者區時,Windows會向視窗函式傳送WM_PAINT訊息。
2. 當Windows關閉覆蓋視窗部分割槽域的對話方塊時,以及選單下拉出來又被釋放時,視窗使用者區被臨時覆蓋,系統會試圖恢復顯示區域,可能向視窗函式傳送一條WM_PAINT訊息,要求應用程式重新整理其使用者區。
這兩種情況下將使MFC呼叫OnPaint處理函式。也僅有這兩種情況,檢視物件具有一個OnPaint處理函式。
開始點選 [開啟圖片] 時,算是哪種情況呢?%>_<% 】
核心程式碼:
int numberOfObject=cvFindContours(dst,stor,&cont,sizeof(CvContour),CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE,cvPoint(0,0));
Area=fabs(cvContourArea(cont,CV_WHOLE_SEQ));
Length=cvArcLength(cont)
圈圈的個數就是 連通區域的個數了
關於LPCTSTR轉換為const char * ??
如何將LPCTSTR轉換為const char * ?? 專案--屬性--配置屬性--字符集 改為使用多位元組 居然可以這麼簡單~~~【LPCTSTR 1、在非UNICODE環境下為 const char * 2、在UNICODE環境下為 const unsigned short * so,需要將寬字元轉換為多位元組】
可是,Release版本下,這個還是通不過,網上查了好多,可素,感覺亂七八糟的,誰有簡單又方便的方案????
這個應該自己設計演算法來實現的~~~~~哎~~~菜鳥啊菜鳥,這個才2行核心程式碼而已啊,趕緊學著自己寫一個吧%>_<%
具體程式碼: http://download.csdn.net/detail/timidsmile/3671517
給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow
基於對話方塊的程式。
實現介面:
開啟圖片的訊息響應函式:
void CcountRiceDlg::OnBnClickedOpen(){ // TODO: 在此新增控制元件通知處理程式程式碼 TCHAR szFilters[]=_T("BMP Files (*.bmp)|*.png|All Files (*.*)|*.*||"); CFileDialog dlg(TRUE,_T("All Files(*.*)"),_T("*.*"),OFN_OVERWRITEPROMPT,szFilters); if (dlg.DoModal()) { CString path=dlg.GetPathName(); int sizeOfString = (path.GetLength() + 1); LPCTSTR lpsz = new TCHAR[sizeOfString]; lpsz =(LPCTSTR)path; CRect outputRect; GetDlgItem(IDC_ORIGIN_PIC)->GetWindowRect(&outputRect); //檢索指定的對話方塊中的控制元件控制代碼;返回指定視窗的邊框矩形的尺寸 if (m_cvImage->Load(lpsz)) { m_hasLoadImg=true; m_cvImage->Show(GetDlgItem(IDC_ORIGIN_PIC)->GetDC()->GetSafeHdc(),0,0,outputRect.Width(),outputRect.Height()); } }}
圖片處理的訊息響應函式:
void CcountRiceDlg::OnBnClickedProcess(){ // TODO: 在此新增控制元件通知處理程式程式碼 if (!m_hasLoadImg) { OnBnClickedOpen(); } CvvImage* tmp=new CvvImage; CvvImage* backImage=new CvvImage; IplConvKernel* element=cvCreateStructuringElementEx(4,4,1,1,CV_SHAPE_ELLIPSE,0);//形態學結構指標[建立結構元素,4列4行,橢圓形】 tmp->CopyOf(*m_cvImage); backImage->CopyOf(*m_cvImage); cvErode(m_cvImage->GetImage(),tmp->GetImage(),element,10);//腐蝕 cvDilate(tmp->GetImage(),backImage->GetImage(),element,10);//這裡得到的backImage是背景影象 cvSub(m_cvImage->GetImage(),backImage->GetImage(),tmp->GetImage(),0);//用原始影象減去背景影象,tmp是結果影象 cvThreshold(tmp->GetImage(),backImage->GetImage(),50,255,CV_THRESH_BINARY);//這裡得到的backImage是二值圖 CvMemStorage* stor=cvCreateMemStorage(0); CvSeq * cont=cvCreateSeq(CV_SEQ_ELTYPE_POINT,sizeof(CvSeq),sizeof(CvPoint),stor); IplImage* dst; dst = cvCreateImage( cvGetSize(backImage->GetImage()), backImage->GetImage()->depth, 1 ); cvCvtColor(backImage->GetImage(), dst, CV_BGR2GRAY );//3通道->1通道 int numberOfObject=cvFindContours(dst,stor,&cont,sizeof(CvContour),CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE,cvPoint(0,0)); double maxArea=0; double tmpArea=0; CvSeq* maxAreaRice=0; double maxLength=0; double tmpLength=0; CvSeq* maxLengthRice=0; //cvThreshold(dst,dst,0,255,CV_THRESH_BINARY);//在畫輪廓前先把影象變成白色 IplImage* dst_contours = cvCreateImage( cvGetSize(dst), dst->depth, dst->nChannels); cvThreshold( dst_contours, dst_contours ,0, 0, CV_THRESH_BINARY ); //在畫輪廓前先把影象變成黑色。 threshold=0,pixel>0,pixel = 0. for (;cont;cont=cont->h_next) { tmpArea=fabs(cvContourArea(cont,CV_WHOLE_SEQ)); if(tmpArea>maxArea) { maxArea=tmpArea; maxAreaRice=cont; } tmpLength=cvArcLength(cont); if (tmpLength>maxLength) { maxLength=tmpLength; maxLengthRice=cont; } if (tmpArea>10) { cvDrawContours(dst_contours,cont,CV_RGB(0,0,255),CV_RGB(255,0,0),0,1,8,cvPoint(0,0));//在影象上繪製外部和內部輪廓. //【影象,第一個輪廓指標,外輪廓的顏色,內輪廓的顏色,畫輪廓的最大層數(如果是0,只繪製contour),線條粗細,線條型別,按給定值移動所有點的座標 】 } } CRect outputRect; GetDlgItem(IDC_PROCESSED_PIC)->GetWindowRect(&outputRect); m_ProcessedImage->CopyOf(dst_contours,1); CRect rect; SetRect( rect, 0, 0, outputRect.Width(),outputRect.Height() ); m_ProcessedImage->DrawToHDC(GetDlgItem(IDC_PROCESSED_PIC)->GetDC()->GetSafeHdc(),&rect); m_result.Format(_T("米粒數目為: %d 個\n米粒最大面積: %f\n米粒最大周長: %f"),numberOfObject,maxArea,maxLength); UpdateData(FALSE); cvReleaseImage(&dst); cvReleaseImage(&dst_contours); cvReleaseMemStorage(&stor);}
退出按鈕的訊息響應,過載了一下 Dialog的 OnCancel 函式:
void CcountRiceDlg::OnBnClickedExit(){ // TODO: 在此新增控制元件通知處理程式程式碼 CDialog::OnCancel();}
記得在解構函式裡面釋放圖片哦~
CcountRiceDlg::~CcountRiceDlg(){ if (m_cvImage) { delete m_cvImage; } if (m_ProcessedImage) { delete m_ProcessedImage; }}
在 DoDataExchange 函式裡面, DDX_Text(pDX, IDC_RESULT, m_result);
是將 CString 型別的m_result 將 控制元件 IDC_RESULT 關聯起來~然後,就可以在static text 顯示字串了。。。。。
控制元件和變數的關聯是在 DoDataExchange 中顯示的 : DDX_Text(pDX, IDC_RESULT, m_result);
方法VC classwizard -- member variables 。vs 中是在控制元件上右擊--新增變數~~~是吧
在 OnInitDialog()
中新增~
m_cvImage=new CvvImage;
m_ProcessedImage=new CvvImage;
m_hasLoadImg=false;
在OnPaint() 的
else 中新增:
CDialog::OnPaint(); CRect outputRect; GetDlgItem(IDC_PROCESSED_PIC)->GetWindowRect(&outputRect); m_ProcessedImage->Show(GetDlgItem(IDC_PROCESSED_PIC)->GetDC()->GetSafeHdc(),0,0,outputRect.Width(),outputRect.Height()); GetDlgItem(IDC_ORIGIN_PIC)->GetWindowRect(&outputRect); CRect rect; SetRect( rect, 0, 0, outputRect.Width(),outputRect.Height() ); m_cvImage->DrawToHDC(GetDlgItem(IDC_ORIGIN_PIC)->GetDC()->GetSafeHdc(),&rect);
【paint 函式什麼時候被呼叫呢?當註釋掉 OnBnClickedOpen() 中顯示圖片用的是show函式 時,沒有影響~~~~
WM_PAINT訊息僅用於以下兩種情況:
1. 當用戶移動視窗或顯示視窗,或使用者改變視窗的大小,或滾動視窗使用者區時,Windows會向視窗函式傳送WM_PAINT訊息。
2. 當Windows關閉覆蓋視窗部分割槽域的對話方塊時,以及選單下拉出來又被釋放時,視窗使用者區被臨時覆蓋,系統會試圖恢復顯示區域,可能向視窗函式傳送一條WM_PAINT訊息,要求應用程式重新整理其使用者區。
這兩種情況下將使MFC呼叫OnPaint處理函式。也僅有這兩種情況,檢視物件具有一個OnPaint處理函式。
開始點選 [開啟圖片] 時,算是哪種情況呢?%>_<% 】
核心程式碼:
int numberOfObject=cvFindContours(dst,stor,&cont,sizeof(CvContour),CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE,cvPoint(0,0));
Area=fabs(cvContourArea(cont,CV_WHOLE_SEQ));
Length=cvArcLength(cont)
圈圈的個數就是 連通區域的個數了
關於LPCTSTR轉換為const char * ??
如何將LPCTSTR轉換為const char * ?? 專案--屬性--配置屬性--字符集 改為使用多位元組 居然可以這麼簡單~~~【LPCTSTR 1、在非UNICODE環境下為 const char * 2、在UNICODE環境下為 const unsigned short * so,需要將寬字元轉換為多位元組】
可是,Release版本下,這個還是通不過,網上查了好多,可素,感覺亂七八糟的,誰有簡單又方便的方案????
這個應該自己設計演算法來實現的~~~~~哎~~~菜鳥啊菜鳥,這個才2行核心程式碼而已啊,趕緊學著自己寫一個吧%>_<%
具體程式碼: http://download.csdn.net/detail/timidsmile/3671517