筆者實現了一個論文裏面的算法程序,論文(能夠網上搜索到,實在搜不到能夠聯繫筆者或留下郵箱發給你)講解比較到位,按照做者的思路寫完了代碼,測試效果很好,在此分享一下算法思路及實現代碼。算法
此算法優於通常的像素標記算法,只需掃描一遍就能夠得出圖像邊界、面積等等,大大減小了計算量。數組
算法描述:學習
1、全圖掃描測試
對二值圖像全圖掃描,左到右,上到下,一遇到像素邊界就進行判斷。像素邊界指當前像素灰度爲1,其餘8領域至少有一個灰度值爲0。ui
1.先依次判斷當前像素(i,j)的左側、左上側、上側像素和右上側像素是否被已標記,一旦遇到已標記則說明當前像素(i,j)和這個已標記像素屬於同一個目標,賦予Edge[i][j]相同的標記值,結束本像素標記,如四個像素都未標記則進入第二步。spa
2.當前像素右移一部,即變爲(i,j+1),進入一子循環,每次循環判斷當前像素右上側像素是否已標記。如已標記則賦予Edge[i][j]相同的標記值並跳出循環結束,如當前像素右上側像素未標記則右移一位像素繼續判斷,直到到達這一行像素的右側邊界,跳出循環說明像素(i,j)屬於新目標。則原來最大目標標記值temp加1並賦予Edge[i][j],結束本像素標記。debug
這一大步須要注意可能會有同一類別被分到不一樣目標,須要全圖掃描時進行判斷,主要是凹形。code
2、掃描後處理blog
1.歸類。前面記錄的等價標記數組只是記錄了兩兩等價狀況,而實際可能超過兩個,如三個等價。這裏須要補充的是,Same2數組是一個tempX1的數組,第幾行就對應第幾個目標處理狀況。依次掃描Same1數組每一行,在Same2中修改類別值,保證統一類的值歸爲一類。class
2.標以正確的目標值。通過上一步,屬於同一目標的像素標記值都已歸爲一類,有幾類就有幾個帶下凹的目標,再加上0的個數(不帶下凹的目標個數)就是實際目標總數。順序掃描Same2,遇到0說明該行號表示的目標位沒有下凹的,result+1賦予Same3的同一行,遇到非零數字,則看它是否第一次出現,若是第一次出現,result+1並賦予Same3同一行,如Same2這一行的值不是第一次出現,則把前面具備相同數字那一行在Same3中同行的值賦予Same3的這一行,直到檢測完Same2。最後在Same3的最後數字表示的就是目標數。
3.根據獲得目標數進行目標劃分,整個圖像就被分到了幾個目標值。獲得的目標值能夠統計目標數目、實現面積、周長和質心等特徵值。
程序代碼:
1 //改進的像素標記算法實現代碼及註釋 2 //做者用這個算法來繪製目標外接矩形用的 3 //返回找到圖像目標處理凹形數目,參數frame是原始二值圖像,num爲處理前凹形找到目標數目,s和e分別表示繪製矩形的開始點和結束點 4 int pixelFlag(cv::Mat &frame,int &num,vector<Point2f> &s,vector<Point2f> &e)//返回個數 5 { 6 //frame. 7 int kind=0,kindEnd=0,kindResult=0;//歸類類別 8 vector<int> same1[2];//可疑邊界目標 9 10 int edge[frame.rows][frame.cols];//代表邊界屬於哪一個類 11 memset(edge,0,sizeof(edge)); 12 //qDebug()<<frame.channels(); 13 //掃描每一個像素判斷 14 for(int i=1;i<frame.rows-1;i++) 15 for(int j=1;j<frame.cols-1;j++) 16 { 17 if((frame.at<uchar>(i,j)!=0)&&(!frame.at<uchar>(i-1,j)||!frame.at<uchar>(i-1,j-1)||!frame.at<uchar>(i-1,j+1) 18 ||!frame.at<uchar>(i,j-1)||!frame.at<uchar>(i,j+1)||!frame.at<uchar>(i+1,j-1) 19 ||!frame.at<uchar>(i+1,j)||!frame.at<uchar>(i+1,j+1)))//判斷邊界點 20 { 21 if(edge[i][j-1])//判斷是否緊鄰已被標物體 左 22 { 23 edge[i][j]=edge[i][j-1]; 24 } 25 else 26 if(edge[i-1][j-1])//左上 27 { 28 edge[i][j]=edge[i-1][j-1]; 29 } 30 else 31 if(edge[i-1][j])//上 32 { 33 edge[i][j]=edge[i-1][j]; 34 }else 35 if(edge[i-1][j+1])//右上 36 { 37 edge[i][j]=edge[i-1][j+1]; 38 }else 39 { 40 int f=0; 41 while(frame.at<uchar>(i,j+f)&&((j+f)<frame.cols-1))//右移判斷 42 { 43 if(edge[i-1][j+f+1]) 44 { 45 edge[i][j]=edge[i-1][j+f+1]; 46 break; 47 } 48 else 49 { 50 f++; 51 } 52 } 53 if(!frame.at<uchar>(i,j+f))//未找處處理 54 { 55 kind++; 56 edge[i][j]=kind; 57 58 } 59 } 60 if(edge[i][j]&&edge[i-1][j+1])//若是當前點和右上不在一個類別就記錄 61 { 62 if(edge[i][j]!=edge[i-1][j+1]) 63 { 64 same1[0].push_back(edge[i][j]); 65 same1[1].push_back(edge[i-1][j+1]); 66 } 67 } 68 69 70 71 } 72 } 73 74 //處理掃描後的結果 75 int same2[kind];memset(same2,0,sizeof(same2)); 76 int sameEnd[kind];memset(sameEnd,0,sizeof(sameEnd)); 77 //QDebug debug; 78 if(!same1[0].empty()) 79 { 80 for(uint i=0;i<same1[0].size();i++) 81 { 82 if((!same2[same1[0][i]-1])&&(!same2[same1[1][i]-1]))//若是都沒有處理,種類加1 83 { 84 kindEnd++; 85 same2[same1[0][i]-1]=kindEnd; 86 same2[same1[1][i]-1]=kindEnd; 87 }else 88 if(same2[same1[0][i]-1]&&same2[same1[1][i]-1]) 89 { 90 same2[same1[0][i]-1]=same2[same1[1][i]-1]; 91 92 }else 93 if(!same2[same1[0][i]-1]&&same2[same1[1][i]-1]) 94 { 95 same2[same1[0][i]-1]=same2[same1[1][i]-1]; 96 }else if(same2[same1[0][i]-1]&&!same2[same1[1][i]-1]) 97 { 98 same2[same1[1][i]-1]=same2[same1[0][i]-1]; 99 } 100 101 } 102 } 103 104 for(int i=0;i<kind;i++)//複製到sameend 105 { 106 107 if(!same2[i]) 108 { 109 kindResult++; 110 sameEnd[i]=kindResult; 111 } 112 else 113 //if(same2) 114 { 115 int j=0; 116 while(j<i) 117 { 118 if(same2[j]==same2[i]) 119 { 120 break; 121 } 122 j++; 123 } 124 if(j<i) 125 { 126 sameEnd[i]=sameEnd[j]; 127 }else 128 { 129 kindResult++; 130 sameEnd[i]=kindResult; 131 } 132 133 } 134 } 135 num=kind; 136 //對邊界進行處理 137 for(int i=1;i<frame.rows-1;i++) 138 for(int j=1;j<frame.cols-1;j++) 139 { 140 if(edge[i][j]) 141 { 142 edge[i][j]=sameEnd[edge[i][j]-1]; 143 } 144 } 145 for(int i=0;i<kindResult;i++) 146 { 147 s.push_back(Point2f(1000,1000)); 148 e.push_back(Point2f(0,0)); 149 } 150 for(int i=1;i<frame.rows-1;i++)//求邊界對角點 151 for(int j=1;j<frame.cols-1;j++) 152 { 153 if(edge[i][j]) 154 { 155 if(s[edge[i][j]-1].y>i) 156 { 157 s[edge[i][j]-1].y=i; 158 } 159 if(s[edge[i][j]-1].x>j) 160 { 161 s[edge[i][j]-1].x=j; 162 } 163 if(e[edge[i][j]-1].y<i)
164 {
165 e[edge[i][j]-1].y=i; 166 } 167 168 if(e[edge[i][j]-1].x<j) 169 { 170 e[edge[i][j]-1].x=j; 171 } 172 } 173 } 174 return kindResult; 175 176 177 178 }
效果以下:
共享園友,學習共勉!