I'm writing a simple tool, the user can select an image and it should list all the colors found in the picture.
Now, I'm facing 2 main issues, one is that it's slow because I'm looping through all the pixels in an image. Second, I'm getting unexpected results.
First thing's first, the code:
public static async Task<List<ImageColor>> GetImageColorsAsync(StorageFile image)
{
List<ImageColor> colors = new List<ImageColor>();
var imagestream = await image.OpenStreamForReadAsync(); // Convert image to stream
var imageDecoder = await BitmapDecoder.CreateAsync(imagestream.AsRandomAccessStream()); // decode stream
var imagePixelData = await imageDecoder.GetPixelDataAsync(); // get information about pixels
var bytes = imagePixelData.DetachPixelData(); // get pixel data
for (int x = 0; x < imageDecoder.PixelWidth; x++)
{
for (int y = 0; y < imageDecoder.PixelHeight; y++)
{
var location = (y * (int)imageDecoder.PixelWidth + x) * 3; // Navigate to corresponding coordinates
var color = Color.FromArgb(0, bytes[location + 0], bytes[location + 1], bytes[location + 2]); // Filter Red Green Blue and convert this to Argb
// find if color already exsists from its hex code
string hex = color.ToString();
var prevColor = colors.FirstOrDefault(a => a.ColorCodeHex == hex);
if (colors.Count == 0 || prevColor == null)
{
// new color
ImageColor imgColor = new ImageColor()
{
R = color.R,
G = color.G,
B = color.B,
ColorCodeHex = hex,
Occurence = 1
};
colors.Add(imgColor);
}
else
{
// exsisting color
prevColor.Occurence++;
}
}
}
return colors;
}
Now, do I really need to go through every single pixel?
And, what I did was test this function using a black image (completely black) and what I got was that there are 4 colors in that picture: black, red, green and blue.
Also, when testing using an image which was just a screenshot of some text (so the colors black, white and maybe some yellow were present) the result was huge (almost 1000+ colors) so there is clearly something wrong with my method
Now the lines where I find the location
and color
are not mine, I found them online and I can't really verify that this is how you should do it.
Any help guys?
First, I don't have a UWP app at hand, but I think your correctness problem is because you ignore the stride. This number is the amount of bytes that the system uses to represent a row, which is not 3*width*y, but usually more in order to align row data to a fixed grid.
Second, are you really sure you have a 3 channel image and not 4 (ARGB)? The fourth channel would at least explain why you see non-zero values in a black picture, especially because you see (#ff0000, #00ff00 and #0000ff), so you are getting ff at locations you don't expect.
Third, performance-wise, it would be a wise decision to use a dictionary or hashset instead of a list.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.