Color matching library - java

I'm looking for a way to get a matching color(s) for any given color.
Is there a way to do this either programmatically or using a library (in Java/Android)?
Thanks!
(As in a color that goes well with said color, This is a good example: colorcombos.com/colors/FF0000)

A simple method for getting the most contrasting color, would be to bounce each RGB color as far as possible. By this I mean a value of 00-7F becomes FF, and a value of 80-FF becomes 00. The result will always be saturated.
If you want the complimentary color to stay consistent with the original color, e.g a pastel red becomes a pastel cyan, things get more complicated, but it all depends on the color model you use, e.g. RGB vs HSV vs others.
You could use the formula of 0xFF - value for each RGB color, but a gray will stay gray, so that's not always good.
As for how to work with the RGB color values, here's how to find most contrasting color of a color given as the hex string.
String color = "2E8B57" // SeaGreen
int r1 = Integer.parseInt(color.substring(0, 2), 16);
int g1 = Integer.parseInt(color.substring(2, 2), 16);
int b1 = Integer.parseInt(color.substring(4, 2), 16);
int r2 = (r1 < 0x80 ? 0xFF : 0x00);
int g2 = (g1 < 0x80 ? 0xFF : 0x00);
int b2 = (b1 < 0x80 ? 0xFF : 0x00);
String newColor = String.format("%02x%02x%02x", r2, g2, b2);
// newColor = "FF00FF" (Fuchsia)
Using the other way, you'd use:
int r2 = 0xFF - r1;
int g2 = 0xFF - g1;
int b2 = 0xFF - b1;
String newColor = String.format("%02x%02x%02x", r2, g2, b2);
// newColor = "D174A8" (Hopbush)
Color names are from www.htmlcsscolor.com: SeaGreen, Fuchsia, Hopbush

Related

Color code to int (NumberFormatExeption) [duplicate]

So in a BufferedImage, you receive a single integer that has the RGB values represented in it. So far I use the following to get the RGB values from it:
// rgbs is an array of integers, every single integer represents the
// RGB values combined in some way
int r = (int) ((Math.pow(256,3) + rgbs[k]) / 65536);
int g = (int) (((Math.pow(256,3) + rgbs[k]) / 256 ) % 256 );
int b = (int) ((Math.pow(256,3) + rgbs[k]) % 256);
And so far, it works.
What I need to do is figure out how to get an integer so I can use BufferedImage.setRGB(), because that takes the same type of data it gave me.
I think the code is something like:
int rgb = red;
rgb = (rgb << 8) + green;
rgb = (rgb << 8) + blue;
Also, I believe you can get the individual values using:
int red = (rgb >> 16) & 0xFF;
int green = (rgb >> 8) & 0xFF;
int blue = rgb & 0xFF;
int rgb = ((r&0x0ff)<<16)|((g&0x0ff)<<8)|(b&0x0ff);
If you know that your r, g, and b values are never > 255 or < 0 you don't need the &0x0ff
Additionaly
int red = (rgb>>16)&0x0ff;
int green=(rgb>>8) &0x0ff;
int blue= (rgb) &0x0ff;
No need for multipling.
if r, g, b = 3 integer values from 0 to 255 for each color
then
rgb = 65536 * r + 256 * g + b;
the single rgb value is the composite value of r,g,b combined for a total of 16777216 possible shades.
int rgb = new Color(r, g, b).getRGB();
To get individual colour values you can use Color like following for pixel(x,y).
import java.awt.Color;
import java.awt.image.BufferedImage;
Color c = new Color(buffOriginalImage.getRGB(x,y));
int red = c.getRed();
int green = c.getGreen();
int blue = c.getBlue();
The above will give you the integer values of Red, Green and Blue in range of 0 to 255.
To set the values from RGB you can do so by:
Color myColour = new Color(red, green, blue);
int rgb = myColour.getRGB();
//Change the pixel at (x,y) ti rgb value
image.setRGB(x, y, rgb);
Please be advised that the above changes the value of a single pixel. So if you need to change the value entire image you may need to iterate over the image using two for loops.

Incorrect result of image subtraction

