finding a color with a robot
Hey i am making this program and i need an efficient findcolor algorithm i am currently using this:
public Point FindColor(Color c,int x1,int y1,int x2,int y2,int tol){
for (int i=y1;i<=y2;i++){
for(int j=x1;j<=x2;j++){
if (colorSimilarity(getPixelColor(j, i),c)*100>100-tol){
return new Point(j,i);
}
}
}
return null;
}
public double colorSimilarity ( Color col1, Color col2 )
{
double dr, dg, db;
dr = col1.getRed() - col2.getRed();
dg = col1.getGreen() - col2.getGreen();
db = col1.getBlue() - col2.getBlue();
return 1-(( Math.sqrt ( ( dr * dr ) + ( dg * dg ) + ( db * db ) ) )/(255*Math.sqrt(3)));
}
but it takes forever to search the whole screen (by forever i mean 8-9 seconds). any ideas as to how i could improve its efficiency to more like .1-.5 seconds
[892 byte] By [
nickmagusa] at [2007-11-26 15:10:12]

1. Don't crosspost.
2. Use the code tags (button above posting box) to format your code nicely.
3. It might not save tons of time, but you could precalculate the (1/(255*Math.sqrt(3)) once:
return 1-(( Math.sqrt ( ( dr * dr ) + ( dg * dg ) + ( db * db ) ) )/
(255*Math.sqrt(3)));
becomes:
return 1-(Math.sqrt( ( dr * dr) + ( dg * dg ) + ( db * db ) ) * FACTOR);
where you declare the following at the top of the class:
private static final double FACTOR = 1/(255 * Math.sqrt(3));
There are microoptimizations you can do, such as pulling the value
of 100-tol out of the for loops and keeping 255 * Math.sqrt(3) as
a private final static. I doubt these will significantly impact
performance. You've got to run through a lot of points, and do math
at each step. That takes a while.
You should consider using a profiler on your entire codebase to
make sure that your problem is where you think it is.
it saved 100 ms but every little helps ty
If you rewrite your inequalities, you will see that:
if (colorSimilarity(getPixelColor(j, i),c)*100 > 100-tol){
is equivalent to:
if ((Math.sqrt( ( dr * dr) + ( dg * dg ) + ( db * db ) ) * FACTOR * 100) < tol)
You would then want to change the definition of FACTOR to include the 100:
if ((Math.sqrt( ( dr * dr) + ( dg * dg ) + ( db * db ) ) * NEW_FACTOR) < tol)
where NEW_FACTOR is:
private static final double NEW_FACTOR = 100/(255 * Math.sqrt(3));
Moving the NEW_FACTOR to the other side gives:
if ((Math.sqrt( ( dr * dr) + ( dg * dg ) + ( db * db ) ) ) < (tol * DIFFERENT_FACTOR))
where DIFFERENT_FACTOR is 1/ NEW_FACTOR:
private static final double DIFFERENT_FACTOR = (255 * Math.sqrt(3)) / 100;
You would calculate tol * DIFFERENT_FACTOR once before starting the 'for' loops.
Instead of scanning the screen with getPixelColor, take a capture of the entire screen and scan that. Checking individual pixels is incredibly slow.
ok so how do i scan the image
Robot's createScreencapture method returns a BufferedImage, and that has a getRGB method. Does that help?
but then im back scanning every pixel
Maybe you need to step back and give the requirements for this program. What is it scanning the screen anyway?
a robot im expandin the robot class to do alot more stuff
Hmmm... You're building a better robot? Screen capture is useful if you need to see what some other process has rendered to the screen. But if you are writing the swing component in question, it makes more sense to buffer it and examine its buffer, rather that making a roundtrip to the screen.
That being said, jsalonen seems to be suggesting that calling createScreenCapture once, then examining various pixels is faster than multiple calls to createScreenCapture. Why don't you time it and see?
nvm i figured it out if u convert the color to an int it goes way faster my new code
public Point FindColor(Color c,int x1,int y1,int x2,int y2,int tol){
double tolLevel=tol/100.0;
int rgb=c.getRGB();
for (int i=y1;i<=y2;i++){
for(int j=x1;j<=x2;j++){
int c1=getPixelColor(j, i).getRGB();
if (Math.abs(rgb-c1)/16777216.0>tolLevel){
return new Point(j,i);
}
}
}
return null;
}
took 0 ms
nvm it was faster with an image
my final code is
public Point FindColor(Color c,int x1,int y1,int x2,int y2,int tol){
BufferedImage image= createScreenCapture(new Rectangle(x1-1,y1-1,Math.abs(x1-x2)+1,Math.abs(y1-y2)+1));
double tolLevel=tol/100.0;
int rgb=c.getRGB();
for (int i=y1;i<=y2;i++){
for(int j=x1;j<=x2;j++){
int c1=image.getRGB(j, i);
if (Math.abs(rgb-c1)/16777215.0<=tolLevel){
return new Point(j,i);
}
}
}
return null;
}
ty. how do i give the duke dolars