Random color in C# - c#

Is there any way to simplify this line of code? Are two calls to Color.FromArgb() really necessary?
Color c = Color.FromArgb(255, Color.FromArgb(Convert.ToInt32(rand.Next(0x1000000))));
Without the duplicated Color.FromArgb() call I get only Alpha=0 colors.
References:
How do I generate random dark colors in C#?

Just tried this in LinqPad and it seemed to do the trick:
var random = new Random();
System.Drawing.Color c;
unchecked
{
var n = (int)0xFF000000 + (random.Next(0xFFFFFF) & 0x7F7F7F);
Console.WriteLine($"ARGB: {n}");
c = System.Drawing.Color.FromArgb(n);
}
Console.WriteLine($"A: {c.A}");
Console.WriteLine($"R: {c.R}");
Console.WriteLine($"G: {c.G}");
Console.WriteLine($"B: {c.B}");
More concisely, it would be:
var random = new Random();
Color c;
unchecked
{
c = Color.FromArgb((int)0xFF000000 + (random.Next(0xFFFFFF) & 0x7F7F7F));
}
Or if you want to get really funky with bit manipulation (this is not more efficient, just saves you typing some 0s):
c = Color.FromArgb((int)(0xFF << 24 ^ (random.Next(0xFFFFFF) & 0x7F7F7F)));
Original poster pointed out that an extra pair of brackets eliminates the need for unchecked:
c = Color.FromArgb((int)(0xFF000000 + (random.Next(0xFFFFFF) & 0x7F7F7F)));
Bit of an explanation. ARGB is using a signed 32 bit int to represent four bytes, A, R, G, and B. We want the colour to be solid, so A needs to be 255 hence:
0xFF000000
Then random.Next(0xFFFFFF) generates a pseudo-random 24 bit number taking care of the R, G and B bytes. As the question only wanted dark colours we mask off the most significant bit of each byte. For a simple example, say the RNG spat out the max value (equivalent to white):
0xFFFFFF = 111111111111111111111111
We then do a bitwise AND to chop off the most significant bits:
0x7F7F7F = 011111110111111101111111
111111111111111111111111 & 011111110111111101111111 = 011111110111111101111111

You could just use the overload that takes the individual color components. You're trading off 2 calls to FromArgb() for 3 random numbers.
var rand = new Random();
Color c = Color.FromArgb(rand.Next(256), rand.Next(256), rand.Next(256));

There is method, that accepts only one argument:
Color c = Color.FromArgb(rand.Next(int.MaxValue) | (0xFF0000));
0xFF0000 - to create solid color (alpha = 255)

I created library (MIT license) for work with colors. Also I added implementation with random generator.
Examples:
Get random color:
RGB rgb = ColorGenerator.GetRandomColor<RGB>();
HEX hex = ColorGenerator.GetRandomColor<HEX>();
CMYK cmyk = ColorGenerator.GetRandomColor<CMYK>();
Another methods:
GetLightRandomColor<type>();
GetDarkRandomColor<type>();
GetRedRandomColor<type>();
GetGreenRandomColor<type>();
GetBlueRandomColor<type>();
Links:
Github and NuGet.

Related

How can I can the integer value (range 0-255) of a grayscale image pixel

Hi I want to get the integer values (0-255 range) of a gray scale image ....this code shows me the R,G,B values not one value..how can i get it?
Bitmap temp1 = image1;
for (int i = 0; i < temp1.Height; i++)
{
for (int j = 0; j < temp1.Width; j++)
{
Color cl = new Color();
cl = temp1.GetPixel(i, j);
}
}
just read the properties R or G or B, any of them will have the same value.
var intValue = cl.R;
If your source image is greyscale and you just want the level of greyness, just pick any of the three components. They will be equal.
If your source image is color but you want to get the grey equivalent, you can convert your color to a grey value in the range 0..255 by blending the red, green and blue color components together. The blending factors are different because the human eye has different sensitivity to the three primary colors. For fun, try varying the factors (e.g. use 0.3333 for each) and see what the result looks like.
Color cl = c.GetPixel(i, j); // No need to separately allocate a new Color()
int greyValue = (int)((cl.R * 0.3) + (cl.G * 0.59) + (cl.B * 0.11));
Color grey = Color.FromArgb(cl.A, greyValue, greyValue, greyValue);
Note that it is quite slow to loop through a larger Bitmap, using GetPixel() on each pixel. There are much faster techniques available.
UPDATE
Here's an example image with different scaling factors for R, G, and B applied. The image will always be greyscaled because the same numeric value is used for each RGB component in the modified image, but the relative lightness does change. The middle image uses scaling factors suitable for the human eye. Note how blue areas in the original image seem oversaturated in the rightmost version.
There are multiple ways to get grayscale from RGB.
A common way is to do (R+G+B)/3
Others are computing some luminance Luminance measure (Lab, YUV, HSV)

