As already been pointed out the main problem is speed of rendering the sphere, change sphere to box and things really race, but its not so pretty.
In a 24bit image the number of unique colours will be close to the number of pixels. I did some tests with a 3200 pixel image with 2633 unique colours, this would result in approx 567 duplicate spheres, also many of the spheres were so close in color that the spheres overlapped and it was impossible to distiguish the difference in colour.
The approach I took was to remove duplicates and to reduce the number of spheres where the colour difference was small. The changes in code are significant but fairly straightforward.
Using the image mentioned above the code below resulted in 239 spheres and a 12 fold increase in speed.
Code:
import java.util.TreeSet;
PixelBall[] pballs;
int nbrPixels;
TreeSet pbset = new TreeSet();
PImage img;
long time;
void setup(){
size(600, 600, P3D);
noStroke();
smooth();
//noFill();
img = loadImage("img.png");
// noLoop();
nbrPixels = img.pixels.length;
int x,y,z;
int col;
int value;
// This defines how similar colours are to be considered the same
// the larger the value then bigger differences are considered
// insignificant.
int similar = 16; // bigger the value less spheres
for (int i=0; i<nbrPixels; i++){
x = (int) red(img.pixels[i]);
y = (int) green(img.pixels[i]);
z = (int) blue(img.pixels[i]);
value = (x / similar) << 15;
value += (y / similar) << 8;
value += (z / similar);
col = img.pixels[i];
pbset.add(new PixelBall(x,y,z,col, value)); // does not allow 'dulicates'
}
println("Pixels " + nbrPixels + " --> " + pbset.size() + " spheres" );
// Convert set to array for fast traversal for rendering
pballs = (PixelBall[])pbset.toArray(new PixelBall[pbset.size()]);
pbset = null;
time = System.currentTimeMillis();
}
void draw(){
lights();
// pushMatrix();
//
translate(width/2, height/2, 0);
// rotateX( radians(mouseY));
// rotateY( radians(mouseX));
//box(250);
translate( -128, -128, -128);
//println(img.pixels.length);
for (int i=0; i<pballs.length; i++)
pballs[i].display();
//Time since last render complete
long t = System.currentTimeMillis();
println(t - time);
time = t;
}
public class PixelBall implements Comparable {
private int x,y,z;
private int col;
private int value;
PixelBall(int x, int y, int z, int col, int value){
this.x = x;
this.y = y;
this.z = z;
this.col = col;
this.value = value;
}
public void display(){
pushMatrix();
translate(x,y,z);
fill(col);
sphere(5);
popMatrix();
}
public int compareTo(Object o) {
PixelBall pb = (PixelBall) o;
// defines whether 2 PixelBalls are the 'same'
return (new Integer(value).compareTo(new Integer(pb.value)));
}
}