Algorithm of bitmap getbrightness() in C# - c#

I want to implement a function in java that calculate brightness of a color exactly as same as C# getbrightness() function. So I need to know the exact algorithm that used in C#. There is some algorithms here but all of them have about 5% error.

Use official source:
http://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/Color.cs#23adaaa39209cc1f
public float GetBrightness()
{
float r = (float)R / 255.0f;
float g = (float)G / 255.0f;
float b = (float)B / 255.0f;
float max, min;
max = r; min = r;
if (g > max) max = g;
if (b > max) max = b;
if (g < min) min = g;
if (b < min) min = b;
return (max + min) / 2;
}

Related

Is there mathematical gamma function in C#?

I'd like to make a scientific calculator in C#, but I didn't find gamma function to
calculate fractal factorials.
The function's description is below:
https://en.wikipedia.org/wiki/Gamma_function
How can I reach gamma function in C#?
Install the Math.NET package from nuget
Documentation on the Gamma Function : https://numerics.mathdotnet.com/Functions.html
The Math.NET package is indeed an easy way to get the gamma function. Please keep in mind that gamma(x) is equal to (x-1)!. So, gamma(4.1) = 6.813 while 4.1! = 27.932. To get 4.1! from gamma(4.1), you can multiply gamma(4.1) by 4.1, or simply take the gamma of 5.1 instead. (I see no need to show a bunch of digits of precision here.)
In C#:
using MathNet.Numerics; //at beginning of program
private double Factorial(double x)
{
double r = x;
r *= SpecialFunctions.Gamma(x);
return r;
//This could be simplified into:
//return x * SpecialFunctions.Gamma(x);
}
private double Factorial2(double x)
{
double r;
r = SpecialFunctions.Gamma(x + 1);
return r;
}
If for some reason you don't want to use Math.Net, you can write your own gamma function as follows:
static int g = 7;
static double[] p = {0.99999999999980993, 676.5203681218851, -1259.1392167224028,
771.32342877765313, -176.61502916214059, 12.507343278686905,
-0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7};
Complex MyGamma(Complex z)
{
// Reflection formula
if (z.Real < 0.5)
{
return Math.PI / (Complex.Sin(Math.PI * z) * MyGamma(1 - z));
}
else
{
z -= 1;
Complex x = p[0];
for (var i = 1; i < g + 2; i++)
{
x += p[i] / (z + i);
}
Complex t = z + g + 0.5;
return Complex.Sqrt(2 * Math.PI) * (Complex.Pow(t, z + 0.5)) * Complex.Exp(-t) * x;
}
}
Note that you can replace the data type Complex with double and the Complex. functions with Math. if you don't need complex numbers, like so:
double MyGammaDouble(double z)
{
if (z < 0.5)
return Math.PI / (Math.Sin(Math.PI * z) * MyGammaDouble(1 - z));
z -= 1;
double x = p[0];
for (var i = 1; i < g + 2; i++)
x += p[i] / (z + i);
double t = z + g + 0.5;
return Math.Sqrt(2 * Math.PI) * (Math.Pow(t, z + 0.5)) * Math.Exp(-t) * x;
}
This is from an old wiki page (which has been replaced) but is copied here.

C# Color Matching

Can you help me with my color matching
I tried to search some codes it didn't work well
My logic is like below, with adjustable tolerance like 5% or 10% closest to color:
Red and Light Red = True
Red and Dark Red = True
Red and black = False
here's my code but it didn't work very well
public static bool MatchArgb(int Argb1, int Argb2, int tolerance)
{
Color c1 = Color.FromArgb(Argb1);
Color c2 = Color.FromArgb(Argb2);
return Math.Abs(c1.R - c2.R) <= tolerance ^
Math.Abs(c1.G - c2.G) <= tolerance ^
Math.Abs(c1.B - c2.B) <= tolerance;
}
public static bool MatchColor(Color c1, Color c2, int tolerance)
{
return Math.Abs(c1.R - c2.R) <= tolerance ^
Math.Abs(c1.G - c2.G) <= tolerance ^
Math.Abs(c1.B - c2.B) <= tolerance;
}
Maybe it is a good idea to check how this is done in Paint.NET. I found a clone of it and the corresponding source code here: Pinta/Flood Tool
private static bool CheckColor (ColorBgra a, ColorBgra b, int tolerance)
{
int sum = 0;
int diff;
diff = a.R - b.R;
sum += (1 + diff * diff) * a.A / 256;
diff = a.G - b.G;
sum += (1 + diff * diff) * a.A / 256;
diff = a.B - b.B;
sum += (1 + diff * diff) * a.A / 256;
diff = a.A - b.A;
sum += diff * diff;
return (sum <= tolerance * tolerance * 4);
}