OpenCV: how to increase color channel

Within a RGB image (from a webcam) I'm looking for a way to increase the intensity/brightness of green. Glad if anyone can give a starting point.
I'm using AFORGE.NET in C# and/or OpenCV directly in C++.
in general multiplication of pixel values is though of as an increase in contrast and addition is though of as an increase in brightness.
in c#
where you have an array to the first pixel in the image such as this:
byte[] pixelsIn;
byte[] pixelsOut; //assuming RGB ordered data
and contrast and brightness values such as this:
float gC = 1.5;
float gB = 50;
you can multiply and/or add to the green channel to achieve your desired effect: (r - row, c - column, ch - nr of channels)
pixelsOut[r*w*ch + c*ch] = pixelsIn[r*w*ch + c*ch] //red
int newGreen = (int)(pixelsIn[r*w*ch + c*ch+1] * gC + gB); //green
pixelsOut[r*w*ch + c*ch+1] = (byte)(newGreen > 255 ? 255 : newGreen < 0 ? 0 : newGreen); //check for overflow
pixelsOut[r*w*ch + c*ch+2] = pixelsIn[r*w*ch + c*ch+2]//blue
obviously you would want to use pointers here to speed things up.
(Please note: this code has NOT BEEN TESTED)
For AFORGE.NET, I suggest use ColorRemapping class to map the values in your green channel to other value. The mapping function should be a concave function from [0,255] to [0,255] if your want to increase the brightness without losing details.
This is what I came up with after reading through many pages of AForge.NET and OpenCV documentation. If you apply the saturation filter first, you might get a dizzy image. If you apply it later you will get a much clearer image but some "light green" pixels might have been lost before while applying the HSV filter.
// apply saturation filter to increase green intensity
var f1 = new SaturationCorrection(0.5f);
f1.ApplyInPlace(image);
var filter = new HSLFiltering();
filter.Hue = new IntRange(83, 189); // all green (large range)
//filter.Hue = new IntRange(100, 120); // light green (small range)
// this will convert all pixels outside the range into gray-scale
//filter.UpdateHue = false;
//filter.UpdateLuminance = false;
// this will convert all pixels outside that range blank (filter.FillColor)
filter.Saturation = new Range(0.4f, 1);
filter.Luminance = new Range(0.4f, 1);
// apply the HSV filter to get only green pixels
filter.ApplyInPlace(image);

How to overlay two images (as byte arrays)

