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.