Colors Harmony Theory and Algorithm, compute complementary, triad, tetratic, etc

currently working on a application and trying to find colors(complementary, split-Complementary, analogous, triad, tetratic, square, etc...) from a provided base colors.
What i am doing right now:
Convert RGB Color to HSV
Adjust the H value to get a color around the 360 degrees wheel(S and V values are untouched)
Convert HSV back to RGB
Here is an example for Triad(hsv object represent the base color):
colors.Add(new HSVData() { h = hsv.h + 120, s = hsv.s, v = hsv.v });
colors.Add(new HSVData() { h = hsv.h - 120, s = hsv.s, v = hsv.v });
And for Square:
colors.Add(new HSVData() { h = hsv.h + 90, s = hsv.s, v = hsv.v });
colors.Add(new HSVData() { h = hsv.h + 180, s = hsv.s, v = hsv.v });
colors.Add(new HSVData() { h = hsv.h + 270, s = hsv.s, v = hsv.v });
RGB to HSV:
public static HSVData RGBtoHSV(RGBResult RGB)
{
double min;
double max;
double delta;
double r = (double)RGB.r / 255;
double g = (double)RGB.g / 255;
double b = (double)RGB.b / 255;
double h;
double s;
double v;
min = Math.Min(Math.Min(r, g), b);
max = Math.Max(Math.Max(r, g), b);
v = max;
delta = max - min;
if (max == 0 || delta == 0)
{
s = 0;
h = 0;
}
else
{
s = delta / max;
if (r == max)
{
// Between Yellow and Magenta
h = (g - b) / delta;
}
else if (g == max)
{
// Between Cyan and Yellow
h = 2 + (b - r) / delta;
}
else
{
// Between Magenta and Cyan
h = 4 + (r - g) / delta;
}
}
h *= 60;
if (h < 0)
{
h += 360;
}
return new HSVData()
{
h = (int)(h / 360 * 255),
s = (int)(s * 255),
v = (int)(v * 255)
};
}
HSV to RGB:
public static Color ConvertHsvToRgb(float h, float s, float v)
{
byte MAX = 255;
h = h / 360;
if (s > 0)
{
if (h >= 1)
h = 0;
h = 6 * h;
int hueFloor = (int)Math.Floor(h);
byte a = (byte)Math.Round(MAX * v * (1.0 - s));
byte b = (byte)Math.Round(MAX * v * (1.0 - (s * (h - hueFloor))));
byte c = (byte)Math.Round(MAX * v * (1.0 - (s * (1.0 - (h - hueFloor)))));
byte d = (byte)Math.Round(MAX * v);
switch (hueFloor)
{
case 0: return Color.FromArgb(MAX, d, c, a);
case 1: return Color.FromArgb(MAX, b, d, a);
case 2: return Color.FromArgb(MAX, a, d, c);
case 3: return Color.FromArgb(MAX, a, b, d);
case 4: return Color.FromArgb(MAX, c, a, d);
case 5: return Color.FromArgb(MAX, d, a, b);
default: return Color.FromArgb(0, 0, 0, 0);
}
}
else
{
byte d = (byte)(v * MAX);
return Color.FromArgb(255, d, d, d);
}
}
The colors I am getting are wrong according to many online colors tools! Should I be using HSL intead of HSV? What am I doing wrong?
Online Tools compared with:
http://colorschemedesigner.com/
http://www.colorsontheweb.com/colorwizard.asp
Thanks in advance!
What range of values are you expecting to get in the ConvertHsvToRgb method? It looks to me like it is:
0 <= h <= 360
0 <= s <= 1.0
0 <= v <= 1.0
You don't show how you are calling this method, but if you aren't passing values in these ranges, you won't get the correct conversion. You probably want to include a way to normalize the hue to 0 - 360 if you plan to subtract hues, like you do in the triad.
I think your conversions are correct except you should not be converting your h,s,v values to integers; keep them as doubles, in the ranges shown above.
public static HSVData RGBtoHSV(Color RGB)
{
double r = (double)RGB.R / 255;
double g = (double)RGB.G / 255;
double b = (double)RGB.B / 255;
double h;
double s;
double v;
double min = Math.Min(Math.Min(r, g), b);
double max = Math.Max(Math.Max(r, g), b);
v = max;
double delta = max - min;
if (max == 0 || delta == 0)
{
s = 0;
h = 0;
}
else
{
s = delta / max;
if (r == max)
{
// Between Yellow and Magenta
h = (g - b) / delta;
}
else if (g == max)
{
// Between Cyan and Yellow
h = 2 + (b - r) / delta;
}
else
{
// Between Magenta and Cyan
h = 4 + (r - g) / delta;
}
}
h *= 60;
if (h < 0)
{
h += 360;
}
return new HSVData()
{
h = h,
s = s,
v = v
};
}
Now you can pass these h,s,v valuew directly into the ConvertHsvToRgb method. I have changed the arguments to double, validating the saturation and value inputs, and normalized the hue.
public static Color ConvertHsvToRgb(double h, double s, double v)
{
Debug.Assert(0.0 <= s && s <= 1.0);
Debug.Assert(0.0 <= v && v <= 1.0);
// normalize the hue:
while (h < 0)
h += 360;
while (h > 360)
h -= 360;
h = h / 360;
byte MAX = 255;
if (s > 0)
{
if (h >= 1)
h = 0;
h = 6 * h;
int hueFloor = (int)Math.Floor(h);
byte a = (byte)Math.Round(MAX * v * (1.0 - s));
byte b = (byte)Math.Round(MAX * v * (1.0 - (s * (h - hueFloor))));
byte c = (byte)Math.Round(MAX * v * (1.0 - (s * (1.0 - (h - hueFloor)))));
byte d = (byte)Math.Round(MAX * v);
switch (hueFloor)
{
case 0: return Color.FromArgb(MAX, d, c, a);
case 1: return Color.FromArgb(MAX, b, d, a);
case 2: return Color.FromArgb(MAX, a, d, c);
case 3: return Color.FromArgb(MAX, a, b, d);
case 4: return Color.FromArgb(MAX, c, a, d);
case 5: return Color.FromArgb(MAX, d, a, b);
default: return Color.FromArgb(0, 0, 0, 0);
}
}
else
{
byte d = (byte)(v * MAX);
return Color.FromArgb(255, d, d, d);
}
}
Based on my tests, these two methods will now give "round-trip" conversions for any color from RGB to HSV and back.
For the "triad" you are are adjusting +/- 120 degrees from the original color. So for example, if you start with Red as your base color, the +/- 120 degree colors are Green and Blue. These conversions appear to work correctly:
HSVData hsv = HSVData.RGBtoHSV(Color.FromArgb(255, 0, 0));
HSVData hsv2 = new HSVData() { h = hsv.h + 120, s = hsv.s, v = hsv.v };
HSVData hsv3 = new HSVData() { h = hsv.h - 120 , s = hsv.s, v = hsv.v };
Color red = HSVData.ConvertHsvToRgb(hsv.h, hsv.s, hsv.v);
Color green = HSVData.ConvertHsvToRgb(hsv2.h, hsv2.s, hsv2.v);
Color blue = HSVData.ConvertHsvToRgb(hsv3.h, hsv3.s, hsv3.v);
HSVData hsv4 = HSVData.RGBtoHSV(Color.YellowGreen);
Color yellowGreen = HSVData.ConvertHsvToRgb(hsv4.h, hsv4.s, hsv4.v);

