I have list of colors in HEX format (for example #000000) and I would like to detect color type (blue, red, green etc.) and then change color type to another color type. Is this possible and are there any frameworks/libraries for this task?
Example:
I have color #EB1369 (red) then I convert it to blue and it becomes for example #1313EB (blue).
Here's a function that will let you shift colors around the hue circle. You should read the wikipedia page on the HSB (or HSV) color system to really understand what is going on: http://en.wikipedia.org/wiki/HSV_color_space
/** Converts an input color given as a String such as "ab451e" to
* the HSB color space. Shifts its hue from the given angle in degrees.
* Then returns the new color in the same format it was given.
*
* For example shift("ff0000", 180); returns "80ff00" (green is the opposite of red).*/
public static String shift(String rgbS, int angle) {
// Convert String to integer value
int value = Integer.parseInt(rgbS, 16);
// Separate red green and blue
int r = value >> 16;
int g = (value >> 8) & 0xff;
int b = value & 0xff;
// Convert to hsb
float[] hsb = Color.RGBtoHSB(r, g, b, null);
// Convert angle to floating point between 0 and 1.0
float angleF = (float)(angle/360.0);
// Shift the hue using the angle.
float newAngle = hsb[0] + angleF;
if(newAngle > 1.0)
newAngle = newAngle - 1.0f;
hsb[0] = newAngle;
// Convert back to RGB, removing the alpha component
int rgb = Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]);
rgb = rgb & 0xffffff;
// Build a new String
return Integer.toHexString(rgb);
}
Detecting colors can be complex, it depends on the result you really expect.
If what you want is simply an approximation (red, green, blue, yellow, etc.) then you can look at the hue circle of the HSB color-space, choose a hue value for each color you want to define, and then map the color you get in input to the closest one you chose.
You can also rely on things like named HTML colors: http://www.w3schools.com/html/html_colornames.asp . Take this list, create a mapping in your program, then all you have to do is map the color you get to the closest one in your map, and return its name. Be wary though: computing the distance between two colors can be tricky (especially in RGB) and naive approaches (such as channel-by-channel difference) can give surprisingly bad results. Colorimetry is a complex topic, and you will find good methods on this page: http://en.wikipedia.org/wiki/Color_difference
Try convert RGB values to HSV (HSB exactly) - it is format for colors which is more comfortable for human. After conversion, all u need to do is change H V (probably) and convert it back to RGB.
I guess that you like to convert RGB color to HSB. YOu can do this wuth:
java.awt.Color.RGBtoHSB(...)
then you can easily determine whetther H value fits in your definition of blue, and modify it to whatever you like. After this, you can easily convert it back to RGB via:
java.awt.Color.getHSBColor(...)
And ifg you do not like jawa.awt.color just multiply color vector by transofrmation matrix.
Each HEX Color has three parts in it, red, green and blue the # identifies a HEX color, the following two letters are the amount of red; the next two are green and the next two are blue. i.e: RGB
The two letters can have a maximum hexidecimal value of FF which is 255, and a minimum of 00 which is zero.
So you can argue like this, I want a color with 2 red parts, 7 green parts, and zero blue parts, which will give you #020700
That is why #FFFFFF is white (all the colors together) and #000000 is black (no colors at all)
With this logic you can modify the color in any way you want; The Color class can also help a lot.
Related
Let's say I have two colors in Lab color space-
Color 1: L=81, a=-8, b=74
Color 2: L=64, a=-14, b=3
I want generate n colors between them. For say n=100 or as many colors possible between them.
I know the RGB and HSV color gradient algorithm. But I want to generate gradient in LAB color spaces. I don't want to convert the colors to HSV or RGB as different color models generate different gradients.
This is a link i found which generates gradient in Lab and other color models: http://davidjohnstone.net/pages/lch-lab-colour-gradient-picker
I'm aiming to do something similar in Java but language doesn't matter, I just need to understand the logic and algorithm behind it.
I'm doing this basically for matching a scanned color value with a chart of 5 colors I have. So, I have to first generate all colors in between those 5 colors (using gradient) and compare the other color to find the one which is closest to it. (For comparing I'm using CIEDE2000 Delta-e method). But that's secondary i guess.
Adding further to the last part of my question,
I suppose I'll have to generate a gradient because I want to find the exact location of the color from my sample in the sequence of chart I have.
For eg- I have 6 colors of green shades (light to dark) in my chart each corresponding to particular numeric data between 0 to 450 mg like below (with their LAB values)
Color 1: 78, -10, -71 [0 mg]
Color 2: 73,-14,44 [30 mg]
Color 3: 71, -19, 53 [80 mg]
Color 4: 67, -18, 31 [160 mg]
Color 5: 69, -2, 29 [300 mg]
Color 6: 61, -14, 3 [450 mg]
Now I want to generate all colors between them and find the location of my scanned color and return the mg value. Say my color is exactly between Color 1 and Color 2, then it'll return 15 mg, otherwise if it is closer to Color 2 it'll return 28.5 mg and so on.
Hope this clears up what I'm trying to achieve.
To generate a gradient between two color values, you can just linearly interpolate between them. This will basically work in any color space, although if the transformation between two color spaces is not linear, the gradient obtained by linearly interpolating in one space will not be linear in the other. Thus, generating gradients in Lab color space is exactly like generating them in, say, RGB space.
(For color spaces like HSV or HSL which have a hue coordinate that "loops around", some extra care may be needed to choose the right direction to interpolate in; fortunately, you're not asking about those color spaces here, so I don't need to go into such details.)
Just as a demonstration, here's how you'd generate an n-sample gradient between the colors c1 and c2 (each given as a LabColor object with properties L, a and b):
public static LabColor[] makeGradient(LabColor c1, LabColor c2, int n) {
LabColor gradient = new LabColor[n];
for (int i = 0; i < n; i++) {
float alpha = (float)i / (n-1); // 0.0 <= alpha <= 1.0
float L = (1-alpha) * c1.L + alpha * c2.L;
float a = (1-alpha) * c1.a + alpha * c2.a;
float b = (1-alpha) * c1.b + alpha * c2.b;
gradient[i] = new LabColor(L, a, b);
}
return gradient;
}
This will return a gradient with n color samples, where the first color is equal to c1, the last color is equal to c2, and the rest are interpolated between them.
However, based on the remark at the end of your question, I suspect you don't actually need to generate any gradients. Rather, to find the color in your chart that most closely matches the one in your sample, you just need to calculate the perceptual distance of each chart color from the sample (which, in the Lab color space, can be well approximated simply by their Euclidian distance) and select the closest one:
public static LabColor findNearest(LabColor sample, LabColor[] chart) {
LabColor nearest = null;
float minDistanceSquared = Float.POSITIVE_INFINITY;
for (int i = 0; i < chart.length; i++) {
float dL = sample.L - chart[i].L;
float da = sample.a - chart[i].a;
float db = sample.b - chart[i].b;
float distanceSquared = dL*dL + da*da + db*db;
if (distanceSquared < minDistanceSquared) {
nearest = chart[i];
minDistanceSquared = distanceSquared;
}
}
return nearest;
}
I cannot find a conversion routine for converting 8-bit indexed color to RGB. For some background details, I am using POI to read an xlsx file and one of the cells has a background color indexed as value 64. When I attempt to create a PdfPCell in iText with this value for the background BaseColor, I get a Navy Blue and the correct color should be Black. So I need a routine that will convert the value of 64 to rgb(0, 0, 0).
This is the code that sets the background to Navy Blue
short c = ((XSSFColor) color).getIndexed();
BaseColor base = new BaseColor(c);
I found a similar question here on SO but the "packed" routine failed with "Color value outside range 0-255".
short packed = ((XSSFColor) color).getIndexed();
log.debug("Indexed {}", packed);
int r = (packed >> 5) * 32;
int g = ((packed >> 2) << 3) * 32;
int b = (packed << 6) * 64;
BaseColor base = new BaseColor(r, g, b);
Update 1: It seems that there is a Palette somewhere in the document, in my case an XSSFPalette. Once I find the answer I'll update it here.
Update 2: XSSFWorkbook doesn't provide access to the palette, hence my follow question: Access to the color palette in an XSSFWorkbook
There isn't a mathematical relationship between color index and RGB values. It's a lookup.
Eight-bit indexed color means that each pixel's color is represented by the number 0-255. What those colors actually are depends on your pallette (just like a painter would use!) The eight bits, therefore, allow you to have 256 separate colors in your picture.
If your image displays in color, then you have a pallette somewhere that will tell you what index corresponds to what RGB triplet.
http://en.wikipedia.org/wiki/Indexed_color
I'm trying to write function, which can generate colors between two colors based on a given value. An example would explain it better..
Input ..
X : 1
Y : 0.5
Z : 0
The user gives any set of color:value pairs, then enters a number(say 0.75). I have to then generate color which is a blend of Y and Z in proportion(based on the their values and the input value). I was thinking of the following approach.
Find the colors which surround the value, for 0.75 it will be 0.5 and 1.
Mix those two colors somehow, based on the value and generate new colors.
I'm completely lost, as how to generate colors and are there any libraries for this.
UPDATE:
It is part of a bigger project I'm working on. Lets say we have ..
1 : X
0 : Y
and the user inputs, 0.25
I would like to have something..
(X*0.25 + Y*0.75)
as it's more near to Y, that's why the higher proportion. If the user inputs, 0.5.. the output should be
(X*0.5 + Y*0.5)
and so on. I have no idea how to do this with RGB colors.
P.S: The questions is not specific to language, but I'm doing this in Java.
You have to blend each color channel (red, green and blue) seperately like this:
Color x,y; //set by you
float blending;//set by you
float inverse_blending = 1 - blending;
float red = x.getRed() * blending + y.getRed() * inverse_blending;
float green = x.getGreen() * blending + y.getGreen() * inverse_blending;
float blue = x.getBlue() * blending + y.getBlue() * inverse_blending;
//note that if i pass float values they have to be in the range of 0.0-1.0
//and not in 0-255 like the ones i get returned by the getters.
Color blended = new Color (red / 255, green / 255, blue / 255);
So far for the color example. Generally if you want a linear interpolation between two values you have to do the following:
var firstValue;
var secondValue;
var interpolation;
var interpolated = firstValue * interpolation +
secondValue * (1 - interpolation);
But since you have Color-Objects in your case, you cannot interpolate the whole object in one step, you have to interpolate each relevant value on its own. Eventually you have to interpolate the alpha-channel as well, don´t know that, since you didn´t mention it, but for completeness i include it in this answer.
A color is a point in a three-dimensional space. The exact coordinates used depend on what's called a "color space", of which there are several: RGB, HSV, and so on. So to compute a color in between two given colors, get those two colors in the same color space, and compute a third point between those two along the line in 3d-space between them.
The simplest way to do this would be simply to do a linear interpolation for each of the three values of the colorspace (R, G, and B, for example). But there's a further complication that the coordinate values are often not linear, so you have to linearize them first (for example, TV colors are exponential with a lambda of about 2.2). Depending on your application, incorrectly assuming linearity might work OK anyway, especially if the starting colors are already close.
(As mentioned by luk2302, add a fourth coordinate for alpha if necessary).
You could use Java.awt.color by doing somting like this:
public Color mixColors(Color color1, Color color2, double percent){
double inverse_percent = 1.0 - percent;
int redPart = (int) (color1.getRed()*percent + color2.getRed()*inverse_percent);
int greenPart = (int) (color1.getGreen()*percent + color2.getGreen()*inverse_percent);
int bluePart = (int) (color1.getBlue()*percent + color2.getBlue()*inverse_percent);
return new Color(redPart, greenPart, bluePart);
}
I have found this code on JavaDoc, but I can't seem to understand it.
output.setRGB(x, y, (image.getRGB(x, y) & 0xff00ff00)
| ((image.getRGB(x, y) & 0xff0000) >> 16)
| ((image.getRGB(x, y) & 0xff) << 16));
All I know that this code turns blue color to red in a BufferedImage.
but what if I want to replace blue with white or some other color and vice-versa?
I would appreciate any help.
Colors are stored like this, in hexadecimal:
RRGGBBAA
Red, green, blue, alpha. Now let's take a look at one of the lines:
(image.getRGB(x, y) & 0xff0000) >> 16
image.getRGB(x, y) would return an RRGGBBAA value, and this line is bitmasking it with 0xff0000. Here is a visual:
RRGGBBAA
&
00FF0000
=
00GG0000
Therefore, it transforms the RRGGBBAA value into GG0000.
Then, there is a bitshift 16 binary bits to the right. Java can't shift bits in hexadecimal, but we are visualizing the colors in hexadecimal right now. Therefore, we must convert the 16 binary shifts into 4 hex shifts, because hexadecimal is base-16. Binary is base-2, and 2^4 is 16, the base of hexadecimal.
Therefore, you must shift right 4 bits. This would turn GG0000 into GG, since the bits are being shifted 4 places to the right.
Therefore, we now have the value for the amount of green in our color.
You can apply similar logic to the other lines to see how they work.
When I work with color I use different idea:
BufferedImage image = //create Buffered image
int rgb = image.getRGB(x,y); //get Rgb color value
Color color = new Color(rgb); // create color with this value
Color resultColor = new Color(color.getRed(), color.getBlue(), color.getGreen()); //create new color change blue and green colors values
image.setRGB(x,y,resultColor.getRGB()); //set color
I think this idea is easier to understand.
if you want to get white color use this :
BufferedImage image = new BufferedImage();
Color color = new Color(255,255,255);
image.setRGB(x,y,color.getRGB());
I am trying to make a color change on a canvas in java to respresent how strong or weak the values respresented by color are relative to each other.
The rgb colors have to be the same color just different shades, like white to grey to black and every shade of grey in between. How can I change the rgb values considering that the values I am representing vary a lot, from -9999999 to positive 9999999.
I think you should take a look at HSL/HSV instead of RGB.
While RGB is elementary in nature in that it expresses colors in terms of the primaries, it does not allow you to make "understandable" changes to the R, G or B values to arrive at "similar" colors. With a HSL/HSV model, you will be able to make changes to Brightness/Lightness/Value (L/V) to arrive at colors with varying amounts of gray, or make changes to Hue (H) to obtain similar colors across the spectrum. You can start at full brightness (White) and create darker tones of gray by decreasing the value of L/V and eventually reach the color of no brightness (Black).
A very mild introduction to color theory, for developers is available here.
As to your question, you should express your colors in terms of HSL, with increasing values of Saturation to have a range of colors starting from white to black. Of course, if you want gray tones in between white and black without any other color, you should keep the hue to a minimum.
A short example on how to get a range of colors follows. For brevity, I've populated the colors into an array, but that is not required since you might want to use the color rightaway (besides considering memory requirements).
private Color[] produceColorRange(int steps)
{
float value = 1.0f; //Starting with full brightness
Color[] colors = new Color[steps];
for(int ctr = 0; ctr < steps; ctr++)
{
value = value - (1.0f/steps); //tend to darkness
int rgb = Color.HSBtoRGB(0.7f, 0.0f, value); //create a darker color
//Hue is Blue, not noticeable
//because Saturation is 0
Color color = new Color(rgb);
colors[ctr] = color;
}
return colors;
}
If you use the above method and paint a JFrame, you will be able to get a result similar to the one below (except that I've modified the hue and saturation to get my color range).
Note that if you want a simpler way of getting a color range, initialize a Color object with Color.WHITE and invoke color.darker(). Of course, you will not be able to control the increment.
Yes, scale your values to fit your domain. That depends on how your RGB values are stored. Usually, 8 bits are used for each. Since grey has R = G = B, you want to scale values in range (-9999999,9999999) to (0, 255).
Consider x in the first interval. Since the first range covers also negative numbers, first, do a shift.
x = x + 9999999
Now x is in the interval (0, 19999998). And the next step is to scale it down to (0, 255). Since the colour values grow linearly in that interval, all you have to do is this:
x = x * 255 / 19999998
Now x is in the interval (0, 255) just like you want.
Generally, if your inital values are in an interval (a, b) and want to transform it into (0, c), apply this formula: (Note that a can be negative)
x = (x - a) * c / (b - a)
So if you R, G, B values are 16 bits long, c will be 2**16 = 65536 and the formula:
x = (x + 9999999) * 65536 / 19999998
Hope that helps.
I'm not completely sure I understand your question, but, if I do:
Why not just scale the RGB values to the values in your range (from -9999999 to positive 9999999)? Moreover, set R, G, and B all to the same value so that you're using shades of gray to represent the value.
Like this:
private final int MIN = -9999999;
private final int MAX = 9999999;
public Color getScaledColor(int val) {
int gray = (int) Math.round((double) (val - MIN) / (double) (MAX - MIN)
* 255.0);
Color color = new Color(gray, gray, gray);
return color;
}
Note that this solution will not give unique colors for all the values in the range you specified. But also keep in mind that the human eye can only distinguish between so many shades (and 2 * 9999999 + 1 is probably more than the number of shades than it can distinguish between).
The HSL Color class implements the formulas provided in the Wikipedia link on HSL/HSV provide above.