Dynamically creating colors with different brightness - java

I have a color, which I only know at runtime. Using this color i want to create two new colors, one very bright and one none bright version of the color.
So to clarify, say i have the color Red; I want to create the hex-value for a "Light red" color, and a "Dark red" color.
How would i go about doing this? My code is written in Java using GWT.

Convert the colours to the HSB/HSV (Hue-Saturation-Brightness/Value ) space and adjust the Brightness up for lighter and down for darker. Then convert back again. In Java:
import java.awt.Color;
float hsbVals[] = Color.RGBtoHSB( originalColour.getRed(),
originalColour.getGreen(),
originalColour.getBlue(), null );
Color highlight = Color.getHSBColor( hsbVals[0], hsbVals[1], 0.5f * ( 1f + hsbVals[2] ));
Color shadow = Color.getHSBColor( hsbVals[0], hsbVals[1], 0.5f * hsbVals[2] );
The HSB space is designed for this kind of operation.
The essential point is that you only need to vary the Brightness term to get the lightening/darkening effect you want. You'll have to experiment with how much you lighten/darken.
The above code shifts the Brightness to half-way towards white for the highlight and half-way to black for the shadow. (I used this code to create a highlighted border effect on a button.)
See: http://en.wikipedia.org/wiki/HSL_and_HSV and http://www.acasystems.com/en/color-picker/faq-hsb-hsv-color.htm
Edit: According to the comments, the java.awt.Color class can't be used in GWT. Since the only part of theColor class we're using are the HSV to RGB and the RGB to HSV conversions, as you're using GWT you could instead google for an implementation of those algorithms: Google HSV RGB conversion algorithm. For example:
javascripter.net
cs.rit.edu/~ncs
rapidtables.com (RGB to HSV)
rapidtables.com (HSV to RGB)
StackOverflow: Algorithm to convert RGB to HSV and HSV to RGB?