BetaInv function in SQL Server

similarly to the question: Inverted beta in MySQL I need to use the BetaInv function inside a SQL Server stored procedure.
function is described here: Excel's BETAINV
is anybody aware of anything similar in TSQL or would you wrap it in a CLR .NET managed SQL user defined function?
I really need to use it within the stored procedure and not as post executing code in the C# side after data has been retrieved with the stored procedure because I should keep all logic on the db server for better reuse.
can I assume that a .NET managed udf running in the SQL Server would perform as fast as a normal native TSQL function?
Thanks!
I've in the end implemented the whole function myself, here the source code in case somebody needs it:
public static class UDFs
{
private const int MAXIT = 100;
private const double EPS = 0.0000003;
private const double FPMIN = 1.0E-30;
[SqlFunction(Name = "BetaInv", DataAccess = DataAccessKind.Read)]
public static SqlDouble BetaInv(SqlDouble p, SqlDouble alpha, SqlDouble beta, SqlDouble A, SqlDouble B)
{
return InverseBeta(p.Value, alpha.Value, beta.Value, A.Value, B.Value);
}
private static double InverseBeta(double p, double alpha, double beta, double A, double B)
{
double x = 0;
double a = 0;
double b = 1;
double precision = Math.Pow(10, -6); // converge until there is 6 decimal places precision
while ((b - a) > precision)
{
x = (a + b) / 2;
if (IncompleteBetaFunction(x, alpha, beta) > p)
{
b = x;
}
else
{
a = x;
}
}
if ((B > 0) && (A > 0))
{
x = x * (B - A) + A;
}
return x;
}
private static double IncompleteBetaFunction(double x, double a, double b)
{
double bt = 0;
if (x <= 0.0)
{
return 0;
}
if (x >= 1)
{
return 1;
}
bt = System.Math.Exp(Gammln(a + b) - Gammln(a) - Gammln(b) + a * System.Math.Log(x) + b * System.Math.Log(1.0 - x));
if (x < ((a + 1.0) / (a + b + 2.0)))
{
// Use continued fraction directly.
return (bt * betacf(a, b, x) / a);
}
else
{
// Use continued fraction after making the symmetry transformation.
return (1.0 - bt * betacf(b, a, 1.0 - x) / b);
}
}
private static double betacf(double a, double b, double x)
{
int m, m2;
double aa, c, d, del, h, qab, qam, qap;
qab = a + b; // These q’s will be used in factors that occur in the coe.cients (6.4.6).
qap = a + 1.0;
qam = a - 1.0;
c = 1.0; // First step of Lentz’s method.
d = 1.0 - qab * x / qap;
if (System.Math.Abs(d) < FPMIN)
{
d = FPMIN;
}
d = 1.0 / d;
h = d;
for (m = 1; m <= MAXIT; ++m)
{
m2 = 2 * m;
aa = m * (b - m) * x / ((qam + m2) * (a + m2));
d = 1.0 + aa * d; //One step (the even one) of the recurrence.
if (System.Math.Abs(d) < FPMIN)
{
d = FPMIN;
}
c = 1.0 + aa / c;
if (System.Math.Abs(c) < FPMIN)
{
c = FPMIN;
}
d = 1.0 / d;
h *= d * c;
aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
d = 1.0 + aa * d; // Next step of the recurrence (the odd one).
if (System.Math.Abs(d) < FPMIN)
{
d = FPMIN;
}
c = 1.0 + aa / c;
if (System.Math.Abs(c) < FPMIN)
{
c = FPMIN;
}
d = 1.0 / d;
del = d * c;
h *= del;
if (System.Math.Abs(del - 1.0) < EPS)
{
// Are we done?
break;
}
}
if (m > MAXIT)
{
return 0;
}
else
{
return h;
}
}
public static double Gammln(double xx)
{
double x, y, tmp, ser;
double[] cof = new double[] { 76.180091729471457, -86.505320329416776, 24.014098240830911, -1.231739572450155, 0.001208650973866179, -0.000005395239384953 };
y = xx;
x = xx;
tmp = x + 5.5;
tmp -= (x + 0.5) * System.Math.Log(tmp);
ser = 1.0000000001900149;
for (int j = 0; j <= 5; ++j)
{
y += 1;
ser += cof[j] / y;
}
return -tmp + System.Math.Log(2.5066282746310007 * ser / x);
}
}
}
as you can see in the code, the SqlFunction is calling the InverseBeta private method which does the job using couple of other methods.
results are the same of Excel.BetaInv up to 5 or 6 digits after comma.

