1

Ich versuche, Perimeter des binären Objekts zu finden.Finden Sie den Umfang des Bildes binäres Objekt

folgendes Bild Betrachten

[ 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 ] 

Beschriftete Bild wird so aussehen

[ 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 ] 

Auch sammelte ich jedes Objektpixel in Array-Liste

So zum Beispiel für 4 die Liste Objekt markiert wird be

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

Bereich ist nur die Größe jedes Objekts Pixel-Array, aber wie kann ich den Umfang finden, sollte ich erneut über das gesamte Bild finden Nachbarn der Zelle überprüfen, ob es das Eckpixel des Objekts ist oder gibt es viel einfacher Weg, dies zu tun nur basierend auf den Koordinaten.

Bitte legen nahe, was die einfachere Möglichkeit ist Perimeter zu finden, wird jedes Codebeispiel hoch

Antwort

2

geschätzt wird Versuchen eine Breitensuche Ihres Bildes zu tun, (oder alternativ Iterierte durch die Liste der Punkte) und Tag jedes Pixel, das ein anderes Pixel, das nicht aus der gleichen Gruppe.

Es ist mir nicht klar, wenn der Umfang, den Sie wollen, ist jedes Pixel an der Außenkante des angeforderten Objekts oder jedes Pixel, das das Objekt Grenzen. Ich werde das erstere für jetzt übernehmen.

das Bild ein:

Hier ist, wie Sie über das tun dies gehen würde. Zuerst stellen Sie Ihr Bild als 2-D-Matrix auf, wobei jedes Pixel mit der Gruppennummer beschriftet:

[ 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 ] 

Ein guter Weg, dies ein Scanner Objekt zu verwenden, wäre zu laden jeden Punkt zu bekommen, eins nach dem anderen :

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); 
} 

Beachten Sie die Verwendung von Scanner.next(String pattern). Dies ist eine Methode, die das nächste String zurückgibt, das wie dieses Muster aussieht. (Lesen Sie auf reguläre Ausdrücke, wenn Sie wollen mehr darüber erfahren, wie das funktioniert.)

Nun zu bevölkern das Raster:

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; 
} 

Damit ist das Objekt, vertreten durch unsere Sammlung von Point Objekte "points ", in ein Raster von boolean s. Wir müssen uns nur um dieses eine Objekt kümmern, sodass wir keine anderen laden müssen. Jetzt, um herauszufinden, welche Punkte auf dem Umfang sind.

rekursive Methode:

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)); 
     } 
    } 
} 

Jetzt haben Sie ein Gitter mit jedem Punkt auf dem Umfang als true markiert.Wenn Sie diese als eine Liste benötigen, diese Punkte herauszupicken ist einfach:

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)); 

Iterative Methode:

Das ist ziemlich ähnlich wie oben, aber springt direkt auf die Umfangspunkte in eine Liste setzen.

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; 
     } 
    } 
} 

Beachten Sie die Etiketten outer: und inner:. Auf diese Weise können wir auswählen, welche for-Schleife überspringen soll, wenn wir continue outer; sagen.

Los geht's! Dies sollte Ihnen helfen, den Umfang eines Objekts entweder als Binärbild oder als Liste zu erhalten.

Verwandte Themen