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

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));

doremifasollatidoa at 2007-7-8 9:00:56 > top of Java-index,Java Essentials,Java Programming...
# 2

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.

es5f2000a at 2007-7-8 9:00:56 > top of Java-index,Java Essentials,Java Programming...
# 3
it saved 100 ms but every little helps ty
nickmagusa at 2007-7-8 9:00:56 > top of Java-index,Java Essentials,Java Programming...
# 4

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.

doremifasollatidoa at 2007-7-8 9:00:56 > top of Java-index,Java Essentials,Java Programming...
# 5
Instead of scanning the screen with getPixelColor, take a capture of the entire screen and scan that. Checking individual pixels is incredibly slow.
jsalonena at 2007-7-8 9:00:56 > top of Java-index,Java Essentials,Java Programming...
# 6
ok so how do i scan the image
nickmagusa at 2007-7-8 9:00:56 > top of Java-index,Java Essentials,Java Programming...
# 7
Robot's createScreencapture method returns a BufferedImage, and that has a getRGB method. Does that help?
DrLaszloJamfa at 2007-7-8 9:00:56 > top of Java-index,Java Essentials,Java Programming...
# 8
but then im back scanning every pixel
nickmagusa at 2007-7-8 9:00:56 > top of Java-index,Java Essentials,Java Programming...
# 9
Maybe you need to step back and give the requirements for this program. What is it scanning the screen anyway?
DrLaszloJamfa at 2007-7-8 9:00:56 > top of Java-index,Java Essentials,Java Programming...
# 10
a robot im expandin the robot class to do alot more stuff
nickmagusa at 2007-7-8 9:00:56 > top of Java-index,Java Essentials,Java Programming...
# 11

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?

DrLaszloJamfa at 2007-7-8 9:00:56 > top of Java-index,Java Essentials,Java Programming...
# 12

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

nickmagusa at 2007-7-8 9:00:56 > top of Java-index,Java Essentials,Java Programming...
# 13
tnxs for all your help
nickmagusa at 2007-7-8 9:00:56 > top of Java-index,Java Essentials,Java Programming...
# 14

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

nickmagusa at 2007-7-8 9:00:56 > top of Java-index,Java Essentials,Java Programming...