I wanted to subtract two images pixel by pixel to check how much they are similar. Images have the same size one is little darker and beside brightness they don't differ. But I get those little dots in the result. Did I subtract those two images rigth? Both are bmp files.
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class Main2 {
public static void main(String[] args) throws Exception {
int[][][] ch = new int[4][4][4];
BufferedImage image1 = ImageIO.read(new File("1.bmp"));
BufferedImage image2 = ImageIO.read(new File("2.bmp"));
BufferedImage image3 = new BufferedImage(image1.getWidth(), image1.getHeight(), image1.getType());
int color;
for(int x = 0; x < image1.getWidth(); x++)
for(int y = 0; y < image1.getHeight(); y++) {
color = Math.abs(image2.getRGB(x, y) - image1.getRGB(x, y));
image3.setRGB(x, y, color);
}
ImageIO.write(image3, "bmp", new File("image.bmp"));
}
}
Image 1
Image 2
Result
The problem here is that you can't subtract the colors direcly. Each pixel is represented by one int value. This int value consists of 4 bytes. These 4 bytes represent the color components ARGB, where
A = Alpha
R = Red
G = Green
B = Blue
(Alpha is the opacity of the pixel, and always 255 (that is, the maximum value) in BMP images).
Thus, one pixel may be represented by
(255, 0, 254, 0)
When you subtract another pixel from this one, like (255, 0, 255, 0), then the third byte will underflow: It would become -1. But since this is part of ONE integer, the resulting color will be something like
(255, 0, 254, 0) -
(255, 0, 255, 0) =
(255, 255, 255, 0)
and thus, be far from what you would expect in this case.
The key point is that you have to split your color into the A,R,G and B components, and perform the computation on these components. In the most general form, it may be implemented like this:
int argb0 = image0.getRGB(x, y);
int argb1 = image1.getRGB(x, y);
int a0 = (argb0 >> 24) & 0xFF;
int r0 = (argb0 >> 16) & 0xFF;
int g0 = (argb0 >> 8) & 0xFF;
int b0 = (argb0 ) & 0xFF;
int a1 = (argb1 >> 24) & 0xFF;
int r1 = (argb1 >> 16) & 0xFF;
int g1 = (argb1 >> 8) & 0xFF;
int b1 = (argb1 ) & 0xFF;
int aDiff = Math.abs(a1 - a0);
int rDiff = Math.abs(r1 - r0);
int gDiff = Math.abs(g1 - g0);
int bDiff = Math.abs(b1 - b0);
int diff =
(aDiff << 24) | (rDiff << 16) | (gDiff << 8) | bDiff;
result.setRGB(x, y, diff);
Since these are grayscale images, the computations done here are somewhat redundant: For grayscale images, the R, G and B components are always equal. And since the opacity is always 255, it does not have to be treated explicitly here. So for your particular case, it should be sufficient to simplify this to
int argb0 = image0.getRGB(x, y);
int argb1 = image1.getRGB(x, y);
// Here the 'b' stands for 'blue' as well
// as for 'brightness' :-)
int b0 = argb0 & 0xFF;
int b1 = argb1 & 0xFF;
int bDiff = Math.abs(b1 - b0);
int diff =
(255 << 24) | (bDiff << 16) | (bDiff << 8) | bDiff;
result.setRGB(x, y, diff);
You did not "subtract one pixel from the other" correctly. getRGB returns "an integer pixel in the default RGB color model (TYPE_INT_ARGB)". What you are seeing is an "overflow" from one byte into the next, and thus from one color into the next.
Suppose you have colors 804020 - 404120 -- this is 3FFF00; the difference in the G component, 1 gets output as FF.
The correct procedure is to split the return value from getRGB into separate red, green, and blue, subtract each one, make sure they fit into unsigned bytes again (I guess your Math.abs is okay) and then write out a reconstructed new RGB value.
I found this which does what you want. It does seem to do the same thing and it may be more "correct" than your code. I assume it's possible to extract the source code.
http://tutorial.simplecv.org/en/latest/examples/image-math.html
/Fredrik Wahlgren

Getting RGB value out of negative int value

