-2

I have a method which takes a javafx.scene.paint.color as a parameter and returns either black or white as a color depending on the brightness of the given color.

Here is my code:

@Override
public Color getPixelColor(Color color) {
    return color.getBrightness() > cutOff ? Color.WHITE : Color.BLACK;
}

Because this has to be done for each pixel of an image this method can take a while depending of the image size. (For an Full HD Image the code will run through 2 million if statements)

So my question is, if there is a way/calcuation, which gives you 0(black) or 1(white) as result but doesn't use any if statements.

Thanks in advance.

Dimitrios Begnis
  • 823
  • 6
  • 16
  • aaaaaaaa but you didn specify javafx. in your prologue?? did you now? – gpasch May 10 '16 at 21:46
  • 1
    Processing a fullhd image on the cpu willbe slow whatever you do. Especially in java. I'd look for some gpu accelerated solution. In this case I am pretty sure that not the ternary operator is the bottleneck. – Tamas Hegedus May 10 '16 at 21:50
  • @TamasHegedus, yes I am aware of that, but I wonder in general if it's possible to put such an if statement in a proper calculation – Dimitrios Begnis May 10 '16 at 21:56
  • Since `java.awt.Color` doesn't have a `getBrightness()` method I'm going to assume you extended `Color` and added that method (you should have told us). In that case, I suspect the bottleneck is in your `getBrightness()` method and not the cutoff calculation. – Jim Garrison May 10 '16 at 21:59
  • It is possible, you just did. – Tamas Hegedus May 10 '16 at 21:59
  • @JimGarrison he is using javafx.scene.paint.color – Iłya Bursov May 10 '16 at 22:01
  • 1
    Based on [this](http://stackoverflow.com/questions/3793650/convert-boolean-to-int-in-java) Id say this is the right way. If there was a builtin for that, that wouldnt be much faster anyway. – Tamas Hegedus May 10 '16 at 22:01
  • 1
    Ah... still I suspect the bottleneck is `getBrightness()`. Without actual profiling data optimizing the cutoff calculation is a stab in the dark. It will be MUCH more expensive to calculate a relative brightness (several multiplies and/or divisions) compared to a simple threshold test. – Jim Garrison May 10 '16 at 22:02

1 Answers1

6

As it was said in comments - I doubt that this particular function is bottleneck. But still you can optimize it.

If you go deeper and de-compile getBrightness function, you will see that it is actually converts R,G,B values to HSB and then returns only B. It uses com.sun.javafx.util.Utils.RGBtoHSB function for that

By going further, in com.sun.javafx.util.Utils.RGBtoHSB we will see that to calculate brightness, you need to pick maximal value from R,G,B

double cmax = (r > g) ? r : g;
if (b > cmax) cmax = b;
brightness = cmax;

so, we can either re-use this knowledge, like that (no array allocation, useless calculations of hue/saturation):

if ((clr.getRed() > cutoff) || (clr.getGreen() > cutoff) || (clr.getBlue() > cutoff)) {
    return Color.WHITE;
} else {
    return Color.BLACK;
}

or optimize it further (to eliminate if statements):

private static final Color[] BW_VALUES = {Color.BLACK, Color.WHITE};

public static Color convertToBW_1(final Color clr, final double cutoff) {
    /**
     * rd will be 0, if red channel under cutoff, ie black. rd will be 1, if red channel is above cutoff, ie white
     */
    final byte rd = (byte) (Double.doubleToRawLongBits(cutoff - clr.getRed()) >>> 63);
    final byte gd = (byte) (Double.doubleToRawLongBits(cutoff - clr.getGreen()) >>> 63);
    final byte bd = (byte) (Double.doubleToRawLongBits(cutoff - clr.getBlue()) >>> 63);

    /**
     * if at least one value is 1, then return white.
     */
    return BW_VALUES[rd | gd | bd];
}

According to my quick measurements - this variant 2 times faster, but your mileage may vary

Iłya Bursov
  • 23,342
  • 4
  • 33
  • 57