There are at least two decent solutions to this, one better (more 'proper', anyway) than the other. It depends on what you want to use the colour for, or a tradeoff against short and simple code.
Using a colour space that models brightness
The problem is your colours are probably specified as RGB (ie, amounts of red, green and blue, reflecting your monitor.) The best way to change a colour's brightness is to specify your colours in a different colour space where brightness is one component, such as HSB - hue (the 'colour'), saturation ('amount' of the colour) and brightness (self-explanatory, I think!)
This Wikipedia article on HSL and HSV color models explains far more than you probably want to know :)
Have a look at this HSB demo.
The point is, once your colours are specified in a different space where one component is brightness, changing the brightness is easy because you can increase or decrease that component as you wish, in the same way you might increase or decrease the amount of blue in a RGB colour. Java, I think, has some colour conversion functions built in - some googling found this page with a handy example of Color.RGBtoHSB() and going back again with Color.HSBtoRGB.
Blending with white or black
This is hackier, but effective in most situations, and most code I've written that needs to get two versions of a colour (for a gradient, for example) for something unimportant like a UI background uses this sort of method. The logic is that a colour will be brighter as it gets closer to white (RGB 255,255,255) and darker as it gets closer to black (RGB 0,0,0). So to brighten something, blend with white by, say, 25%. You can blend between two colours by taking a proportion of one colour, and the inverse of that proportion of the other, for each channel / component.
The following is untested, and is a conversion of Delphi code I have used to do the same thing (the code is taken from memory, and on top of that I haven't used Java for years and don't remember the syntax and classes well, so I don't expect this to compile but you should be able to get an idea):
Color Blend(Color clOne, Color clTwo, float fAmount) {
float fInverse = 1.0 - fAmount;
// I had to look up getting colour components in java. Google is good :)
float afOne[] = new float[3];
clOne.getColorComponents(afOne);
float afTwo[] = new float[3];
clTwo.getColorComponents(afTwo);
float afResult[] = new float[3];
afResult[0] = afOne[0] * fAmount + afTwo[0] * fInverse;
afResult[1] = afOne[1] * fAmount + afTwo[1] * fInverse;
afResult[2] = afOne[2] * fAmount + afTwo[2] * fInverse;
return new Color (afResult[0], afResult[1], afResult[2]);
}
And you'd probably use it like:
Color clBrighter = Blend(Color.red, Color.white, 0.25);
You might want to add some safety code, such as ensuring a clamp between 0..255 for each component, or checking that dAmount is truly in the range 0..1.
The Java Color documentation looks like the Color class has all sorts of useful methods. (Edit: I just noticed you said you're using gwt not awt - I haven't used it and have no idea what classes from standard Java are included. This should point you in the right direction anyway.) It's possible this is not the cleanest way in Java - that'll be due to my lack of knowledge of the classes and methods these days - but it should be enough to get you well down the track. Hope that helps!

I don't know in wich format you have the color (I tried to see if GWT uses colors... but they rely heavily on CSS so they don't have specific properties).
Anyway, if you have one value for each component (Red, green, Blue), and each value ranges between 0 and 255 -this is standard- then apply this algorithm:
for each component
multiply the original value by a factor (let's say 1.1, 10% more bright)
convert the float/double value to int
if this value surpass 255, cut it to 255
Then you'll have a new color (a new three component tuple).
Hexa colors
If you have colors in the web format:
RRGGBB
RR - two hexa digits for red
GG - two hexa digits for green
BB - two hexa digits for blue
you'll need to convert them to int and back to hexa:
Hexa string to int
Integer.parseInt("AB", 16"); // returns 171
int to Hexa string
Integer.toHexaString(171); // returns "AB"

Since you are using GWT, you should do your color calculations using HSL rather then RGB, as it's more intuitive, and can be applied as a style color directly to your components.
Your initial color is "red" is defined as "color: hsl(0,100%, 50%)", see http://www.w3.org/TR/css3-color/#hsl-color for more on style colors.
To get a light red, all you need is to increase the L (lightness) component, so a light red would be "color: hsl(0,100%, 75%)". To get a dark red, decrease the L component, "color: hsl(0,100%, 25%)"
To apply your color, just set the color using
component.getElement().getStyle().setColor("hsl(0,100%, 25%)")

Just Add the following function to your code. It will return the hash value for lighter and darker color as per your requirement.
pass two arguments.
(1) the hash value of your selected color.
(2) how much lighter or darker you want (Ex. if you want 10% lighter shade then pass 0.1 as the second argument and if you want 40% darker then pass -0.4(negative value for darker) as the second argument)
So if you want to find 20% lighter shade of red then call as below
String lightred=convert("ff0000",0.2);
public static String convert(String hex, double num) {
String rgb = "#",temp;
int i;
double c,cd;
for (i = 0; i < 3; i++) {
c = Integer.parseInt(hex.substring(i * 2,(i*2)+2), 16);
c = Math.min(Math.max(0, c+(255*num)), 255);
cd=c-(int)c;
if(cd>0){c=(int)c+1;}
temp = Integer.toHexString((int)c);
if(temp.length()<2)
{
temp=temp+temp;
}
rgb += temp;
}
return rgb;
}

Related

Color subtraction RBG or CIElab

I've read few topics here and according to answers there is no exact solution. Anyway lets assume we have RGB color picker (0-255,0-255,0-255) and two colors, one original unmixed and another mixed one, then how do I exactly subtract to find which one was added? Does it actually work as
z - y = x ?
Are there any research formulas?
Another question is if apply CIElab tranformation to get hue saturation brightness then how do I apply these to subtract colors?
You mean additive colour mixing?
In this case, just the light is added. So, it is just addition and subtraction of intensities of light, so RGB is fine. But you need linear colour space. So you need to "unapply" gamma, add or subtract, and apply again gamma.
See https://en.wikipedia.org/wiki/SRGB#Specification_of_the_transformation for the formula to apply Gamma and unapply it: C is channel (R, G, B, each), C_linear is linear space (where you can add and subtract intensities) and C_srgb is the channel value as we use on computers. Note: you should divide and multiply with 255, to normalize values from 0 to 1.
For normal colour mixing (paints, inks, dyes, etc.), this is complex, but one could in such case, CIExyz is preferred: In fact on such space, the result of mixing is in the line between the two original chromacities. Unfortunately, the model do not tell you where the result will be within such line. Usually more data about each colour is needed (often instead of the RGB triplet, a vector of about 60 items [so a data every 5nm])

What is skin colour range in rgb?

I've seen several questions about skin colour already but didn't found an exact skin colour range in rgba. Can someone tell what is a min-max rgba colours for example for a middle-aged European man?
My code is like this:
//Here should be scin min max rgba range
static CvScalar min = cvScalar(0, 0, 130, 0);//BGR-A
static CvScalar max= cvScalar(140, 110, 255, 0);//BGR-A
public static void main(String[] args) {
//read image
IplImage orgImg = cvLoadImage("colordetectimage.jpg");
//create binary image of original size
IplImage imgThreshold = cvCreateImage(cvGetSize(orgImg), 8, 1);
//apply thresholding
cvInRangeS(orgImg, min, max, imgThreshold);
//smooth filter- median
cvSmooth(imgThreshold, imgThreshold, CV_MEDIAN, 13);
//save
cvSaveImage("threshold.jpg", imgThreshold); }
So I need to just specify rgba values here.
There is no real answer to this. Skin tone is highly variable (even for middle age Caucasian men), and when you then throw in lighting effects (over exposure, under exposure, low light, colored incident light) you can't distinguish skin from non-skin based solely on RGB values of pixels.
My advice would be to pick a sensible first approximation, and then tweak the parameters. And don't expect to be able to pick accurately detect skin without taking the context into account ... somehow.
You could take your first approximation by looking at one of the color charts that you get from Googling "skin tone color chart rgb". Take your pick ...
#Stephen C what do u mean by "pick sensible first approximation, and then tweak the parameters" ? Just picking 1 color from a palette and what then?
(Ignoring the issue of lighting effects.) Since colors in RGB define a 3-D space, I propose that there is a region of that space where the colors are "skin" tones. The problem is to get a reasonable approximation of that region, you could start with a color chart of "skin" tones, plot them in 3-D and figure out a simple 3-D hull that encloses them ... and doesn't enclose colors that don't look right to your eye. Then try your "skin detection" based on the hull and adjust accordingly.

What does Graphics.setXORMode(Color) do in simple terms?

Here is what I read about it but cant understand exactly what it does:
One way to implement rubber-banding is to draw in XOR mode. You set
XOR mode by calling the setXORMode() method for a graphics context and
passing a color to it — usually the background color. In this mode
the pixels are not written directly to the screen. The color in which
you are drawing is combined with the color of the pixel currently
displayed together with a third color that you specify, by exclusive
ORing them together, and the resultant pixel color is written to the
screen. The third color is usually set to be the background color, so
the color of the pixel that is written is the result of the following
operation:
resultant_Color = foreground_color^background_color^current_color
I know how XORing works but don't know what the above paragraph means. Please elucidate it for me
It takes a color in and applies an XOR mask just like a regular XOR would a bit mask, except it is on the RGB colors, so it produces the color you pass in if it overlays a color with the same values or the inverse of that colors RGB and and color below its RGB if the values are different.
Just write some code and try it and it will be immediate evident what happens.

Add a certain amount to the 'red' value of RGB to create a sunset affect, help please. (java)

Ok, so I want a program that goes through a picture line by line, and adds a certain amount to the red value (RGB) to create a sunset affect. The only problem is that, when you get the different values for red, green, and blue, I cannot add, lets say, 50 to the red value to get a sunset affect. The code below is only the part that is responsible for looping through the lines and changing the pixel values.
for(int y=0; y < sunsetPic.getHeight(); y++)
{
for(int x = 0; x < sunsetPic.getWidth(); x++)
{
targetPixel = sunsetPic.getPixel(x,y);
pixelColor = targetPixel.getColor();
redValue = pixelColor.getRed();
greenValue = pixelColor.getGreen();
blueValue = pixelColor.getBlue();
pixelColor = new Color(redVlue + 50, greenValue, blueValue);
targetPixel.setColor(pixelColor);
}
}
As you can see, I cannot just add 50 to the redValue to create a sunset affect. Can someone please help me by making a way I can get my sunset affect?
To achieve a sunset effect, you need to do a bit more than add a bit of red. Odds are good you'll need to remove a bit of green and blue too. Those removals will likely be proportional removals, leaving a percentage of the original color present. The most flexible technique to go about this is to use one or more color matrices. That way you can independently adjust each output color based on a linear combination of the input colors. Generally, you include the A color, which means that most color matrices are 4x5, with the fifth element being a constant added or subtracted regardless of input.
A code example is here, and depending on your need for fidelity, you can tweak the transformation matrix as many times as you like until you get the visual effects you are seeking.
If you can, load the image into a paint program like Gimp or Photoshop and use that to edit and preview color changes. Once you get the look you want use the percentages of RGB you arrived at and those will be your runtime changes.
I'd suggest using a multiplier instead of an addition and I'd suggest not boosting your Red above 1.0 but follow Edwin Buck's idea of multiplying down Green and Blue.

Scanned image heatmap in java

My issue is this:
I have a black and white scanned image and I need to convert it into a heatmap.If I scan my hand for example, where the pressure is higher the scanned skin will be whiter, where it is less pressure the skin is darker so I need the white to be pure red and the black to be blue while the greys between to vary from yellow to green. So highest pressure red->orange->yellow->green->blue.
Where can I get a java api/sdk/program to do that for me.
Thanks
Your black/white image can be interpreted as a double X from 0 (meaning black) to 1 (meaning white).
Now take the HSV color space:
It consists of a triple (H,S,V) of doulbes (from (0,0,0) to (1,1,1), where H (roughly) resembles the color and S and V modify the color. If you look at the color which different values of H resemble, you will see, that they exactly it your needs. So simple construct a new HSV-Color (X,0.5,0.5) (where X is your gray scale value, change the 0.5 to your needs). If you need RGB-Colors, take the well known formula to convert.

Categories

Resources