2016-03-26 27 views
1

我正在嘗試查找二進制對象的周長。查找圖像二進制對象的周長

考慮下面的圖片

[ 0 0 0 0 1 1 0 ] 
[ 0 0 1 0 0 0 0 ] 
[ 0 1 1 0 1 1 0 ] 
[ 0 1 1 0 0 1 0 ] 
[ 0 1 1 1 0 0 0 ] 
[ 0 1 0 0 1 1 0 ] 
[ 0 0 0 0 1 1 0 ] 

標記圖像將看起來像這樣

[ 0 0 0 0 1 1 0 ] 
[ 0 0 2 0 0 0 0 ] 
[ 0 2 2 0 3 3 0 ] 
[ 0 2 2 0 0 3 0 ] 
[ 0 2 2 0 0 0 0 ] 
[ 0 2 0 0 4 4 0 ] 
[ 0 0 0 0 4 4 0 ] 

此外,我收集在陣列列表中的每個對象像素

因此,例如,對於4標記對象將列表be

{ (5,4), (5,5) , (6,4), (6,5) } 

面積只是每個對象像素數組的大小,但是如何才能找到周長,我是否應該再次遍歷整個圖像查找單元格的鄰居,檢查它是否是對象的角點像素還是有更簡單的方法來做到這一點只是基於座標。

請建議什麼是找到周邊最簡單的方法,任何代碼示例將不勝感激

回答

2

嘗試做廣度優先搜索圖像的,(或可替代迭代通過您點的列表)和標記與不屬於同一組的另一個像素相鄰的每個像素

我不清楚,如果你想要的邊界是所請求的對象的外邊緣上的每個像素,或與該對象的邊界的每個像素。我現在假設前者。

設置圖片:

下面是你如何去做這件事。首先,設置你的圖像作爲2-d陣列,用標記有組號的每個像素:

[ 0 0 0 0 1 1 0 ] 
[ 0 0 2 0 0 0 0 ] 
[ 0 2 2 0 3 3 0 ] 
[ 0 2 2 0 0 3 0 ] 
[ 0 2 2 0 0 0 0 ] 
[ 0 2 0 0 4 4 0 ] 
[ 0 0 0 0 4 4 0 ] 

一個好的方式來加載,這將是使用一個Scanner對象來獲取每個點,一個接一個:

List<Point> points = new ArrayList<>(); 
Scanner scanner = new Scanner(/* whatever your input source is */); 
String pointRegex = "\\(\\d,\\d\\)"; //looks for something like "(#,#)" 
while(!scanner.hasNext(pointRegex)){ 
    String pointText = scanner.next(pointRegex); //For example, "(5,4)" 
    Point point = getPointFromText(pointText); //turns a string into a point 
    points.add(point); 
} 

請注意使用Scanner.next(String pattern)。這是一種方法,將返回看起來像那個模式的下一個String。在(閱讀上的正則表達式,如果你想了解更多有關如何工作的。)

我們填充網格:

boolean[][] binaryImage = new boolean[width][height]; 
for(Point p : points){ //Iterate through each Point inside our List of Point objects 
    binaryImage[p.getX()][p.getY()] = true; 
} 

這使得對象,通過我們的Point對象的集合「points代表「,變成boolean s的格子。我們只需要擔心這個對象,所以我們不需要加載任何其他對象。現在找出外圍的點。

遞歸方法:

boolean[][] visitedBefore = new boolean[width][height]; 
boolean[][] isOnPerimeter = new boolean[width][height]; 
int[] deltaX = {-1, 0, 1, -1, 1, -1, 0, 1}, 
     deltaY = {-1, -1, -1, 0, 0, 1, 1, 1}; 
Queue<Point> searchNext = new LinkedList<>(); 
searchNext.add(points.get(0)); //Just need one point to get going 
while(!searchNext.isEmpty()){ 
    Point p = searchNext.remove(); //take what's waiting at the front of the queue 
    if(visitedBefore[p.getX()][p.getY()]){ 
     continue; //already check this spot! 
    } 

    //mark that we've been here 
    visited[p.getX()][p.getY()] = true; 

    //look at all of this Point's neighbors 
    for(int i = 0 ; i < deltaX.length ; i++){ 
     int newX = p.getX() + deltaX[i]; 
     int newY = p.getY() + deltaY[i]; 

     //make sure this isn't out of bounds 
     if(newX < 0 || newX >= width || newY<0 || newY>=height){ 
      isOnPerimeter[p.getX()][p.getY()] = true; //if you decide bordering the edge of the image counts as being on the perimeter 
      continue; 
     } 

     //check if this new point we're considering isn't part of the image 
     if(binaryImage[p.getX()][p.getY()] != binaryImage[newX][newY]){ 
      //if it isn't, then this Point p must be on the perimeter 
      isOnPerimeter[p.getX()][p.getY()] = true; 
     } else { 
      /* otherwise, this new point we're considering is part of the 
      * same object, and could be part of the perimeter. */ 
      searchNext.add(new Point(newX, newY)); 
     } 
    } 
} 

現在你有一個在外線的每個點的網格標記爲true。如果你需要這些作爲一個列表,挑選出這些點很簡單:

List<Point> perimeter = new ArrayList<Point>(); 
for(int x = 0 ; x < isOnPerimeter.length ; x++) 
    for(int y = 0 ; y < isOnPerimeter[x].length ; y++) 
     perimeter.add(new Point(x,y)); 

迭代方法:

這是非常類似上面,而是直接跳轉到把周邊點到列表中。

int[] deltaX = {-1, 0, 1, -1, 1, -1, 0, 1}, 
     deltaY = {-1, -1, -1, 0, 0, 1, 1, 1}; 
outer: for(Point p : points){ 
    inner: for(int i = 0 ; i < deltaX.length ; i++){ 
     int newX = p.getX() + deltaX[i]; 
     int newY = p.getY() + deltaY[i]; 
     //check if this new point we're considering is outside the image 
     if(newX < 0 || newX >= width || newY<0 || newY>=height){ 
      perimeter.add(p); //if you decide bordering the edge of the image counts as being on the perimeter 
      continue outer; 
     } 

     //check if this new point we're considering isn't part of the image 
     if(binaryImage[p.getX()][p.getY()] != binaryImage[newX][newY]){ 
      //if it isn't, then this Point p must be on the perimeter 
      perimeter.add(p); 
      continue outer; 
     } 
    } 
} 

注意標籤outer:inner:。當我們說continue outer;時,這讓我們選擇哪個循環跳過。

你走了!這應該可以幫助您將任何對象的邊界視爲二進制圖像或列表。