改進的二值影像畫素標記演算法及程式實現
筆者實現了一個論文裡面的演算法程式,論文(可以網上搜尋到,實在搜不到可以聯絡筆者或留下郵箱發給你)講解比較到位,按照作者的思路寫完了程式碼,測試效果很好,在此分享一下演算法思路及實現程式碼。
此演算法優於一般的畫素標記演算法,只需掃描一遍就可以得出影像邊界、面積等等,大大減少了計算量。
演算法描述:
一、全圖掃描
對二值影像全圖掃描,左到右,上到下,一遇到畫素邊界就進行判斷。畫素邊界指當前畫素灰度為1,其他8領域至少有一個灰度值為0。
1.先依次判斷當前畫素(i,j)的左側、左上側、上側畫素和右上側畫素是否被已標記,一旦遇到已標記則說明當前畫素(i,j)和這個已標記畫素屬於同一個目標,賦予Edge[i][j]相同的標記值,結束本畫素標記,如四個畫素都未標記則進入第二步。
2.當前畫素右移一部,即變為(i,j+1),進入一子迴圈,每次迴圈判斷當前畫素右上側畫素是否已標記。如已標記則賦予Edge[i][j]相同的標記值並跳出迴圈結束,如當前畫素右上側畫素未標記則右移一位畫素繼續判斷,直到到達這一行畫素的右側邊界,跳出迴圈說明畫素(i,j)屬於新目標。則原來最大目標標記值temp加1並賦予Edge[i][j],結束本畫素標記。
這一大步需要注意可能會有同一類別被分到不同目標,需要全圖掃描時進行判斷,主要是凹形。
二、掃描後處理
1.歸類。前面記錄的等價標記陣列只是記錄了兩兩等價情況,而實際可能超過兩個,如三個等價。這裡需要補充的是,Same2陣列是一個tempX1的陣列,第幾行就對應第幾個目標處理情況。依次掃描Same1陣列每一行,在Same2中修改類別值,保證統一類的值歸為一類。
2.標以正確的目標值。經過上一步,屬於同一目標的畫素標記值都已歸為一類,有幾類就有幾個帶下凹的目標,再加上0的個數(不帶下凹的目標個數)就是實際目標總數。順序掃描Same2,遇到0說明該行號表示的目標位沒有下凹的,result+1賦予Same3的同一行,遇到非零數字,則看它是否第一次出現,如果第一次出現,result+1並賦予Same3同一行,如Same2這一行的值不是第一次出現,則把前面具有相同數字那一行在Same3中同行的值賦予Same3的這一行,直到檢測完Same2。最後在Same3的最後數字表示的就是目標數。
3.根據得到目標數進行目標劃分,整個影像就被分到了幾個目標值。得到的目標值可以統計目標數目、實現面積、周長和質心等特徵值。
程式程式碼:
//改進的畫素標記演算法實現程式碼及註釋
//作者用這個演算法來繪製目標外接矩形用的
//返回找到影像目標處理凹形數目,引數frame是原始二值影像,num為處理前凹形找到目標數目,s和e分別表示繪製矩形的開始點和結束點
int pixelFlag(cv::Mat &frame,int &num,vector<Point2f> &s,vector<Point2f> &e)//返回個數
{
//frame.
int kind=0,kindEnd=0,kindResult=0;//歸類類別
vector<int> same1[2];//可疑邊界目標int edge[frame.rows][frame.cols];//表明邊界屬於哪個類
memset(edge,0,sizeof(edge));
//qDebug()<<frame.channels();
//掃描每個畫素判斷
for(int i=1;i<frame.rows-1;i++)
for(int j=1;j<frame.cols-1;j++)
{
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)
||!frame.at<uchar>(i,j-1)||!frame.at<uchar>(i,j+1)||!frame.at<uchar>(i+1,j-1)
||!frame.at<uchar>(i+1,j)||!frame.at<uchar>(i+1,j+1)))//判斷邊界點
{
if(edge[i][j-1])//判斷是否緊鄰已被標物體 左
{
edge[i][j]=edge[i][j-1];
}
else
if(edge[i-1][j-1])//左上
{
edge[i][j]=edge[i-1][j-1];
}
else
if(edge[i-1][j])//上
{
edge[i][j]=edge[i-1][j];
}else
if(edge[i-1][j+1])//右上
{
edge[i][j]=edge[i-1][j+1];
}else
{
int f=0;
while(frame.at<uchar>(i,j+f)&&((j+f)<frame.cols-1))//右移判斷
{
if(edge[i-1][j+f+1])
{
edge[i][j]=edge[i-1][j+f+1];
break;
}
else
{
f++;
}
}
if(!frame.at<uchar>(i,j+f))//未找到處理
{
kind++;
edge[i][j]=kind;}
}
if(edge[i][j]&&edge[i-1][j+1])//如果當前點和右上不在一個類別就記錄
{
if(edge[i][j]!=edge[i-1][j+1])
{
same1[0].push_back(edge[i][j]);
same1[1].push_back(edge[i-1][j+1]);
}
}
}
}//處理掃描後的結果
int same2[kind];memset(same2,0,sizeof(same2));
int sameEnd[kind];memset(sameEnd,0,sizeof(sameEnd));
//QDebug debug;
if(!same1[0].empty())
{
for(uint i=0;i<same1[0].size();i++)
{
if((!same2[same1[0][i]-1])&&(!same2[same1[1][i]-1]))//如果都沒有處理,種類加1
{
kindEnd++;
same2[same1[0][i]-1]=kindEnd;
same2[same1[1][i]-1]=kindEnd;
}else
if(same2[same1[0][i]-1]&&same2[same1[1][i]-1])
{
same2[same1[0][i]-1]=same2[same1[1][i]-1];}else
if(!same2[same1[0][i]-1]&&same2[same1[1][i]-1])
{
same2[same1[0][i]-1]=same2[same1[1][i]-1];
}else if(same2[same1[0][i]-1]&&!same2[same1[1][i]-1])
{
same2[same1[1][i]-1]=same2[same1[0][i]-1];
}}
}for(int i=0;i<kind;i++)//複製到sameend
{if(!same2[i])
{
kindResult++;
sameEnd[i]=kindResult;
}
else
//if(same2)
{
int j=0;
while(j<i)
{
if(same2[j]==same2[i])
{
break;
}
j++;
}
if(j<i)
{
sameEnd[i]=sameEnd[j];
}else
{
kindResult++;
sameEnd[i]=kindResult;
}}
}
num=kind;
//對邊界進行處理
for(int i=1;i<frame.rows-1;i++)
for(int j=1;j<frame.cols-1;j++)
{
if(edge[i][j])
{
edge[i][j]=sameEnd[edge[i][j]-1];
}
}
for(int i=0;i<kindResult;i++)
{
s.push_back(Point2f(1000,1000));
e.push_back(Point2f(0,0));
}
for(int i=1;i<frame.rows-1;i++)//求邊界對角點
for(int j=1;j<frame.cols-1;j++)
{
if(edge[i][j])
{
if(s[edge[i][j]-1].y>i)
{
s[edge[i][j]-1].y=i;
}
if(s[edge[i][j]-1].x>j)
{
s[edge[i][j]-1].x=j;
}
if(e[edge[i][j]-1].y<i)
{
e[edge[i][j]-1].y=i;
}if(e[edge[i][j]-1].x<j)
{
e[edge[i][j]-1].x=j;
}
}
}
return kindResult;}
效果如下:
相關文章
- 常用的畫素操作演算法:影像加法、畫素混合、提取影像中的ROI演算法
- 實現SLIC演算法生成畫素畫演算法
- python改變單通道圖片的畫素值Python
- 影像行畫素處理
- 亞畫素數值極值檢測演算法總結演算法
- webgl 影像處理2---影像畫素處理Web
- 【CV/Matlab系列】一種改進的影像顯著性檢測方法及實現Matlab
- 記錄Mybatis第二天(實現增刪改及一些標籤配置)MyBatis
- 二值影像
- 常用的畫素操作演算法:影象加法、畫素混合、提取影象中的ROI演算法
- 【短道速滑八】圓形半徑的影像最大值和最小值演算法的實現及其實時優化(非二值圖)演算法優化
- 批次提取畫素差異並儲存二進位制
- 效能優化之關於畫素管道及優化(二)優化
- 裝置畫素、獨立畫素和css畫素CSS
- retina屏中1物理畫素border的實現
- 協同過濾的R語言實現及改進R語言
- 十三種基於直方圖的影象全域性二值化演算法原理、實現、程式碼及效果。直方圖演算法
- 基於模糊集理論的一種影象二值化演算法的原理、實現效果及程式碼演算法
- 第二章. Dump程式的改進
- 資料結構&演算法實踐—地精排序及改進資料結構演算法排序
- 手機實現1畫素邊框顯示
- 常用的畫素操作演算法:Resize、Flip、Rotate演算法
- 【OpenCV】訪問Mat影象中每個畫素的值OpenCV
- 使用matlab對影像進行二值化處理Matlab
- 樸素貝葉斯分類和預測演算法的原理及實現演算法
- 資料結構&演算法實踐—氣泡排序及改進資料結構演算法排序
- [Swift]SpriteKit實現類似畫素鳥的小遊戲 - Crashy PlaneSwift遊戲
- 【移動適配】一個畫素的border怎麼實現
- 如何構建標籤畫像工程體系及實現方案
- canvas畫素畫板Canvas
- 掌握web開發基礎系列--物理畫素、邏輯畫素、css畫素WebCSS
- 畫直線的演算法之DDA演算法+程式碼實現(法一)演算法
- 漫畫演算法:最小棧的實現演算法
- 目標跟蹤演算法----KCF進階(基於KCF改進的演算法總結)演算法
- Vue 進階系列(二)之外掛原理及實現Vue
- 實現謠傳QQ中的手段——“1畫素頁面保活”
- opencv——輪廓發現與輪廓(二值影像)分析OpenCV
- 記一次資料同步需求的改進(二)