1

I have a Collection of Integers of Processing colors (it contains colors of images rescaled to 1x1 to get the "average" color).
I have this thing that must retrieve me the nearest color of the array :

public static int getNearestColor(Collection<Integer> colors, int color) {
    return colors.stream()
        .min(Comparator.comparingInt(i -> Math.abs(i - color)))
        .orElseThrow(() -> new NoSuchElementException("No value present"));
}

But when I do this, it returns me a color that is way far than the input, but the array contains some colors that are nearest than the input, this is my problem that I don't understand ?

Aditya Rewari
  • 2,343
  • 2
  • 23
  • 36
Ayfri
  • 570
  • 1
  • 4
  • 24

3 Answers3

2

The RGB color channels of a color() are encoded in an int. You can extract the red, green and blue component of the color, by red(), green() and blue().
Treat the color channels as a 3 dimensional vector (PVector) and compute the Euclidean distance of 2 color vectors, by dist(). The color with the shortest "distance" is the "nearest" color:

In the following function the arguments c1 and c2 are colors of type int:

float ColorDistance(int c1, int c2) {
    return PVector.dist(
        new PVector(red(c1), green(c1), blue(c1)), 
        new PVector(red(c2), green(c2), blue(c2)));
}

Find the "nearest" color, in a collection of colors, by finding the minimum floating point "distance" (ColorDistance(i, color)).

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • @Ayfri While the formula RGB distance formula is clean and correct, bare it's unlikely to find the perceptually closest color in RGB colour space. For that you may want to convert to L*a*b which is slightly [more complicated](https://stackoverflow.com/questions/15438063/how-to-calculate-the-distance-between-ofcolors-in-openframeworks/15721504#15721504). Nice answer Rabbid76 (+1): clean and concise – George Profenza Apr 26 '20 at 18:06
0

arrays in java don't have a stream method; perhaps you meant Arrays.stream(colors). IntStream has no way to do a comparison other than on natural order. You can map to the difference (abs(i - color)) first, but now you've deleted the information you were looking for (the original color), so that won't work either. Let's box it. This results in the following code, which is exactly like your code, except this compiles and runs. I'll then also add a test case to make it a self-contained example:

int[] colors = {1,4,5,9,12};
int target = 6;
int a = Arrays.stream(colors).boxed()
    .min(Comparator.comparingInt(i -> Math.abs(i - target)))
    .orElseThrow(() -> new NoSuchElementException());
System.out.println(a);

and, whoa nelly, '5' falls out, which is exactly what you want.

In other words, the intent of your code is fine, if it's not giving the right answer your inputs are not what you thought they are, or something else is wrong that cannot be gleaned from your paste.

May I suggest that if it is at all possible to put the question in a simple, self contained form (as this question clearly was, see the code snippet in this answer), that you do so? Often you'll answer your own questions that way :)

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • It's because I'm stupid, my function actually take `values()` from a `HashMap`, to simplify the problem I just put `int[]` but I didn't realized that the function cannot work with this, I'm so sorry :( Can you modify your message ? I modified mine. – Ayfri Apr 26 '20 at 16:50
0
public static int getNearestColor(int[] colors, int color) {
    int minDiff = IntStream.of(colors)
            .map(val -> Math.abs(val - color))
            .min()
            .getAsInt();

    OptionalInt num = IntStream.of(colors)
            .filter(val-> val==(color + minDiff))
            .findFirst();

    if(num.isPresent()){
        return color + minDiff;
    } else {
        return color - minDiff;
    }
  }
Aditya Rewari
  • 2,343
  • 2
  • 23
  • 36
  • I have changed the code flow.. But, This is returning the expected output ! – Aditya Rewari Apr 26 '20 at 16:56
  • I'm ! I'm stupid, my function actually take `values()` from a `HashMap`, to simplify the problem I just put `int[]` but I didn't realized that the function cannot work with this, I'm so sorry :( Can you modify your message ? I modified mine. – Ayfri Apr 26 '20 at 16:59
  • 3
    Instead of just posting code, can you please explain what your code does and how it works, that way people can learn from it? – Kevin Workman Apr 26 '20 at 17:23