PImage imageMask; ArrayList> polygons; void setup() { size(512, 512); imageMask = loadImage("imageMask.png"); // Create an empty array to store the polygons polygons = new ArrayList>(); // Iterate through each pixel in the image for (int y = 0; y < imageMask.height; y++) { for (int x = 0; x < imageMask.width; x++) { // If the pixel is black and hasn't been visited yet, start a new polygon and add it to the polygons array if (brightness(imageMask.get(x, y)) == 0) { ArrayList polygon = new ArrayList(); polygons.add(polygon); tracePolygon(polygon, x, y, 0); } } } // Smooth the polygon outlines smoothPolygons(); } void draw() { background(255); // Draw the polygons stroke(0); strokeWeight(1); noFill(); for (ArrayList polygon : polygons) { beginShape(); for (PVector point : polygon) { vertex(point.x, point.y); } endShape(CLOSE); } } // Function to smooth the polygon outlines void smoothPolygons() { // Iterate through each polygon for (ArrayList polygon : polygons) { // Create a new array to store the smoothed points ArrayList smoothedPolygon = new ArrayList(); // Iterate through each point in the polygon for (int i = 0; i < polygon.size(); i++) { PVector p1 = polygon.get(i); PVector p2 = polygon.get((i + 1) % polygon.size()); PVector p3 = polygon.get((i + 2) % polygon.size()); // Compute the angle between the three points float angle = abs(PVector.angleBetween(p2.sub(p1), p3.sub(p2))); // If the angle is acute, add the middle point to the smoothed polygon if (angle < PI / 2) { smoothedPolygon.add(p2); } else { // If the angle is obtuse, add a new point halfway between the middle point and the point with the smallest distance PVector p4 = p2.lerp(dist(p1.x, p1.y, p2.x, p2.y) < dist(p2.x, p2.y, p3.x, p3.y) ? p1 : p3, 0.5); smoothedPolygon.add(p4); } } // Replace the original polygon with the smoothed polygon polygon.clear(); polygon.addAll(smoothedPolygon); } } // Maximum recursion depth int maxRecursionDepth = 1000; // Function to trace the outline of a polygon void tracePolygon(ArrayList polygon, int x, int y, int recursionDepth) { // Check the recursion depth if (recursionDepth > maxRecursionDepth) { return; } // Add the current point to the polygon if it hasn't already been visited if (brightness(imageMask.get(x, y)) == 0) { polygon.add(new PVector(x, y)); // Set the current pixel to white to mark it as visited imageMask.set(x, y, color(255)); } // Check the pixels around the current point for (int dx = -1; dx <= 1; dx++) { for (int dy = -1; dy <= 1; dy++) { // Skip the current point and pixels outside the image if (dx == 0 && dy == 0 || x + dx < 0 || x + dx >= imageMask.width || y + dy < 0 || y + dy >= imageMask.height) { continue; } // If the pixel is black and hasn't been visited yet, recursively trace the polygon from that point if (brightness(imageMask.get(x + dx, y + dy)) == 0) { tracePolygon(polygon, x + dx, y + dy, recursionDepth + 1); } } } }