how to generate heat maps given the points

I want to generate a heat map in windows form. I have a set of points as the input. How to go about doing this in the simplest way?
Thanks.
Here is a simple method that will generate a color based on the relative position of a value between min and max. Values closer to min will be greener, while values closer to max will be redder.
To use this method, generate your list of values and calculate the min and max values. If you are building a grid you can handle the RowDataBound event or something similar and call the HeatMap method from there. Get a reference to the cell and set the background color to the color returned by the HeatMap method.
public Color HeatMap(decimal value, decimal min, decimal max)
{
decimal val = (value - min) / (max-min);
return new Color
{
A = 255,
R = Convert.ToByte(255 * val),
G = Convert.ToByte(255 * (1-val)),
B = 0
};
}
Building on the answers already here, this method allows you to specify the Colors you wish to use as the max and min colours.
private Color HeatMapColor(double value, double min, double max)
{
Color firstColour = Color.RoyalBlue;
Color secondColour = Color.LightSkyBlue;
// Example: Take the RGB
//135-206-250 // Light Sky Blue
// 65-105-225 // Royal Blue
// 70-101-25 // Delta
int rOffset = Math.Max(firstColour.R, secondColour.R);
int gOffset = Math.Max(firstColour.G, secondColour.G);
int bOffset = Math.Max(firstColour.B, secondColour.B);
int deltaR = Math.Abs(firstColour.R - secondColour.R);
int deltaG = Math.Abs(firstColour.G - secondColour.G);
int deltaB = Math.Abs(firstColour.B - secondColour.B);
double val = (value - min) / (max - min);
int r = rOffset - Convert.ToByte(deltaR * (1 - val));
int g = gOffset - Convert.ToByte(deltaG * (1 - val));
int b = bOffset - Convert.ToByte(deltaB * (1 - val));
return Color.FromArgb(255, r, g, b);
}
The results look like this for a test DataGrid with some sample data.
This is a fix for Sam's code.
public Color HeatMapColor(decimal value, decimal min, decimal max)
{
decimal val = (value - min) / (max - min);
int r = Convert.ToByte(255 * val);
int g = Convert.ToByte(255 * (1 - val));
int b = 0;
return Color.FromArgb(255,r,g,b);
}
Divide the surface up into a grid of cells, and count the points inside each cell.
Given the count of points, calculate a color for each cell
A solution going from red to yellow to green
static Color CreateHeatColor(int value, decimal max)
{
if (max == 0) max = 1M;
decimal pct = value/max;
Color color = new Color();
color.A = 255;
if (pct < 0.34M)
{
color.R = (byte) (128 + (127 * Math.Min(3 * pct, 1M)));
color.G = 0;
color.B = 0;
}
else if (pct < 0.67M)
{
color.R = 255;
color.G = (byte) (255 * Math.Min(3 * (pct - 0.333333M), 1M));
color.B = 0;
}
else
{
color.R = (byte)(255 * Math.Min(3 * (1M - pct), 1M));
color.G = 255;
color.B = 0;
}
return color;
}
The C# version of "Curtis White"'s answer:
public Color HeatMap(decimal value, decimal min, decimal max)
{
decimal val = (value - min) / (max - min);
int A, B, R, G;
A = 255;
R = Convert.ToByte(255 * val);
B = Convert.ToByte(255 * (1 - val));
G = 0;
return Color.FromArgb(A, R, G, B);
}
This worked well for me.
public Color HeatMap(float value, float max)
{
int r, g, b;
float val = value / max; // Assuming that range starts from 0
if (val > 1)
val = 1;
if (val > 0.5f)
{
val = (val - 0.5f) * 2;
r = Convert.ToByte(255 * val);
g = Convert.ToByte(255 * (1 - val));
b = 0;
}
else
{
val = val * 2;
r = 0;
g = Convert.ToByte(255 * val);
b = Convert.ToByte(255 * (1 - val));
}
return Color.FromArgb(255, r, g, b);
}
If you want red to green via yellow, you could also use HSL to get your heatmap. The numbers in that instance would be 0 - 60, where 0 = red and 60 = green (see figure 11 on this link).
To implement, you need to use System.Runtime.InteropServices and add the following:
[DllImport("shlwapi.dll")]
public static extern int ColorHLSToRGB(int H, int L, int S);
In the method, val is a long value and m_iMax is the largest number in the collection, you could change it as required:
if (val == 0)
return ColorTranslator.ToHtml(Color.FromArgb(255, 255, 255)); // white
else
{
// 0 = red, 60 = green
int col = 60 - (int)(60 * val / m_iMax);
return ColorTranslator.ToHtml(ColorTranslator.FromWin32(ColorHLSToRGB(col, 120, 240)));
}
The following is the result of the code above in a HTML table:

Categories