Home > other >  CS50 pset4 Blur
CS50 pset4 Blur

Time:12-21

I do not understand why my code does not work. It returns a very strange image, with VERY dark colors. I read someone else's code on a similar question (https://stackoverflow.com/a/70203062/19299155), and to me it looks like a very similar concept and approach. If someone could explain to me why mine doesn't work I'd be very grateful. One thing I do not understand about the other guy's code is why he updates the pixel value when he does (//assigning new pixel values) because it would mean that the average of other pixels would be using the new value of the now updated pixel instad of the original. (I hope I am explaining myself correctly). I also read this post (cs50 - pset4 - blur) this guy seems to have the same problem as me, and very similar code but the answers people gave him don't seem to apply to me. Here is my code:

void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE blurred[height][width];

    for (int i = 0; i<height; i  ){
        for (int j = 0; j<width; j  ){
            float colorCount = 0.0;
            blurred[i][j].rgbtBlue = 0;
            blurred[i][j].rgbtGreen = 0;
            blurred[i][j].rgbtRed = 0;

            for (int count = -1; count<2; count  ){
                if (((count i) >= 0) && ((count i) < height)){
                    for (int count2 = -1; count2<2; count2  ){
                        if (((count2 j) >= 0) && ((count2 j) < width)){
                            blurred[i][j].rgbtBlue  = image[i count][j count2].rgbtBlue;
                            blurred[i][j].rgbtGreen  = image[i count][j count2].rgbtGreen;
                            blurred[i][j].rgbtRed  = image[i count][j count2].rgbtRed;
                            colorCount  = 1.0;
                        }
                    }
                }
            }
            blurred[i][j].rgbtBlue = round(blurred[i][j].rgbtBlue/colorCount);
            blurred[i][j].rgbtGreen = round(blurred[i][j].rgbtGreen/colorCount);
            blurred[i][j].rgbtRed = round(blurred[i][j].rgbtRed/colorCount);

        }
    }

for (int i = 0; i<height; i  ){
        for (int j = 0; j<width; j  ){
            image[i][j].rgbtBlue = blurred[i][j].rgbtBlue;
            image[i][j].rgbtGreen = blurred[i][j].rgbtGreen;
            image[i][j].rgbtRed = blurred[i][j].rgbtRed;
        }
    }
    return;
}

I tried 2 nested for loops starting at -1 so it would go through the 3x3 adjacent pixels as -1 0 1. for count = -1 it would go count2 =-1 then count2=0 then count2 = 1. then count = 0 and count2 =-1 then count2=0 then count2 = 1. and so on.

CodePudding user response:

Searching for the definition of RGBTRIPLE online (since you did not provide it) yields this post where the definition is:

typedef uint8_t  BYTE;

typedef struct
{
    BYTE  rgbtBlue;
    BYTE  rgbtGreen;
    BYTE  rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;

This poses an issue for your current blur kernel calculation, because you are using a RGBTRIPLE value to accumulate the sum of all pixels in the 3x3 kernel. Each color channel in the pixel uses the entire range, and so the moment you add data from another pixel to this, you risk exceeding the maximum possible value that can be stored. This will discard the carry bit from such an operation and wrap the result to remain in the 0-255 range.

The reason your output is "dark" is precisely because for most of your image the maximum possible value for a channel is round(255.0 / 9), which is 28. On the edges of your image, that will be brighter, but still never better than round(255.0 / 4), which is 64. Within this narrow range, you're also likely to see jagged artifacts or banding where the color channels wrapped after discarding overflow bits.

Even the answers you linked to point out the same thing, which you mistakenly assert "don't seem to apply to me". That is incorrect. There is absolutely no way that this isn't a problem for you. Allow me to fix your code, and maybe just rename some variables along the way to improve readability:

for (int y = 0; y < height; y  ) {
    for (int x = 0; x < width; x  ) {
        int count = 0;
        float sumRed = 0.0f, sumGreen= 0.0f, sumBlue = 0.0f;
        
        for (int dy = -1; dy <= 1; dy  ) {
            int ky = y   dy;
            if (ky >= 0 && ky < height) {
                for (int dx = -1; dx <= 1; dx  ) {
                    int kx = x   dx;
                    if (kx >= 0 && kx < width) {
                        sumBlue   = (float)image[ky][kx].rgbtBlue;
                        sumGreen  = (float)image[ky][kx].rgbtGreen;
                        sumRed    = (float)image[ky][kx].rgbtRed;
                        count  ;
                    }
                }
            }
        }
        
        blurred[y][x].rgbtBlue  = round(sumBlue / count);
        blurred[y][x].rgbtGreen = round(sumGreen / count);
        blurred[y][x].rgbtRed   = round(sumRed / count);
    }
}

for (int y = 0; y < height; y  ) {
    for (int x = 0; x < width; x  ) {
        image[y][x] = blurred[y][x];
    }
}
  • Related