We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Hi all,
I'm playing with the Mesh library to create a voronoi diagram based on an existing image. I want to generate the voronoi sites based on the brightness of interesting pixels in the picture, with the goal of achieving something like what Golan Levin created back in 2000 http://www.flong.com/projects/zoo/.
My approach is to generate a bunch of random points in a 1D array containing "vpoint" objects, assign them a "worthiness" level based on the brightness of the pixel that lays on the randomly created point, and then discriminate the points with a threshold (only add significant points to the "float sites[][]" array to create the voronoi).
I'm able to do all I want but create the voronoi diagram. The 1D array of object points gets nicely populated, then the 2D array containing the "worthy" points gets nicely filled by appending new rows to the array. I decided to append to the array so it became a "dynamic" array that would only contain the points of interest without empty rows. It all works, but when I run the myVoronoi = new Voronoi( sites );
line, I get the ArrayPointerOutOfRangeException: 0; error (Processing highlights this same line of code), and I just can't figure out what I'm doing wrong.
If I understand correctly, that error means the array has a length of 0 therefore can't be read, is this correct? If that's the case, I have a couple of lines that print the length of this array in different parts of the code and it always get populated. Another proof is the following picture. The picture on the left is the source, the image on the right is the plot of all the points contained in the sites[][] array.
Here's my code. I hope you guys can help me see where I'm messing things up.
` /* define a threshold Load the image pixels pic a random location For each point location, measure the brightness of the corresponding pixel Assign a likelihood of a valid voronoi site location based on the brightness value of the pixel Add the location as a voronoi site to the array of points only if the likelihood is greater than the threshold create the voronoi diagram based on the array of voronoi points draw the edges of the voronoi diagram */
// Get Byron's lib for Voronoi and Delaunay
import megamu.mesh.*;
PImage img; // Source image
float V_prob = 0; // probability that a voronoi site lays here
float threshold = 70.0; // % of max brightness
int max_sites = 15000; // max number of sites we'll create
Voronoi myVoronoi;
VPoint[] vpoints; // 1D array to store the potential point objects
float[][] sites; // 2D array to store the voronoi sites (worthy points)
float[][] myEdges; // 2D array to store the voronoi edges
int diam = 2; // diameter of the ellipses that indicate the voronoi sites
void setup() {
img = loadImage("8.jpg"); // Load the image to evaluate
size(img.width, img.height); // Create a window the size of the source img
background(255); // With White BG
sites = new float[1][2]; // Create the 2D array to save the points
sites[0][0]=0;
sites[0][1]=0;
vpoints = new VPoint[max_sites]; // initialize the array for points
for(int i=0; i<max_sites;i++){
vpoints[i] = new VPoint(); // Fill the array with random points
}
}
void draw(){
initPoints(); // Get the voronoi sites
//print(sites[sites.length-1][0]);print(",");println(sites[sites.length-1][1]);
//println(sites.length);
myVoronoi = new Voronoi(sites); // Create the voronoi diagram
myEdges = myVoronoi.getEdges(); // Get the edges of the voronoi
drawSites(); // indicate where the sites are
drawEdges(); // draw the voronoi edges
noLoop(); // we don't need to loop
saveFrame("Voronoied-such a test.png"); // save dat art!
}
void initPoints(){
img.loadPixels(); // Get the pixels so we can work with them
for(int i=0; i<max_sites; i++){
// Get the brightness of the corresponding pixel
// at the point location to see if it's worth it
int locX = vpoints[i].x;
int locY = vpoints[i].y;
int loc = locX + locY*img.width; // find the pixel in the 1D array that stores the pixels
//debug
//print(locX);print(" ");print(locY);print(" ");println(loc);
//print(img.width); print(img.height); println(img.pixels.length);
float luma = brightness(img.pixels[loc]); // Get the brightness of the pixel
// Assing the probability to the voronoi point
// based on the brightness of the pixel
vpoints[i].prob = map(luma,0,255,0,100);
// now, compare this probability to the threshold
if(vpoints[i].prob < threshold){
//Add the point as a voronoi site
sites = (float[][])append(sites, new float[]{locX,locY});
if(sites.length > max_sites) break;
//println("Site added");
//print(sites[sites.length-1][0]);print(",");println(sites[sites.length-1][1]);
//println(sites.length);
} else { /*println("Not worth it");*/}
}//end for
}
void drawSites(){
for(int h=0;h<sites.length;h++){
//print(sites[h][0]);print(",");println(sites[h][1]);
float px = sites[h][0];
float py = sites[h][1];
ellipse(px,py,diam,diam);
}
}
void drawEdges(){
// Draw the Voronoi Edges
for(int i=0; i<myEdges.length; i++){
float startX = myEdges[i][0];
float startY = myEdges[i][1];
float endX = myEdges[i][2];
float endY = myEdges[i][3];
stroke(10); // almost black
line(startX, startY, endX, endY);
}
}
// Let's create an object for each voronoi site
class VPoint
{
int x, y; // Site coordinates
color c; // to store color information
float prob; // to store the probability of worthiness
VPoint()
{ // Assign the point location
x = int(random(img.width));
y = int(random(img.height));
c = color(random(128), random(128,192), random(128,255));
}
}`
Many thanks! Frix
Answers
Hm... gets weirder. I tried the Delaunay triangulation with the same array of points and it does work:
Any clue why the Voronoi might be saying
ArrayIndexOutOfBoundsException: 0
??!So frustrating.
OK... don't worry no more! Rewrote the program, cleaned it up a lot by separating the different processes as independent functions (which may not be the best way, but helped me keep everything neat and tidy), and now it works!
The "meat" of the program is the
discriminatePoints()
function. The rest of the additional functions are to plot the edges or the sites. I did this to have the flexibility of changing the color of the lines or to be able to plot both the Voronoi and the Delaunay without writing more lines.I'm also drawing the Delaunay triangulation just for the kicks:
The [uncommented] code: `
`