问题
I have this one working but it is so damn slow on jpeg images and also needs some changing.
I need to know the individual colours in an image (with a tolerance of +/- 1 for RGB) and the % of the image that is that colour.
so if an image was black and white it would say something like White : 74% Black : 26%
The code below works like I said but I need to add a tolerance system as well and I have no idea on how I would do that.
private Dictionary<string, string> getPixelData(Bitmap image)
{
Dictionary<string, string> pixelData = new Dictionary<string, string>();
//int col, row;
//int r, g, b;
Color pixel;
double offset = 0.000001;
int hmm = (image.Height * image.Width);
double current = 0;
offset = 100 / double.Parse(hmm.ToString());// 0.01;// 100 / (image.Height * image.Width) * 10000;
try
{
for (int i = 0; i < image.Height; i++)
{
for (int j = 0; j < image.Width; j++)
{
current = current + offset;
pixel = image.GetPixel(i, j);
pixelData.Add(i + "," + j, (pixel.R.ToString() + " " + pixel.G.ToString() + " " + pixel.B.ToString()));
pBarprocess.Value = int.Parse(Math.Floor(current).ToString());
pBarprocess.Update();
Application.DoEvents();
}
}
}
catch (Exception ex)
{
MessageBox.Show("Unable to parse image " + ex);
}
return pixelData;
}
And the other function
private void btnProcess_Click(object sender, EventArgs e)
{
pBarprocess.Value = 0;
pBarprocess.Enabled = false;
Bitmap foo = Bitmap.FromFile(@txtFileName.Text) as Bitmap;
Dictionary<string, string> pixelData = new Dictionary<string, string>();
lblProcess.Text = "Processing pixel map";
pixelData = getPixelData(foo);
lblProcess.Text = "Calculating Density";
lblProcess.Update();
var distinctList = pixelData.Values.Distinct().ToList();
Console.WriteLine("DL = " + distinctList.Count);
double offset = 100 / double.Parse(distinctList.Count.ToString());
double current = 0;
foreach (var value in distinctList)
{
IEnumerable<string> query = pixelData.Values.Where(fruit => fruit == value);
double perc = (double.Parse(query.Count().ToString()) / double.Parse(pixelData.Count.ToString())) * 100;
Console.WriteLine(value + " = " + query.Count() + "(" + perc + "%)");
txtAnalysis.Text = "Colour " + value + " : " + query.Count() + " (" + perc.ToString() + "%)\r\n" + txtAnalysis.Text;
txtAnalysis.Update();
pBarprocess.Value = int.Parse(Math.Floor(current).ToString());
pBarprocess.Update();
Application.DoEvents();
}
lblProcess.Text = "Finished.";
pBarprocess.Value = 0;
pBarprocess.Enabled = false;
}
回答1:
GetPixel is not really a fast way to access image data. Use the LockBits method.
EDIT:
Well you're doing a lot of things with strings. Building the pixelData Dictionary that way is pretty useless, why don't you process the distinct colors right away? Color is an immutable struct, so that's a good key for our dictionary already.
Dictionary<Color, int> frequency = new Dictionary<Color, int>();
for (int i = 0; i < image.Height; i++) {
for (int j = 0; j < image.Width; j++) {
pixel = image.GetPixel(i, j);
if (frequency.ContainsKey(pixel)) frequency[pixel]++;
else frequency.Add(pixel, 1);
}
}
// and finally
int totalPixels = image.Width * image.Height;
foreach (var kvp in frequency) {
Console.WriteLine("Color (R={0},G={1},B={2}): {3}", kvp.Key.R, kvp.Key.G, kvp.Key.B, kvp.Value / (double)totalPixels);
}
And that should do it, except when you want to make it even faster and use LockBits instead of GetPixel.
Some other observations:
int hmm = (image.Height * image.Width);
double offset = 100 / double.Parse(hmm.ToString());
You're using a very strange and slow way of casting from int to double. You can just write double offset = 100 / (double)hmm;
and it's the same (you could also write 100.0 and not 100 and the compiler will create a double for you so you don't need to cast hmm).
This made me laugh:
IEnumerable<string> query = pixelData.Values.Where(fruit => fruit == value);
Why fruit!? Seems like you copied this from somewhere.
回答2:
It seems like this is part of a larger image processing goal. The Aforge framework is the go-to choice for image analysis and processing in .NET, and it is extremely fast. It's likely that it already has the code you need.
You mentioned a tolerance system - to me, this sounds like you need quantization - color rounding.
Once you have a quantized bitmap, you can make and array with a length that matches the palette size, LockBits the bitmap, and use the color index for each pixel as the array index for each pixel to accumulate usage statistics.
Could you share more information about your goals for this code? What it is supposed to do exactly?
回答3:
My method of calculation of color percentage of an image is as follow, also in this way we can
calculate any percentage of pixels for any color.
1.Using a software named "ImageJ" at this location, it is free.
http://rsb.info.nih.gov/ij/download.html
2.Open an image with this tool
- Go to Analyze menu and select Histogram, it will open histogram window
4.In histogram window, on the bottom left side click "list" button, it will open list window
5.In the list window select "save as", this will save number of pixels per colors between 0-256
6.For area measurement calculate pixel dimension from resolution and multiply with the number of
pixels. Use excel any other numerical analysis, especially pivot tables.
Here is the ImageJ software, excel file I used, and a screenshot.
https://www.mediafire.com/?htwk83rwgio4zds
来源:https://stackoverflow.com/questions/7874447/get-the-percentage-usage-of-every-colour-in-an-image