2
\$\begingroup\$

I wrote a function that will pixelate an image using the average color of each 4x4 cell.

The function will "split" the image into 4x4 cells, and find the average color of each pixel in the 4x4 cell, and set the 4x4 cell to the average color.

I'd like some help optimizing my function so it can pixelate an image as fast as possible. In its current state the pixelation process is quite slow.

private static Image PixelateImage(Image image)
{
 var bitmap = new Bitmap(image.Width, image.Height);
 using (var graphics = Graphics.FromImage(bitmap))
 {
 graphics.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height),
 new Rectangle(0, 0, image.Width, image.Height), GraphicsUnit.Pixel);
 }
 // Loop through the image in 4x4 cells.
 for (var yy = 0; yy < image.Height && yy < image.Height; yy += 4)
 {
 for (var xx = 0; xx < image.Width && xx < image.Width; xx += 4)
 {
 var cellColors = new List<Color>();
 // Store each color from the 4x4 cell into cellColors.
 for (var y = yy; y < yy + 4 && y < image.Height; y++)
 {
 for (var x = xx; x < xx + 4 && x < image.Width; x++)
 {
 cellColors.Add(bitmap.GetPixel(x, y));
 }
 }
 // Get the average red, green, and blue values.
 var averageRed = cellColors.Aggregate(0, (current, color) => current + color.R) / cellColors.Count;
 var averageGreen = cellColors.Aggregate(0, (current, color) => current + color.G) / cellColors.Count;
 var averageBlue = cellColors.Aggregate(0, (current, color) => current + color.B) / cellColors.Count;
 var averageColor = Color.FromArgb(averageRed, averageGreen, averageBlue);
 // Go BACK over the 4x4 cell and set each pixel to the average color.
 for (var y = yy; y < yy + 4 && y < image.Height; y++)
 {
 for (var x = xx; x < xx + 4 && x < image.Width; x++)
 {
 bitmap.SetPixel(x, y, averageColor);
 }
 }
 }
 }
 return bitmap;
}

enter image description here enter image description here

asked Aug 31, 2016 at 21:44
\$\endgroup\$
1
  • 2
    \$\begingroup\$ There are a few ways to improve performance. One is to scale the image down to the smaller size, then scale it back up to the original size. Another is to render the picture using a pixel shader that handles the averaging. Yet another is to load the image as a texture, generate a MIP map from the texture, then render from the appropriate level of MIP map. Any of these will normally use the GPU for most of the "grunt" work, improving performance substantially. \$\endgroup\$ Commented Sep 1, 2016 at 0:59

1 Answer 1

3
\$\begingroup\$

Jerry Coffin suggested that I should simply scale the image down to a smaller size, and then back up to the original size. (Thanks!)

Using Emgu CV, I was able to shorten my function to a single return statement.

private Image<Bgr, byte> PixelateImage(Image<Bgr, byte> image)
{
 return image.Resize((int)(image.Width * .25), (int)(image.Height * .25), Inter.Area)
 .Resize(image.Width, image.Height, Inter.Nearest);
}
answered Sep 3, 2016 at 14:36
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.