1. 程式人生 > >OpenCV統計米粒數目-計算聯通區域的個數及聯通區域內畫素的個數

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=0double tmpArea=0; CvSeq* maxAreaRice=0double maxLength=0double 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

http://blog.csdn.net/timidsmile/article/details/6859954            

給我老師的人工智慧教程打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=0double tmpArea=0; CvSeq* maxAreaRice=0double maxLength=0double 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

http://blog.csdn.net/timidsmile/article/details/6859954