Skip to content

Instantly share code, notes, and snippets.

@radiovisual
Last active January 2, 2023 18:14
Show Gist options
  • Select an option

  • Save radiovisual/c8b2f33a660828dec6c94e2260ec70f6 to your computer and use it in GitHub Desktop.

Select an option

Save radiovisual/c8b2f33a660828dec6c94e2260ec70f6 to your computer and use it in GitHub Desktop.
PImage imageMask;
ArrayList<ArrayList<PVector>> polygons;
void setup() {
size(512, 512);
imageMask = loadImage("imageMask.png");
// Create an empty array to store the polygons
polygons = new ArrayList<ArrayList<PVector>>();
// 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<PVector> polygon = new ArrayList<PVector>();
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<PVector> 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<PVector> polygon : polygons) {
// Create a new array to store the smoothed points
ArrayList<PVector> smoothedPolygon = new ArrayList<PVector>();
// 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<PVector> 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);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment