Mohit Deshpande
Mohit Deshpande

Reputation: 55257

Programmatically find complement of colors?

Is there a way to find the complement of a color given its RGB values? Or can it only be found for certain colors? How would someone go about doing this in Java?

Upvotes: 19

Views: 22481

Answers (7)

Poypoyan
Poypoyan

Reputation: 466

This is what I come up: (Conjecture)

Let r, g, and b be RGB components of the original color.

Let r', g', and b' be RGB components of the complementary color.

Then:

r' = max(r,b,g) + min(r,b,g) - r   
b' = max(r,b,g) + min(r,b,g) - b
g' = max(r,b,g) + min(r,b,g) - g

I see that this gives the same answer to what the websites (i.e. www.color-hex.com) give, but I will still prove it. :)

EDIT (23/07/2023): Yeah this old "immature" answer of mine needs long-due explanation:

  • This formula is correct only in the RGB model, which means that yes, Red pairs with Cyan. If you want to pair Red with Green instead, you need to look at RYB model instead.
  • This formula is equivalent to applying HSV/HSL to input RGB, then rotate 180 degrees, then convert back to RGB. Of course, this conversion process is what you should do if you need to compute more than just the complementary color.
  • The following is still not a proof, but more of an intuition of why this works: imagine this picture and each hue is a vertical slice, and thus with corresponding level of red, blue, green in [0,1]. Finding complementary color is essentially "setting what is high, to low" and vice versa. If the red in input is the highest, then red in the complementary should be the lowest. More generally, if the blue in input is x above the lowest, then the blue in complementary should be x below the highest. From all of this, the formula can be derived.

Upvotes: 11

Edward
Edward

Reputation: 5248

For a rough approximation, you can do this by converting RGB to HSL (Hue, Saturation, Lightness).

With the HSL value, shift the hue 180 degrees to get a color on the opposite of the color wheel from the original value.

Finally, convert back to RGB.

I've written a JavaScript implementation using a hex value here - https://stackoverflow.com/a/37657940/4939630

For RGB, simply remove the hex to RGB and RGB to hex conversions.

Upvotes: 2

tm1701
tm1701

Reputation: 7601

A more general and simple solution for finding the opposite color is:

private int getComplementaryColor( int color) {
    int R = color & 255;
    int G = (color >> 8) & 255;
    int B = (color >> 16) & 255;
    int A = (color >> 24) & 255;
    R = 255 - R;
    G = 255 - G;
    B = 255 - B;
    return R + (G << 8) + ( B << 16) + ( A << 24);
}

Upvotes: 4

Brill Pappin
Brill Pappin

Reputation: 4810

You might find more information at: Programmatically choose high-contrast colors

public static int complimentaryColour(int colour) {
    return ~colour;
}

Upvotes: -1

user1277936
user1277936

Reputation:

Just focusing on the 3D RGB cube. Here's a function that does a binary search in that cube to avoid having to figure out how to cast vectors in a direction and find the closest point on the cube boundary that intersects it.

def farthestColorInRGBcubeFrom(color):
  def pathsAt(r, g, b):
    paths = [(r, g, b)]
    if r < 255:
        paths.append((int((r + 255)/2), g, b))
    if r > 0:
        paths.append((int(r/2), g, b))
    if g < 255:
        paths.append((r, int((g + 255)/2), b))
    if g > 0:
        paths.append((r, int(g/2), b))
    if b < 255:
        paths.append((r, g, int((b + 255)/2)))
    if b > 0:
        paths.append((r, g, int(b/2)))
    return paths                         
r = color.red();  g = color.green();  b = color.blue();
#naive guess:
r0 = 255 - r;  g0 = 255 - g;  b0 = 255 - b;
paths = pathsAt(r0, g0, b0)
maxPath = None
while paths != []:
    for p in paths:
        d = (r - p[0])**2 + (g - p[1])**2 + (b - p[0])**2
        if maxPath != None:
            if d > maxPath[0]:
                maxPath = (d, p)
        else:
            maxPath = (d, p)
    p = maxPath[1]
    paths = pathsAt(p[0], p[1], p[2])
c = maxPath[1]
return QColor(c[0], c[1], c[2], color.alpha())

Upvotes: 0

JeffThompson
JeffThompson

Reputation: 1600

None of the answers above really give a way to find the complimentary color, so here's my version written in Processing:

import java.awt.Color;

color initial = color(100, 0, 100);

void setup() {
  size(400, 400);  

  fill(initial);
  rect(0, 0, width/2, height);

  color opposite = getOppositeColor(initial);
  fill(opposite);
  rect(width/2, 0, width/2, height);
}

color getOppositeColor(color c) {
  float[] hsv = new float[3];
  Color.RGBtoHSB(c>>16&0xFF, c>>8&0xFF, c&0xFF, hsv);
  hsv[0] = (hsv[0] + 0.5) % 1.0;

  // black or white? return opposite
  if (hsv[2] == 0) return color(255);
  else if (hsv[2] == 1.0) return color(0);

  // low value? otherwise, adjust that too
  if (hsv[2] < 0.5) {
    hsv[2] = (hsv[2] + 0.5) % 1.0;
  }

  return Color.HSBtoRGB(hsv[0], hsv[1], hsv[2]);
}

Upvotes: 0

Randy
Randy

Reputation: 16673

it should just be math

the total of the r values of the 2 colors should be 255

the total of the g values of the 2 colors should be 255

the total of the b values of the 2 colors should be 255

Upvotes: -3

Related Questions