YCbCr at LipMap detection - java

I'm confused with converting the RGB values to YCbCr color scheme. I used this equation:
int R, G, b;
double Y = 0.229 * R + 0.587 * G + 0.144 * B;
double Cb = -0.168 * R - 0.3313 * G + 0.5 * B + 128;
double Cr = 0.5 * R - 0.4187 * G - 0.0813 * B + 128;
The expected output of YCbCr is normalized between 0-255, I'm confused because one of my source says it is normalized within the range of 0-1.
And it is going well, But I am having problem when getting the LipMap to isolate/detect the lips of the face, I implemented this:
double LipMap = Cr*Cr*(Cr*Cr-n*(Cr/Cb))*(Cr*Cr-n*(Cr/Cb));
n returns 0-255, the equation for n is: n=0.95*(summation(Cr*Cr)/summation(Cr/Cb))
but another sources says: n = 0.95*(((1/k)*summation(Cr*Cr))/((1/k)*summation(Cr/Cb)))
where k is equal to the number of pixels in the face image.
It say's from my sources that it will return a result of 0-255, but in my program it always returns large numbers always, not even giving me 0-255.
So can anyone help me implement this and solve my problem?

From the sources you linked in your comments, it looks like either the equations or the descriptions in the first source are wrong:
If you use RGB values in the Range [0,255] and the given conversion (your Cb conversion differs from that btw.) you should get Cr and Cb values in the same range.
Now if you calculate n = 0.95 * (ΣCr2/Σ(Cr/Cb)) you'll notice that the values for Cr2 range from [0,65025] whereas Cr/Cb is in the range [0,255] (assuming Cb=0 is not possible and thus the highest value would be 255/1 = 255).
If you further assume an image with quite high red and low blue components, you'll get way higher values for n than what is stated in that paper:
Constant η fits final value in range 0..255
The second paper states this, which makes much more sense IMHO (although I don't know whether they normalize Cr and Cb to range [0,1] before the calculation or if they normalize the result which might result in a higher difference between Cr2 and Cr/Cb):
Where (Cr) 2,(Cr/Cb) all are normalized to the
range [0 1].
Note that in order to normalize Cr and Cb to range [0,1] you'd either need to divide the result of your equations by 255 or simply use RGB in range [0,1] and add 0.5 instead of 128:
//assumes RGB are in range [0,1]
double Cb = -0.168 * R - 0.3313 * G + 0.5 * B + 0.5;
double Cr = 0.5 * R - 0.4187 * G - 0.0813 * B + 0.5;

Related

Convert RGB values to binary to decimal

I have the following java code, which takes three double values (between 0 and 1) of the colors RGB and converts them to decimal format. I understood how the first 8 bit save color x, the second 8 bit color y ... and also how to get the decimal value from the resulting binary. what i dont understand 100% is why we multiply with 255 (i know 128+64+32+16+8+4+2+1). What exactly do we get from multiplying the double value with 255. is it a value which can be stored in 8 bit? And why dont we use 256 (possible amount of one color)?
public final double getR() {
return (1 - cyan);
}
public final double getG() {
return (1 - magenta);
}
public final double getB() {
return (1 - yellow);
}
/**
* Gets the rgb color in one integer.
*
* #return an integer containing the red component in bits 16-23, the green component in bits 8-15
* and the blue component in bits 0-7. Bits 24-32 are zero.
*/
public int getRGB() {
int r = (int) Math.round(getB() * 255);
r |= (int) Math.round(getR() * 255) << 16;
r |= (int) Math.round(getG() * 255) << 8;
return r;
}
Thanks
You need the conversion from double because you cannot store the double value into 8 bit.
Your double values are between 0.0 and 1.0. You can see them as the proportion of color used (e.g. 0.33333333 in yellow means that one-third of the possible yellow is used). As you can see such a double can have many decimal places, which means we need a lot of memory (64-bit) to store such a color.
Your function now tries to store the double value into only 8 bit (256 values). As we said the double value can be seen as a portion (between 0 and 1) and the function calculates the same for 8 bit (between 0 and 255). This can simply be done by multiplying the double value with 255. For the example with yellow (0.33333333 of yellow is used) it is: 0.33333333 * 255 = 84,99999915. The meaning is still the same 84,99999915 yellow parts of 255 yellow parts are used, which is still a third.
In order to get a compressed version of this number, it is rounded to the next integer value. In our example, this is 85, which is really close to the actual portion, but we save a lot of memory.
It makes also sense for the lowest double value 0.0, which is converted to the lowest int value 0. The highest double value 1.0 is converted to 255 (highest 8-bit number).
In conclusion, we convert a double (64-bit) into an only 8-bit number, which has the same proportion of the color, but it is not as accurate.
Edit: As there is also a confusion with the 255: 8 bit can store 256 values (0 to 255). If you can choose 256 as a color value somewhere they use the range 1-256 without 0. Essentially it is the same one shifted by 1.

Representing a float as a hexadecimal

I'm studying the float-point type and the examples is a declaration of a variable float expressed as an hexadecimal
float f_in_hex = Ox1.59a8f6p8f
This is the computation to find the float value:
(1 * 16^0 + 5 * 16^-1 + 9 * 16^-2 + 10 * 16^-3 + 8 * 16^-4 + 15 * 16^-5 + 6 * 16^-6) * 2^8
So, I know what is the prefix Ox, that base is 16 but I still don't understand why the exponential part start from 0 and goes with negative values
it's negative value because it's after the decimal point
16^(-1) is the same as 1/16 = .0625
if it was positive exponent it would be a big number.
hope you understand what i mean
that is not a hexadecimal number, firstly Ox is the letter O and it is not a zero, then within the supposed hexadecimal numbers there is a letter p, the hexadecimal numbers only cover from a-f

What does it mean to normalize an array?

I need to normalize an array that contains values between 0 to 1024 into an array that will contain values between 0-255. I am doing this in Java but I am wanting to understand what exactly does it mean to "normalize an array" rather than asking for exact code.
To normalize a vector in math means to divide each of its elements
to some value V so that the length/norm of the resulting vector is 1.
Turns out the needed V is equal to the length (norm) of the vector.
Say you have this array.
[-3, +4]
Its length (in Euclid metric) is: V = sqrt((-3)^2 + (+4)^2) = 5
So its corresponding normalized vector is:
[-3/5, +4/5]
Its length is now: sqrt ( (-3/5)^2 + (+4/5)^2 ) which is 1.
You can use another metric (e.g. I think Manhattan distance)
but the idea is the same. Divide each element of your array
by V where V = || your_vector || = norm (your_vector).
So I think this is what is meant here.
See also:
http://www.fundza.com/vectors/normalize/
http://mathworld.wolfram.com/NormalizedVector.html
Normalize in this case essentially means to convert the value in your original scale to a value on a different scale. Something like this will do it:
x = origVal / 1024;
xNorm = 255 * x;
You will have to decide how you want to handle rounding.
So for example:
.5 = 512 / 1024;
127.5 = 255 * .5;

Recursively create apollonian gaskets [With solution]

Apollonian gaskets = They are planar fractals generated from triples of circles, where each circle is tangent to the other two. In his drawing of the gasket, we start with two externally tangent circles which diameter is D1 and D2. Then we add a third circle which diameter is D1+D2 and to which the two original circles are internally tangent. This is the first generation of circles.
Each subsequent generation of circles is constructed by applying the following scheme:
For any three circles A, B C of any previous generations which are tangent to each other a new circle is constructed which is tangent to A,B,C. The new circle must differ from all circles constructed so far. When a generation is complete, i.e no other circle can be added, then the next generation of circles can start being constructed.
There is an additional stopping rule which prevents from generating infinitesimally small circles. A circle can be added to the gasket if and only if the lenght of its diameter is least minD which is a fixed positive value.
Input consists of one line with three decimal numbers D1, D2 and minD. The number are separated by spaces. The format is usual decimal format (see also the examples bellow) with no exponent part.
It holds that 1.0 ≤ D1, D2 ≤ 1000.0, 0.001 ≤ minD ≤ D1+D2.
Ouput consists of one text line containing two decimal numbers L1 and L2. L1 represents the sum of areas of all circles in the gasket except for the bigggest circle. L2 represents the sum of perimeters of all circles in tin the gasket except for the bigggest circle. Both output values are rounded to 6 decimal digits. Decimal digits must be always present in the output even if some of them are zeros.
Maximim output value is less than 107.
Input
17.000000 40.000000 1.000000
Output
2439.258588 835.263228
2
For given D1 and D2, I create this two circles like this (first iteration):
double D1 = 17.00;
double D2 = 40.00;
double minD = 1.00;
int i = 250, j = 350;
comp.addCircle(i, j, (int) D2, randomColor);
comp.addCircle(i + (int) D2 / 2 + (int) D1 / 2, j, (int) D1, randomColor);
comp.addCircle(i + (int) D1 / 2, j, (int) (D1 + D2), randomColor);
UPDATE:
So, solution is based on Descartes' theorem. We well work with radius, not diameter, and Curvature, with is 1/r.
We will use double for all calculation, but if you work with significantly small numbers, I would prefer BigDecimal. It will slow algorithm, and you should use external method for finding square root, because BigDecimal doesn't have any.
For given D1, D2, minD we modify code above for efficiency:
Some preparation:
double D1 = sc.nextDouble() / 2;
double D2 = sc.nextDouble() / 2;
minD = sc.nextDouble() / 2;
double D3 = D1 + D2;
So, first step looks like this:
Next step looks a little bit more complicated.
Assume we want to write a recursion to solve this problem, and according to Descartes' theorem, for given curvatures of three circles, tangent to each other, (pic. below)
, we could find curvatures of two circles, but for our purposes, we need only small one, so, we can simplify formula to
this.curve = a.curve + b.curve + c.curve + 2 * Math.sqrt(Math.abs(a.curve * b.curve + a.curve * c.curve + b.curve * c.curve));
Lets take a look at Apollonian gaskets again: try to play with it.
See? It is same gaskets, but with different start condition. And whats more important for us, is that it is symmetrical! So, we will calculate just a half, and then multiply result by two!
Lets write a recursion! Inputs will be curvatures of three circles. No output, we will use change our global variables.
double radius_sum = 0.0;
double square_radius_sum = 0.0;
void createAG(double a, double b, double c){
double n = a + b + c + Math.sqrt(a*b + a*c + b*c + 4.0);
if ((minD * n) < 1){
radius_sum += 2. / n; //Remember about symmetry?
square_radius_sum += 2. * (1. / n) * (1. / n); //Remember about symmetry?
createAG(a, b, n);
createAG(a, c, n);
createAG(b, c, n);
}
}
To find the result, we will use formulas to calculate area and perimeter of circle.
Perimeter is length of circumference and equal to .
Area is equal to , as you already know, because we already calculated it in previous step, otherwise we had to store every radius and do more calculations.
radius_sum = 2 * Math.Pi * radius_sum;
square_radius_sum = Math.Pi * square_radius_sum;
But we forget about our first two circles! Let's fix it!
radius_sum += D1*2 + D2*2;
square_radius_sum += D1*D1 + D2*D2;
radius_sum = 2 * Math.Pi * radius_sum;
square_radius_sum = Math.Pi * square_radius_sum;
And there is always a room for improvement. For example, to use IEEE 754 in better way, I assume you will use 1. / x instead of 1 / x.
Thank you!
P.S. Copyright! This task (text and first picture of Apollonian gasket) is created by teachers at CTU, for course ALG. Picture of formulas is from Wikipedia. Everything else is public domain, if not patented, registered e.t.c.
So, solution is based on Descartes' theorem. We well work with radius, not diameter, and Curvature, with is 1/r.
We will use double for all calculation, but if you work with significantly small numbers, I would prefer BigDecimal. It will slow algorithm, and you should use external method for finding square root, because BigDecimal doesn't have any.
For given D1, D2, minD we modify code above for efficiency:
Some preparation:
double D1 = sc.nextDouble() / 2;
double D2 = sc.nextDouble() / 2;
minD = sc.nextDouble() / 2;
double D3 = D1 + D2;
So, first step looks like this:
Next step looks a little bit more complicated.
Assume we want to write a recursion to solve this problem, and according to Descartes' theorem, for given curvatures of three circles, tangent to each other, (pic. below)
, we could find curvatures of two circles, but for our purposes, we need only small one, so, we can simplify formula to
this.curve = a.curve + b.curve + c.curve + 2 * Math.sqrt(Math.abs(a.curve * b.curve + a.curve * c.curve + b.curve * c.curve));
Lets take a look at Apollonian gaskets again: try to play with it.
See? It is same gaskets, but with different start condition. And whats more important for us, is that it is symmetrical! So, we will calculate just a half, and then multiply result by two!
Lets write a recursion! Inputs will be curvatures of three circles. No output, we will use change our global variables.
double radius_sum = 0.0;
double square_radius_sum = 0.0;
void createAG(double a, double b, double c){
double n = a + b + c + Math.sqrt(a*b + a*c + b*c + 4.0);
if ((minD * n) < 1){
radius_sum += 2. / n; //Remember about symmetry?
square_radius_sum += 2. * (1. / n) * (1. / n); //Remember about symmetry?
createAG(a, b, n);
createAG(a, c, n);
createAG(b, c, n);
}
}
To find the result, we will use formulas to calculate area and perimeter of circle.
Perimeter is length of circumference and equal to .
Area is equal to , as you already know, because we already calculated it in previous step, otherwise we had to store every radius and do more calculations.
radius_sum = 2 * Math.Pi * radius_sum;
square_radius_sum = Math.Pi * square_radius_sum;
But we forget about our first two circles! Let's fix it!
radius_sum += D1*2 + D2*2;
square_radius_sum += D1*D1 + D2*D2;
radius_sum = 2 * Math.Pi * radius_sum;
square_radius_sum = Math.Pi * square_radius_sum;
And there is always a room for improvement. For example, to use IEEE 754 in better way, I assume you will use 1. / x instead of 1 / x.
Thank you!
P.S. Copyright! This task (text and first picture of Apollonian gasket) is created by teachers at CTU, for course ALG. Picture of formulas is from Wikipedia. Everything else is public domain, if not patented, registered e.t.c.

Compare Pixel Colour - Java

How can I find similar coloured pixels using colour objects? I know to see if two colors are equal you can use:
a.equals(b);
where a and b are colour objects, but what if I want to find similar shades of blue for example?
Comparing colours is not a trivial problem, there are a variety of different metrics. I can't find a library (easily) that does it but if you have a thorough search I'm sure there'll be something out there Have a look at this class. In the meantime do some reading!
When it comes to programmatically tweaking color values you have lots of options. A very easy solution would be to simply offset the channel values of the color object randomly. Think of it as mutating colors - just take the color you'd like to mutate and generate a few more colors from it:
Color mutateColor(int range){
int r = a.getRed() + (int)(Math.random() * 2 * range - range);
r = Math.min(255, Math.max(0, r));
int g = a.getGreen() + (int)(Math.random() * 2 * range - range);
g = Math.min(255, Math.max(0, g));
int b = a.getBlue() + (int)(Math.random() * 2 * range - range);
b = Math.min(255, Math.max(0, b));
return new Color(r, g, b);
}
This is the simplest example, a range is given and each channel is offset by that same range, resulting in something like this:
This was done with a range value of 10. For added control you could add three arguments to the mutateColor function (offsets for each individual channel). You could also take one range but alter it based on the values already in the channel. For instance:
range = 0.25
red = 100
green = 10
blue = 0
redRange = 100 + rand(-25, 25)
greenRange = 10 + rand(-2.5, 2.5);
etc...
That's just one of many other possibilities.
If you were looking to compare two colors with a tolerance, I ported the code from fredley's link and it works nicely for getting the difference between two colors:
double colorDist(Color e1, Color e2){
long rmean = ( (long)e1.getRed() + (long)e2.getRed() ) / 2;
long r = (long)e1.getRed() - (long)e2.getRed();
long g = (long)e1.getGreen() - (long)e2.getGreen();
long b = (long)e1.getBlue() - (long)e2.getBlue();
return Math.sqrt((((512+rmean)*r*r)>>8) + 4*g*g + (((767-rmean)*b*b)>>8));
}
what if I want to find similar shades of blue for example?
I have no idea what a technical definition for this might mean. However you might be able to use HSL Color to create your own definition.
Basically, I guess you could start by making sure the the Hue of each color is +/- a fixed number of degrees. Then you could narrow it down further by checking if the Saturation and/or Luminosity is within your desired range.

Categories