I want to retrieve the majority color in a b开发者_JS百科ackground image in .NET. Is it possible?
You can loop through all the pixels in the image and use the getPixel method to determine the RGB value. You can then have a dictionary that store the ARGB value along with a count. You can then see which ARGB value is present most in the image.
var list = new Dictionary<int, int>();
Bitmap myImage = (Bitmap)Bitmap.FromFile("C:/test.jpeg");
for (int x = 0; x < myImage.Width; x++)
{
for (int y = 0; y < myImage.Height; y++)
{
int rgb = myImage.GetPixel(x, y).ToArgb();
if (!list.ContainsKey(rgb))
list.Add(rgb, 1);
else
list[rgb]++;
}
}
As pointed out this has no sympathy for similar colors. If you wanted a more 'general' majority color you could have a threshold on similarity. e.g. rather than:
if (!list.ContainsKey(rgb))
list.Add(rgb, 1);
else
list[rgb]++;
you could do:
var added = false;
for (int i = 0; i < 10; i++)
{
if (list.ContainsKey(rgb+i))
{
list[rgb+i]++;
added = true;
break;
}
if (list.ContainsKey(rgb-i))
{
list[rgb-i]++;
added = true;
break;
}
}
if(!added)
list.Add(rgb, 1);
You could up the threshold of 10 to whatever you needed.
You may also find this Algorithm Challenge on Stack Overflow useful:
Algorithm challenge: Generate color scheme from an image
Also consider creating a histogram of the image - and taking the highest valued color as the 'majority color': http://www.phpclasses.org/browse/file/15953.html
This will return the average color for the image.
static Color AverageColor(string fileName)
{
using (var bmp = new Bitmap(fileName))
{
int width = bmp.Width;
int height = bmp.Height;
int red = 0;
int green = 0;
int blue = 0;
int alpha = 0;
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
var pixel = bmp.GetPixel(x, y);
red += pixel.R;
green += pixel.G;
blue += pixel.B;
alpha += pixel.A;
}
Func<int, int> avg = c => c / (width * height);
red = avg(red);
green = avg(green);
blue = avg(blue);
alpha = avg(alpha);
var color = Color.FromArgb(alpha, red, green, blue);
return color;
}
}
This will return the average color for the image using unsafe pointer access. Note: code is only adapted for 24bppRgb, could be adapted for other pixel formats.
unsafe static Color GetColor(string filename)
{
using (var image = (Bitmap)Bitmap.FromFile(filename))
{
if (image.PixelFormat != PixelFormat.Format24bppRgb) throw new NotSupportedException(String.Format("Unsupported pixel format: {0}", image.PixelFormat));
var pixelSize = 3;
var bounds = new Rectangle(0, 0, image.Width, image.Height);
var data = image.LockBits(bounds, ImageLockMode.ReadOnly, image.PixelFormat);
long r = 0;
long g = 0;
long b = 0;
for (int y = 0; y < data.Height; ++y)
{
byte* row = (byte*)data.Scan0 + (y * data.Stride);
for (int x = 0; x < data.Width; ++x)
{
var pos = x * pixelSize;
b += row[pos];
g += row[pos + 1];
r += row[pos + 2];
}
}
r = r / (data.Width * data.Height);
g = g / (data.Width * data.Height);
b = b / (data.Width * data.Height);
image.UnlockBits(data);
return Color.FromArgb((int)r, (int)g, (int)b);
}
}
gist: http://gist.github.com/349210
Assuming you characterize each pixel's color using RGB (versus, say, CMYK), you could build a 3d array (one dimension each for R, G and B). Then decide on the # of bins that you want to have in each dimensions - the more bins, the greater the differentiation you are making between similar hues.
Once that is done, just iterate through a bitmap representation of your image summing the # pixels that falls into each of the cells in you 3d array. The cell with the highest sum will be the predominant color.
You probably want to make your algorithm easily configurable for the # bins in each dimension so that you can adjust how much it discriminates between similar colors.
image = new Bitmap("C:\\test.bmp", true);
int x, y;
// Loop through the images pixels to product 3d histogram
for(x=0; x<image.Width; x++)
{
for(y=0; y<image.Height; y++)
{
Color pixelColor = image.GetPixel(x, y);
// Increment color count in appropriate cell of your 3d histogram here
...
}
}
精彩评论