I am doing some reverse engineering work on a program. One of the things I am trying to pull out of the old data is a color that was chosen from the below color pallet
The way the old software is refrencing the color is by the index in the pallet (so 0 is white, 1 is yellow, 2 is orange, and so on). Is the above pallet a standard layout of some type?
What my best hope is to find some class built in to .NET where I could pass the same index number in and get the color back, however I don't have high hopes for finding something that nice.
Besides using paint and an eyedropper to manually map out the whole table is there any option to make this easier on me?
You can write some code that reads that bitmap and examines the pixels to build the palette of colors in the bitmap you've extracted.
This is a 16 x 16 = 256 palette. The old Software possibly stored this palette in a gif-file. You could build an array of hex values from this palette (hard coded or at runtime).
The first row is a "useful"-colors row.
Row two to eight shifts hue values from hue 338° to hue 335°.
Row nine to fifteen show (7) tints and (8) shades (HSB color model) of hue 0°, 30°, 60°, 116°, 180°, 230° and 300°.
Last row is obviously a grayscale.
I don't think this is a standard layout. If you want an exact value, you need to use the eyedropper...
I ended up using SLaks suggestion and just looped over the image and read the pixel values from the center of each square. Here is quick proof of concept test I ran that loaded all of the colors in to a TableLayoutPanel and it worked perfectly.
private void button1_Click(object sender, EventArgs e)
{
string pngPath = #"E:\Color Pallet.png";
tableLayoutPanel1.Controls.Clear();
using (var bitmap = new Bitmap(pngPath))
{
for (int i = 0; i < 256; i++)
{
var color = bitmap.GetPixel(5 + (10*(i%16)), 5 + (10*(i/16)));
tableLayoutPanel1.Controls.Add(new Panel {Dock = DockStyle.Fill, BackColor = color}, i % 16, i / 16);
}
}
#SLaks, if you post your own answer I will delete mine and accept yours.
Related
I am using a random color for the background in my Windows Forms application. Now I want to display a label.
The problem is that when the random color is white and the label is too, then the label is not visible.
How can I get a perfect color that is visible on my background color? (My background color is a random color from System.Drawing.Color.)
There are various ways to ensure a proper contrast.
Option one : I usually stick to keeping the text Black or White, depending on the brightness of back color.
To get the brightness one could simply go for the built-in function Color.GetBrightness()
Unfortunately this is not really a good solution, as the result is not perceptually correct; to wit: Green and Yellow have the same values, which is obviously not what our eyes will perceive.
Instead this tiny function will help:
float getBrightness(Color c)
{ return (c.R * 0.299f + c.G * 0.587f + c.B *0.114f) / 256f; }
Now we can pick either Black or White:
Label lbl = new Label();
lbl.BackColor = colors[rnd.Next(colors.Count)];
lbl.ForeColor = getBrightness(lbl.BackColor) < 0.55 ? Color.White : Color.Black;
The code uses a list of known colors:
List<Color> colors = ((KnownColor[])Enum.GetValues(typeof(KnownColor))).
Select(x => Color.FromKnownColor(x)).ToList();
Option two : If you want to get colors in the foreground you could pick it randomly and repeat until you get a decent contrast by comparing e.g.
while (Math.Abs(c1.GetBrightness() - c2.GetBrightness()) < 0.5f )
c2 = colors[rnd.Next(colors.Count)];
Note that you must not push the epsilon value too high or else it won't find a suitable color. This happens when trying to find a color that is too far away from a medium brightness! You could add a counter and after a while pick simply black or white..
Option three : Yet another way would be to construct a color with Color.FromArgb().
You could start by inverting each channel, which will give nice color contrasts; but if the color one is of medium brightness and/or saturation you would have to correct, maybe again by picking black or white..
Note: for the above image I have enumerated all KnownColors, which already looks pretty random.
To add some order you may sort the list by color properties, e.g. by hue, then by brightness:
List<Color> allcolors = ((KnownColor[])Enum.GetValues(typeof(KnownColor)))
.Select(x => Color.FromKnownColor(x))
.OrderBy(x => x.GetHue()).ThenBy(x => getBrightness(x)).ToList();
Is there a way to add real padding to migradoc table cells? The options that they currently have (LeftPadding and RightPadding) actually work like margins and not like padding. And if you use it, it pushes the background color as well instead of pushing the content only.
This is what happens when you add "padding" to the whole row or individual cells (added it to the first row):
By default it looks like this:
If you wish to remove the white space between the columns, it seems like you have to do it by setting these padding properties to 0 and then you get this:
..which is almost what I want, but I want to push the content of the cell a bit to towards the centre of the cell from all 4 sides so that it looks like this and has a little room to "breathe":
It was even asked on their forums a long time ago about whether this could be done, but the answer doesn't solve the issue at all. It simply mentions the padding properties which work the exact opposite way of what the OP in that thread asked for (which is the same thing I want to do).
I'm using PDFsharp-MigraDoc-gdi v1.50.4000-beta3b nuget package.
Any ways to hack around this odd behaviour? Thanks.
EDIT: updated with a piece of code I use and with added bit recommended by PDFsharp Novice
var table = new Table();
var columnCount = 4;
for (int i = 0; i < columnCount; i++)
{
table.AddColumn();
}
var hedingRow= table.AddRow();
hedingRow.Format.Font.Bold = true;
hedingRow.Format.Font.Color = Color.Parse("0xFFFFFFFF");
hedingRow.Format.Shading.Color = Color.Parse("0xFF005aa0");
hedingRow.HeadingFormat = true;
hedingRow.Cells[0].AddParagraph("Field");
hedingRow.Cells[1].AddParagraph("Type");
hedingRow.Cells[2].AddParagraph("Default");
hedingRow.Cells[3].AddParagraph(String.Empty);
// Doesn't work as I would assume it should based on PDFsharp Novice
hedingRow.Cells[0].Format.LeftIndent = 4;
hedingRow.Cells[0].Format.RightIndent = 4;
hedingRow.Cells[0].Format.Shading.Color = Color.Parse("0xFF005aa0");
You can set the background color for the cell and/or for the text in the cell.
If you set the color for the cell, the padded area will also have the color.
If you set the color the text only, the padded area will have no color.
I'm trying to find an algorithm that will mix colors, based on a % amount. I'm working on an election project, and want to be able to assign each candidate in a race a different color, and then create a "resulting" color based on how much of the vote that candidate has gotten.
This question:
Is there an algorithm for color mixing that works like mixing real colors?
is close the question I'm asking - but potentially I need to be able to mix 3 or 4 or 5 colors together. I understand that this ultimately an incredibly complicated question - but I'm curious what the suggested method is for doing this on more than 2 colors. So, I might have:
Red (40%), Green(10%), Blue (50%)
OR
Red (40%), Yellow (5%), Blue (10%), Orange (45%)
Once again, I know that the last example would probably produce some sort of Gray or Brown or Black - and that's fine. My problem is that I don't even have an algorithm that attempts to solve this problem.
Edit:
So - after posting this message, I realized that what I was really trying to accomplish was basically PAINT color mixing. IN other words, I don't want LIGHT color mixing, I want to simulate what would happen with PAINT mixing - as that is the "predictable" result that I kept 'expecting' - and was having trouble getting.
I found this link: http://painting.about.com/library/blpaint/blcolormixingpalette1.htm
which behaves VERY closely to what I'm trying to accomplish - and exposes a small "flaw" in my original idea. What is demonstrates is that even though I can mix up to 6 colors using this algorithm, the actual "data" is always broken down into the 3 primary colors.
Even so - this is very close.
Thank you to everyone who has contributed to this thread - all of these suggestions have been very helpful in the exploration of this surprising complex question/field.
Have you tried simply taking a weighted sum?
d.R = a.R*0.25 + b.R*0.25 + c.R*0.5
d.G = a.G*0.25 + b.G*0.25 + c.G*0.5
...
where a, b, c are the colors you're mixing
From my research, it seems there isn't any one correct answer, but whatever seems to produce the most appropriate effect. Moreover, I don't think simply blending the colors would really indicate anything on an infograph. You'd be better off trying something like a really granular dither http://en.wikipedia.org/wiki/Dither#Digital_photography_and_image_processing
The RGB colors system is bad for such calculation, because it does not work like we humans perceive colors. For example we just do not perceive yellow as a mixture of green and red.
The first step is to convert your colors in a color space where you have a lightness coordinate and two coordinates for the color.
This can be either HLS or CIELAB. HLS conversion is more simply, but coordinates in CIELAB represent better the human color experience. Equal distances in this color space are at least roughly equal distances in human perception.
In this color space you have coordidates L, A and B. L should be the same for all your colors. Your base colors should be on a circle around the gray-point, so they have the same distance, and no colors is stronger than the others. so you basically have a few points in the plane and need to calculate their weighted middle point of these points. The you convert this point back to RGB.
It all depends on the primary colors in your color model. It looks like you're using the RGB color model which means that all colors can be represented by a mix of red, green, and blue.
That said, any colors that are not red, green, or blue you would decompose those down into their red, green and blue counterparts, and then multiply those weights by the weight overall.
In your second example:
Red (40%), Yellow (5%), Blue (10%), Orange (45%)
Yellow and Orange need to be decomposed. Assuming you have the Color instance for orange, you can do this:
orangeRed = o.R * .05;
orangeBlue = o.B * .05;
orangeGreen = o.G * .05;
This can actually be generalized across all Color instances (for primary colors, only one of R, G and B will have a value) and then sums and weighted averages can be taken to get your mixed color.
An easy extension method that does this would be:
static Color Mix(this IEnumerable<Tuple<Color, double>> colors)
{
// The red, green, and blue values.
double red = 0.0, green = 0.0, blue = 0.0;
// The denominator for the weighted average for a color.
double denominator = byte.MaxValue * 3.0;
// Cycle through the colors.
foreach (Tuple<Color, double> color in colors)
{
// Get the weighted average value for each component, and then
// multiply that by the weight for the color.
red += ((color.Item1.R / denominator) * color.Item2);
green += ((color.Item1.G / denominator) * color.Item2);
blue += ((color.Item1.B / denominator) * color.Item2);
}
// Create the color and return.
return Color.FromArgb((int) red, (int) green, (int) blue);
}
Im trying to isolate and segment the yellow car body to change the color of it. in order to do that i need to separately identify the body from the image. And continue oration with the remaining white pixels. And im using C#, here the plan
Color d;
Color newColor = Color.YellowGreen;
for(inti =0;i<carimage.Width;i++){
for(intj =0;j<carimage.Height;j++){
d = carimage.GetPixel(i, j);
if(d.R == 255 && d.G==255 && d.B == 255)
image.SetPixel(i, j, newColor );
}
}
simple thresholding will trow the second image where car body is not separated correctly. i tried Aforge.net Fill holes image filter but no significant change has been done to the threshold image. I tried to use color filter but it i did not return a correct output due to color vary of the body. can anyone suggest and solution for this?
Original Image
Threshold Image
Instead of thresholding, you might want to look into clustering.
As a quick&dirty test, I've increased the image brightness in HSB space (using Mathematica):
brightnessAdjusted = Image[
Map[#^{1, 1, 0.2} &, ImageData[ColorConvert[img, "HSB"]], {2}],
ColorSpace -> "HSB"]
Then I've used simple K-Nearest clustering:
(clusters = ClusteringComponents[ColorConvert[brightnessAdjusted, "RGB"], 3,
Method -> "KMeans"]) // Colorize
to find clusters of similar colors in the image (there are many more, probably more suitable clustering algorithms, so you should experiment a little). Then I can just adjust the color in one of the clusters:
Image[MapThread[If[#1 == 2, #2[[{1, 3, 2}]], #2] &, {clusters, ImageData[brightnessAdjusted]}, 2]]
If you want to use thresholding, you should probably use a CIE color space, since euclidian distances in that color space are closer to human perception.
I had a similar project few years ago. I can't remember the exact details, but the idea was to shift a (not too small) sliding window over the image, and calculate the average intensity (maybe for R, G and B separately) inside the window at each position. I filled a "threshold image" with these averages, and subtracted it from the original image. There was a scaling factor somewhere, and other tuning stuff, but the point is, such an approach was way better than using a constant threshold.
If you are going to use a set of thresholds, you might be better of selecting yellow hues in the Hue Saturation Value colorspace. See the related SO question.
I=imread('test.jpg');
I=im2double(rgb2gray(I));
BW=im2bw(I,0.64);imshow(BW)
Gives me :
I got the 0.64 threshold by looking at the image's histogram. I suggest you use MATLAB to do image processing as it is much easier. Hope that helps you in colouring the image.
Im trying to generate a small square 32 by 32 pixels with a 10 by 10 squareish transparent gap in the middle.
This is what I have so far:
private Image CreatePicture(){
// Create a new Bitmap object, 32 x 32 pixels in size
Bitmap canvas = new Bitmap(32,32,System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
for(int i=10;i<21;i++){
for(int p=10;p<21;p++){
canvas.SetPixel(i,p,Color.Lime);
}
}
canvas.MakeTransparent(Color.Lime);
// return the picture
return canvas;
}
Its a it rough and not going to be the final "optimized version" its just a rough demo script. The problem is the returned image does not transparency instead its just a grey box :(.
Any help appreciated.
Michael
UPDATE:
I have updated the script with the PixelFormat set to an Alpha RGB format which it actually accepts without erroring on runtime. Now though if I remove the "canvas.MakeTransparent(Color.Lime);" line it shows a lime box in the middle with it it just shows a grey box the same colour as the grey background; so it seems as if transparency is being recognised just not implimenting the transparency!
private Bitmap CreatePicture(){
// Create a new Bitmap object, 50 x 50 pixels in size
Bitmap canvas = new Bitmap(82,82,System.Drawing.Imaging.PixelFormat.Format32bppArgb);
for(int i=10;i<71;i++){
for(int p=10;p<71;p++){
canvas.SetPixel(i,p,Color.Lime);
}
}
canvas.MakeTransparent(Color.Lime);
// return the picture
return canvas;
}
[...]Format16bppRgb555
Try to use some format with an alpha channel (...Rgba) here. Also, if the output will be an image later, make sure you use an image format like PNG that supports alpha channels.
It depends on how your going to use or display the image. PNG and Gif are the two file formats that support transparency.
For the bitmap setting of transparency, i used:
Graphics.FromImage(bitmap).FillRectangle(Brushes.Transparent, ...) to set the area I wanted as transparent, then I saved the file out as a PNG to get an image with transparency.
I also tried the MakeTransparent method and ran into problems and the Brushes.Transparent was the solution that worked for my situation.
Hope this gives you a direction to look into.
One last note, I create the Bitmap object with width and height only, I don't specify the pixel format or whatever that's called i.e. bitmap = New Bitmap(width, height);
You probably need to change the image format to Format16bppArgb1555.
Right now, you're using Format32bppArgb or Format16bppRgb555, which is 16 bits per pixel with no alpha information. Transparency requires an alpha channel or alpha bit to be present.
My don't you just SetPixel() to Color.Transparent? Instead of Color.Lime then MakeTransparent? And as others have noted; you need a pixel format with an alpha channel.
The MakeTransparent function does work. You have "grey patches" because your TransparencyKey is not correct. You'll find that if you set your TransparencyKey property to whatever color that grey patch is, the grey patches will indeed become transparent when your image is displayed. The default grey patch I got was labeled as "Control" in color, or basically the default Windows Form background color. Change your TransparencyKey to whatever your grey patch is (in my case Control) and your problem will be solved, no saving of files to the Hard Drive neccessary. Cheers mate.