0

I'm working on a box blur algorithm, that I have to implement for one of the course's exercise. Basically, I need to take an image and blur each pixel using this algo (below, the course's description).

"For this problem, we’ll use the “box blur,” which works by taking each pixel and, for each color value, giving it a new value by averaging the color values of neighboring pixels." Consider the following grid of pixels, where we’ve numbered each pixel.

https://i.stack.imgur.com/83CjW.jpg

The new value of each pixel would be the average of the values of all of the pixels that are within 1 row and column of the original pixel (forming a 3x3 box). For example, each of the color values for pixel 6 would be obtained by averaging the original color values of pixels 1, 2, 3, 5, 6, 7, 9, 10, and 11 (note that pixel 6 itself is included in the average). Likewise, the color values for pixel 11 would be be obtained by averaging the color values of pixels 6, 7, 8, 10, 11, 12, 14, 15 and 16.

For a pixel along the edge or corner, like pixel 15, we would still look for all pixels within 1 row and column: in this case, pixels 10, 11, 12, 14, 15, and 16.

So, I tried to implement my solution creating an extended array where all the rows and columns around the image should have the color values set to 0. This way, I didn't need to think around about edge, corner cases.

// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
    int red = 0, green = 0, blue = 0;
    float counter = 0.0;
    int exheight = height + 2;
    int exwidth = width + 2;
    // Creates an extended array to make the implementation of the box blur algorithm easier
    RGBTRIPLE eximg[exheight][exwidth];
    for (int i = 0; i < exheight; i++) {
        for (int j = 0; j < exwidth; j++) {
            if (i == 0 || i == height + 1) {
                eximg[i][j].rgbtRed = 0;
                eximg[i][j].rgbtGreen = 0;
                eximg[i][j].rgbtBlue = 0;
            }                                  // Sets the '0' color value for the pixels in the extended row and column
            if (j == 0 || j == width + 1) {    
                eximg[i][j].rgbtRed = 0;
                eximg[i][j].rgbtGreen = 0;
                eximg[i][j].rgbtBlue = 0;
            }
            else if (i > 0) {
                eximg[i][j].rgbtRed = image[i - 1][j - 1].rgbtRed;
                eximg[i][j].rgbtGreen = image[i - 1][j - 1].rgbtGreen;    // Configure the layout for the extended array
                eximg[i][j].rgbtBlue = image[i - 1][j - 1].rgbtBlue;
            }
            
        }
    }
    // Configure the blur effect for each pixel
    for (int i = 1; i < exheight; i++) {
        for (int j = 1; j < exwidth; j++) {
            red = 0;
            green = 0;
            blue = 0;
            counter = 0.0;
            // Sets the counter for edge pixels
            if (i - 1 == 0 && (j - 1 == 0 || j - 1 == 3)) {
                counter = 4.0;
            }
            // Sets the counter for corner pixels
            else if ((i == 1 && (j == 2 || j == 3)) || (i == 4 && (j == 2 || j == 3)) || (j == 1 && (i == 2 || i == 3)) || (j == 4 && (i == 2 || i == 3))) {
                counter = 6.0;
            }
            // Sets the counter for middle pixels
            else {
                counter = 9.0;
            }
            // Calculation for the pixels
            red = round((eximg[i][j].rgbtRed + eximg[i][j - 1].rgbtRed + eximg[i][j + 1].rgbtRed + eximg[i - 1][j - 1].rgbtRed + eximg[i - 1][j].rgbtRed + eximg[i - 1][j + 1].rgbtRed + eximg[i + 1][j - 1].rgbtRed + eximg[i + 1][j].rgbtRed + eximg[i + 1][j + 1].rgbtRed) / counter);
            green = round((eximg[i][j].rgbtGreen + eximg[i][j - 1].rgbtGreen + eximg[i][j + 1].rgbtGreen + eximg[i - 1][j - 1].rgbtGreen + eximg[i - 1][j].rgbtGreen + eximg[i - 1][j + 1].rgbtGreen + eximg[i + 1][j - 1].rgbtGreen + eximg[i + 1][j].rgbtGreen + eximg[i + 1][j + 1].rgbtGreen) / counter);
            blue = round((eximg[i][j].rgbtBlue + eximg[i][j - 1].rgbtBlue + eximg[i][j + 1].rgbtBlue + eximg[i - 1][j - 1].rgbtBlue + eximg[i - 1][j].rgbtBlue + eximg[i - 1][j + 1].rgbtBlue + eximg[i + 1][j - 1].rgbtBlue + eximg[i + 1][j].rgbtBlue + eximg[i + 1][j + 1].rgbtBlue) / counter);
            // Applies the changes to the original image array
            image[i - 1][j - 1].rgbtRed = red;
            image[i - 1][j - 1].rgbtGreen = green;
            image[i - 1][j - 1].rgbtBlue = blue;
        }
    }
    return;
}

Then, I checked my output with a 4x4 image. This is the expected output: 70 85 95 80 95 105 100 115 125 110 125 135 113 126 136 123 136 145 142 155 163 152 165 173 113 119 136 143 151 164 156 166 171 180 190 194 113 112 132 155 156 171 169 174 177 203 207 209

And this is my output: 70 85 95 80 95 105 100 115 125 110 125 135 113 126 136 123 136 145 142 155 163 152 165 173 113 119 136 143 151 164 156 166 171 180 190 194 78 78 58 239 198 211 253 0 2 118 119 147

Everything ok, only the last row is incorrect. Can someone help me to find what's the error?

  • You're copying the image as an inset into a larger image with black pixel borders to avoid clipping on the fly. Doable but maybe _more_ complex. And the black pixel insert seems wrong. Here's one of my previous Cs50 blur answers: https://stackoverflow.com/a/62331838/5382650 that may help – Craig Estey Sep 27 '22 at 21:03
  • Yeah, I know its a bit complex...but I will take a look on the black pixel insert...also, I looked your solutions, and its really interesting to see that you verify if the color value is > 255 and set it to 255 if so. Thank you so much for taking time to answer. – Champs Legion Sep 28 '22 at 17:08
  • The comparison against 255 is doing "unsigned saturation" math. It's a common technique in video image processing. Professional video processing _never_ uses floating point math [because it's way too slow]. See: https://en.wikipedia.org/wiki/Saturation_arithmetic https://www.felixcloutier.com/x86/pmaddubsw https://stackoverflow.com/questions/121240/how-to-do-unsigned-saturating-addition-in-c https://www.felixcloutier.com/x86/paddusb:paddusw – Craig Estey Sep 28 '22 at 17:59
  • Thank you so much for the hints. I corrected everything and now its working. Finally, my black pixel box works out-of-the-box =D – Champs Legion Oct 04 '22 at 16:25

1 Answers1

0

Problem solved! The black pixel insert was really wrong, and also the conditions that verify if the pixel is on edge, corner or middle of the image. Now its everything correct!