People, i'm sure that it's quite easy, but google didn't helped...
Here is the task - i have two byte arrays (as ARGB), representing my images. They have the same size.
What operation i should perform (byte by byte) to overlay one image to another?
Second image has some transparency, which must be considered.
To clear, im looking for a code like this:
bytes[] result = new bytes[first.Length];
for(i = 0; i< first.Lenght;i++)
{
result[i] = first[i] !!%SOMETHING%!! second[i];
}
Simple guesses like bitwise OR (I know - that's stupid ;) ) don't working.
Thx for your answers.
edit: i can't use standart library becouse of security issues (all this strange manipulations occur on Silverlight).
Assuming that you are in fact working with bitmaps, you'll likely find it easier to just let the library do this for you.
The System.Drawing.Graphics class has a CompositingMode property that can be set to either SourceCopy (the default - overwrites the background colour) or SourceOver (blends with the background color).
See MSDN: How to Use Compositing Mode to Control Alpha Blending for more detail.
If you just want the raw math, alpha blending is pretty simple. For an alpha value a between 0.0 and 1.0, the result should be:
(aOld * oldValue) + ((1 - aOld) * aNew * newValue)
Where oldValue is the previous value before overlay, newValue is what you want to overlay with, and aOld and aNew are the old and new alpha values respectively. You obviously need to do this calculation for the R, G, and B values separately.
See also: Alpha Compositing (wiki link) for a more thorough explanation.
Update: I think it should be easy to figure out how to adapt this to the code in the OP, but I guess not everybody's a math person.
I'm going to assume that the byte[] is a repeating sequence of A, R, G, B values (so Length would be a multiple of 4). If that's not the case, then you'll have to adapt this code to whatever storage format you're using.
bytes[] result = new bytes[first.Length];
for(i = 0; i < first.Length; i += 4)
{
byte a1 = first[i];
byte a2 = second[i];
byte r1 = first[i+1];
byte r2 = second[i+1];
byte g1 = first[i+2];
byte g2 = second[i+2];
byte b1 = first[i+3];
byte b2 = second[i+3];
byte a = a1 + (255 - a1) * a2 / 255;
byte r = r1 * a1 / 255 + r2 * (255 - a1) * a2 / 65025;
byte g = g1 * a1 / 255 + g2 * (255 - a1) * a2 / 65025;
byte b = b1 * a1 / 255 + b2 * (255 - a1) * a2 / 65025;
result[i] = a;
result[i+1] = r;
result[i+2] = g;
result[i+3] = b;
}
I think you have the right idea. The operation you use depends on what you want for the output. Here are some operations that are useful:
average - a common way to combine
minimum
maximum
bitwise replace
xor
or
add
subtract
multiply image 1 value by (image 2 scaled 0 to 1). This will put more of image 1 on the bright places of image 2 and not so much on the dark places. Try them out and see what you like best, or better yet, let the user select.
You can probable add or or the transparency bytes, and use one of the other operations for the each of the three colors.

Convert RGB method?

How can I do this?
int blue = Color.Blue.ToArgb();
int yellow = Color.Yellow.ToArgb();
blue = (blue + yellow) / 2;
Color Blue = ConvertFromRGB(blue);
I think what you're looking for is this:
var blueColor = Color.FromArgb((blue + yellow) / 2);
However, I don't think it will give you the result you actually want.
You must be quite careful about mixing colours in this way. The int value representing a colour in ARGB form is fairly arbitrary as far as the coder is concerned. It's probably best to mix RGB components individually, like:
var color1 = Color.Blue;
var color2 = Color.Yellow;
var blueColor = Color.FromArgb((color1.R + color2.R) / 2,
(color1.G + color2.G) / 2, (color1.B + color2.B) / 2);
This interpolates (taking the centre point) between two colours, and should give you something that looks much more like the blend of the two colours.
(Note that I assume you're referring to the System.Drawing.Color type here.)
I think this is what you might be looking for:
int blue = Color.Blue.ToArgb();
int yellow = Color.Yellow.ToArgb();
blue = (blue + yellow)/2;
Color Blue = Color.FromArgb(blue);
Just average the colors component-wise, if that is what you are trying to do:
Color average = ConvertFromRGB((Color.Blue.R + Color.Yellow.R) / 2), (Color.Blue.G + Color.Yellow.G) / 2), (Color.Blue.B + Color.Yellow.B) / 2));
It would be useful to know what you're expecting from the second assign to 'blue' - you certainly won't be getting a shade of blue (more like red).
The problem is that the Color class keeps its ARGB values as Int32 because each of the 4 bytes represents one of the Alpha, Red, Blue and Green values.
Asking to add together two colours in their Int32 form is going to cause unexpected values, as one byte 'overflows' into the next (what happens when you add 255 and 1?)
Color.Blue, for example, is -16776961. That's because it has 4 bytes that look like this:
0: 255
1: 0
2: 0
3: 255
Or:
11111111 00000000 00000000 11111111
You'll find it much clearer to break the ARGB components down into individual bytes, System.Drawing.Color allows you to do this via its instance properties:
blue.A
blue.R
blue.G
blue.B
You can safely manipulate these, but remember that they're an instance of Byte, so you can't assign a value out of the range 0-255. To create a colour from the component bytes, use:
Color.FromArgb(a, r, g, b);
Where a, r, g, b are bytes.
Somewhat confusingly, Color.FromArgb accepts int parameters, rather than bytes. I'm afraid I've no idea why, someone better than me will have to answer that, but casting a byte to an int with produce an int with a value between 0 and 255, so it's safe to use this. Color also has a private CheckByte class that it passes each argument into so you'll get an ArgumentException rather than an unexpected color (that you'll likely get with your non-component approach).

How do I determine darker or lighter color variant of a given color?

Given a source color of any hue by the system or user, I'd like a simple algorithm I can use to work out a lighter or darker variants of the selected color. Similar to effects used on Windows Live Messenger for styling the user interface.
Language is C# with .net 3.5.
Responding to comment: Color format is (Alpha)RGB. With values as bytes or floats.
Marking answer: For the context of my use (a few simple UI effects), the answer I'm marking as accepted is actually the most simple for this context. However, I've given up votes to the more complex and accurate answers too. Anyone doing more advanced color operations and finding this thread in future should definitely check those out. Thanks SO. :)
In XNA there is the Color.Lerp static method that does this as the difference between two colours.
Lerp is a mathematical operation between two floats that changes the value of the first by a ratio of the difference between them.
Here's an extension method to do it to a float:
public static float Lerp( this float start, float end, float amount)
{
float difference = end - start;
float adjusted = difference * amount;
return start + adjusted;
}
So then a simple lerp operation between two colours using RGB would be:
public static Color Lerp(this Color colour, Color to, float amount)
{
// start colours as lerp-able floats
float sr = colour.R, sg = colour.G, sb = colour.B;
// end colours as lerp-able floats
float er = to.R, eg = to.G, eb = to.B;
// lerp the colours to get the difference
byte r = (byte) sr.Lerp(er, amount),
g = (byte) sg.Lerp(eg, amount),
b = (byte) sb.Lerp(eb, amount);
// return the new colour
return Color.FromArgb(r, g, b);
}
An example of applying this would be something like:
// make red 50% lighter:
Color.Red.Lerp( Color.White, 0.5f );
// make red 75% darker:
Color.Red.Lerp( Color.Black, 0.75f );
// make white 10% bluer:
Color.White.Lerp( Color.Blue, 0.1f );
Simply multiply the RGB values by the amount you want to modify the level by. If one of the colors is already at the max value, then you can't make it any brighter (using HSV math anyway.)
This gives the exact same result with a lot less math as switching to HSV and then modifying V. This gives the same result as switching to HSL and then modifying L, as long as you don't want to start losing saturation.
HSV ( Hue / Saturation / Value ) also called HSL ( Hue / Saturation / Lightness ) is just a different color representation.
Using this representation is it easier to adjust the brightness. So convert from RGB to HSV, brighten the 'V', then convert back to RGB.
Below is some C code to convert
void RGBToHSV(unsigned char cr, unsigned char cg, unsigned char cb,double *ph,double *ps,double *pv)
{
double r,g,b;
double max, min, delta;
/* convert RGB to [0,1] */
r = (double)cr/255.0f;
g = (double)cg/255.0f;
b = (double)cb/255.0f;
max = MAXx(r,(MAXx(g,b)));
min = MINx(r,(MINx(g,b)));
pv[0] = max;
/* Calculate saturation */
if (max != 0.0)
ps[0] = (max-min)/max;
else
ps[0] = 0.0;
if (ps[0] == 0.0)
{
ph[0] = 0.0f; //UNDEFINED;
return;
}
/* chromatic case: Saturation is not 0, so determine hue */
delta = max-min;
if (r==max)
{
ph[0] = (g-b)/delta;
}
else if (g==max)
{
ph[0] = 2.0 + (b-r)/delta;
}
else if (b==max)
{
ph[0] = 4.0 + (r-g)/delta;
}
ph[0] = ph[0] * 60.0;
if (ph[0] < 0.0)
ph[0] += 360.0;
}
void HSVToRGB(double h,double s,double v,unsigned char *pr,unsigned char *pg,unsigned char *pb)
{
int i;
double f, p, q, t;
double r,g,b;
if( s == 0 )
{
// achromatic (grey)
r = g = b = v;
}
else
{
h /= 60; // sector 0 to 5
i = (int)floor( h );
f = h - i; // factorial part of h
p = v * ( 1 - s );
q = v * ( 1 - s * f );
t = v * ( 1 - s * ( 1 - f ) );
switch( i )
{
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
default: // case 5:
r = v;
g = p;
b = q;
break;
}
}
r*=255;
g*=255;
b*=255;
pr[0]=(unsigned char)r;
pg[0]=(unsigned char)g;
pb[0]=(unsigned char)b;
}
Rich Newman discusses HSL color with respect to .NET System.Drawing.Color on his blog and even provides an HSLColor class that does all the work for you. Convert your System.Drawing.Color to an HSLColor, add/subtract values against the Luminosity, and convert back to System.Drawing.Color for use in your app.
You can convert your color into the HSL color-space, manipulate it there and convert back to your color-space of choice (most likely that's RGB)
Lighter colors have a higher L-value, darker a lower.
Here's the relevant stuff and all the equations:
http://en.wikipedia.org/wiki/HSL_color_space
Another method is to simply interpolate your color with white or black. This will also desaturate the color a bit but it's cheaper to calculate.
I have used the ControlPaint.Dark() and .Light() in System.Windows.Forms.
I'm guessing you're using RGB with byte values (0 to 255) as that's very common everywhere.
For brighter, average the RGB values with the RGB of white. Or, to have some control over how much brightening, mix in them in some proportion. Let f vary from 0.0 to 1.0, then:
Rnew = (1-f)*R + f*255
Gnew = (1-f)*G + f*255
Bnew = (1-f)*B + f*255
For darker, use the RGB of black - which, being all zeros, makes the math easier.
I leave out details such as converting the result back into bytes, which probably you'd want to do.
If you are using RGB colors I would transform this color paramaters to HSL (hue, saturation, lightness), modify the lightness parameter and then transform back to RGB. Google around and you'll find a lot of code samples on how to do these color representation transformations (RGB to HSL and viceversa).
This is what I quickly found:
http://bytes.com/forum/thread250450.html
Assuming you get the color as RGB, first convert it to HSV (hue, saturation, value) color space. Then increase/decrease the value to produce lighter/darker shade of the color. Then convert back to RGB.
If your colours are in RGB format (or, presumably CMYK), you can use the fairly crude method of increasing the value of each component of the colour. E.g., in HTML colours are represented as three two-digit hex numbers. #ff0000 will give you a bright red, which can then be faded by increasing the values of the G and B componenets by the same amount, such as #ff5555 (gives a lighter red). Presumably for Hue, Saturation and Lightness (HSL) colours, you can just raise the L component, but I can't say for certain; I'm less familiar with this colour space.
As I say, though, this method is quite crude. From my memories of Live Messenger, it sounds like you're trying to do gradients, which can be applied really quite easily in Windows Presentation Foundation (WPF, part of .NET 3.0). WPF supports many different types of gradient brush, including linear and radial gradients.
I can highly recommend Adam Nathan's book Windows Presentation Foundation Unleashed as a good and thorough introduction to WPF.
HTH
Any variations in color are better done in HSL/HSV.
A good test is to interpolate between two equivalent values in RGB space and HSL space. The ramp in HSL space looks like a natural progression. In RGB space it typically looks quite unnatural. HSL maps to our visual color space perception much better than RGB.
The idea of converting to HSV or some other color space seems good, and may be necessary for precise color work, but for ordinary purposes the error of working in RGB may not be enough to matter. Also, it can be a pain to deal with boundary cases: RGB is a cube-shaped space, while HSV is not. If working with byte values, you can have many-to-one and one-to-many mappings between the spaces. This may or may not be a problem depending on the application. YMMV
This website notes that you can use the ControlPaint class within the BCL C# System.Windows.Forms namespace.

Categories