i had to convert from rgb to hsb so as to perform histogram equalization on an image. I have converted it back into rgb and i am getting a negative value like -158435. Can anyone please help me understand how to convert this into a colour so i can set it to my pixel? Thanks
Simply make use of the bit-shifting. It works.
int rgb = 0x00F15D49;
int r = (rgb >>> 16) & 0xFF;
int g = (rgb >>> 8) & 0xFF;
int b = rgb & 0xFF;
Then use this method
Color.RGBtoHSB(int r, int g, int b, float[] hsbvals); like this:
float[] hsb = Color.RGBtoHSB(r, g, b, null);
To convert it back, simply use the other method (edited, you were right):
int rgb = Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]);
System.out.println(Integer.toHexString(rgb));
The negative value appears because you are storing colors as ARGB (Alpha Red Green Blue).
The alpha channel is then often just 100% opaque, which is 255 = 0xFF.
Therefore, when the color is converted to an 32 bit int, it appears negative.
Example: Opaque Black = ARGB(255, 0, 0, 0) = 0xFF000000 = -16777216

Convert RGB values to Integer

So in a BufferedImage, you receive a single integer that has the RGB values represented in it. So far I use the following to get the RGB values from it:
// rgbs is an array of integers, every single integer represents the
// RGB values combined in some way
int r = (int) ((Math.pow(256,3) + rgbs[k]) / 65536);
int g = (int) (((Math.pow(256,3) + rgbs[k]) / 256 ) % 256 );
int b = (int) ((Math.pow(256,3) + rgbs[k]) % 256);
And so far, it works.
What I need to do is figure out how to get an integer so I can use BufferedImage.setRGB(), because that takes the same type of data it gave me.
I think the code is something like:
int rgb = red;
rgb = (rgb << 8) + green;
rgb = (rgb << 8) + blue;
Also, I believe you can get the individual values using:
int red = (rgb >> 16) & 0xFF;
int green = (rgb >> 8) & 0xFF;
int blue = rgb & 0xFF;
int rgb = ((r&0x0ff)<<16)|((g&0x0ff)<<8)|(b&0x0ff);
If you know that your r, g, and b values are never > 255 or < 0 you don't need the &0x0ff
Additionaly
int red = (rgb>>16)&0x0ff;
int green=(rgb>>8) &0x0ff;
int blue= (rgb) &0x0ff;
No need for multipling.
if r, g, b = 3 integer values from 0 to 255 for each color
then
rgb = 65536 * r + 256 * g + b;
the single rgb value is the composite value of r,g,b combined for a total of 16777216 possible shades.
int rgb = new Color(r, g, b).getRGB();
To get individual colour values you can use Color like following for pixel(x,y).
import java.awt.Color;
import java.awt.image.BufferedImage;
Color c = new Color(buffOriginalImage.getRGB(x,y));
int red = c.getRed();
int green = c.getGreen();
int blue = c.getBlue();
The above will give you the integer values of Red, Green and Blue in range of 0 to 255.
To set the values from RGB you can do so by:
Color myColour = new Color(red, green, blue);
int rgb = myColour.getRGB();
//Change the pixel at (x,y) ti rgb value
image.setRGB(x, y, rgb);
Please be advised that the above changes the value of a single pixel. So if you need to change the value entire image you may need to iterate over the image using two for loops.

convert int color to int components

I obtain pixel color by
int color = image.getRGB(x,y);
then i want to acquire red, green, blue components separately. How to do that? Maybe using some bitmask?
int green = color&0x00ff00;
apparently not working... :(
To get color components you can use:
import android.graphics.Color;
int r = Color.red(intColor);
int g = Color.green(intColor);
int b = Color.blue(intColor);
int a = Color.alpha(intColor);
int value = image.getRGB(x,y);
R = (byte)(value & 0x000000FF);
G = (byte)((value & 0x0000FF00) >> 8);
B = (byte)((value & 0x00FF0000) >> 16);
A = (byte)((value & 0xFF000000) >> 24);
May need to flip the R, A, or B around.
You forgot to shift the byte to the right:
int green = (color & 0x00ff00) >> 8;
You can use Color constructor and pass the given integer and hasalpha=true:
Color color = new Color(image.getRGB(x,y), true);
getRGB returns the color of type TYPE_INT_ARGB which means it has an alpha channel.

Categories