Pixellate parts of an image in C#

[pixellate]

This program lets you click and drag to select an area and pixellate the area.

The code that lets you select an area is interesting but reasonably straightforward. See the code and the example Use a rubberband box to let the user select an area in a picture in C# for more information on selecting areas. The code that loads and saves images is also straightforward.

The following code shows the most interesting part of the program: the method that pixellates an area of the picture.

// Pixellate the indicated rectangle.
private void PixellateRectangle(Rectangle rect)
{
    // Restrict the rectangle to fit on the image.
    int bm_wid = CurrentBitmap.Width;
    int bm_hgt = CurrentBitmap.Height;
    rect = Rectangle.Intersect(rect,
        new Rectangle(0, 0, bm_wid, bm_hgt));

    // Process the rectangle.
    const int box_wid = 8;
    using (Graphics gr =
        Graphics.FromImage(CurrentBitmap))
    {
        int start_y = box_wid * (int)(rect.Top / box_wid);
        int start_x = box_wid * (int)(rect.Left / box_wid);
        for (int y = start_y; y <= rect.Bottom; y += box_wid)
        {
            for (int x = start_x; x <= rect.Right; x += box_wid)
            {
                // Pixellate area with upper left corner (x, y).

                // Get the average of the pixels' color values.
                int total_r = 0, total_g = 0,
                    total_b = 0, num_pixels = 0;
                for (int dy = 0; dy < box_wid; dy++)
                {
                    if (y + dy >= bm_hgt) break;
                    for (int dx = 0; dx < box_wid; dx++)
                    {
                        if (x + dx >= bm_wid) break;
                        Color pixel_color = 
                            CurrentBitmap.GetPixel(x + dx, y + dy);
                        total_r += pixel_color.R;
                        total_g += pixel_color.G;
                        total_b += pixel_color.B;
                        num_pixels++;
                    }
                }
                byte r = (byte)(total_r / num_pixels);
                byte g = (byte)(total_g / num_pixels);
                byte b = (byte)(total_b / num_pixels);
                Color new_color = Color.FromArgb(255, r, g, b);

                // Give all pixels in the box this color.
                using (Brush br = new SolidBrush(new_color))
                {
                    gr.FillRectangle(br, x, y, box_wid, box_wid);
                }
            }
        }

        // Refresh to show the new image.
        picImage.Image = CurrentBitmap;
        picImage.Refresh();
    }
}

This method first intersects the selected rectangle with the picture’s bounds. If the user drags and then releases the mouse off the edge of the picture, the rectangle will include points off of the picture and there’s no point in trying to process them.

Next the code sets the constant box_wid to 8. This is the size of the pixellated boxes. You can change this value to make the boxes bigger or smaller.

The form-level variable CurrentBitmap holds the current picture. This is the original image loaded from a file with some areas possibly already pixellated. The program creates a Graphics object associated with that image to draw on it.

Next the program calculates the X and Y coordinates in the image where it will start pixellating. It divides the target rectangle’s coordinates by box_wid, uses (int) to truncate the result, and then multiplies it by box_wid. That makes the starting X and Y coordinate the largest multiple of box_wid less than or equal to the target rectangle’s upper left corner. The code does this so the pixellations of different rectangles will line up nicely. If you click and drag to pixellate two areas on a picture and those areas overlap, their pixellated boxes will line up.

Next the code loops over the pixels in the target rectangle. For each box_wid×box_wid area, the code adds up all of the pixels’ color components and divides by the number of pixels within the box to get an average color value. The code then fills the box with the average color.

This piece of code is a bit long but not too complicated. The only thing worth note here is that the code uses the break statement to break out of for loops if it is processing a pixel that lies outside of the image. For example, consider the outer dy loop. The variable dy makes the code consider rows of pixels below the starting row with Y coordinate y. If start_y is near the bottom edge of the picture, then when dy is big enough, y + dy will be off of the picture. In that case the program uses a break statement to end the dy loop because pixels for this value of dy and all later values of dy will lie outside of the picture. The code uses break similarly when dx moves beyond the right edge of the picture.


Download Example   Follow me on Twitter   RSS feed   Donate




This entry was posted in algorithms, drawing, graphics, image processing and tagged , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *