CS50 - Issue with pset4 filter “blur”

独自空忆成欢 提交于 2020-07-23 08:47:40

问题


My blur function is behaving oddly. I've recreated the 3x3 bitmap from check50 to get more approximate results from my tests but, for some reason, every right or lower edge pixels are not working properly.

While debugging, I've found that, for some reason, my for loops are not behaving properly. I'll show my code and an example below.

Code:

// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
    RGBTRIPLE temp[height][width]; // Declares temporary structure to avoid overwriting of original values while running loops

    // For loop to set the value of i, rows or height
    for (int i = 0; i < height; i++)
    {
        // For loop to set the value of j, columns or width
        for (int j = 0; j < width; j++)
        {
            float counter = 0.0;
            int sumRed = 0;
            int sumGreen = 0;
            int sumBlue = 0;

            // For loop to set the value of k, to get surrounding pixels
            for (int k = -1; k < 2; k++)
            {
                for (int m = -1; m < 2; m++)
                {
                    if ((i - k) >= 0 && (i - k) < height && (j - m) >= 0 && (j - m) < width)
                    {
                        sumRed = sumRed + image[i - k][j - m].rgbtRed; // Adds the value of verified pixel to the sum
                        sumGreen = sumGreen + image[i - k][j - m].rgbtGreen;
                        sumBlue = sumBlue + image[i - k][j - m].rgbtBlue;
                        counter++; // To get the average
                    }
                }
            }

            temp[i][j].rgbtRed = round(sumRed / counter); // Sets new color based on average of surrounding pixels
            temp[i][j].rgbtGreen = round(sumGreen / counter);
            temp[i][j].rgbtBlue = round(sumBlue / counter);
        }
    }

    // Start new loops to switch original values with temp values
    for (int i = 0; i < height - 1; i++)
    {
        for (int j = 0; j < width - 1; j++)
        {
            image[i][j].rgbtRed = temp[i][j].rgbtRed;
            image[i][j].rgbtGreen = temp[i][j].rgbtGreen;
            image[i][j].rgbtBlue = temp[i][j].rgbtBlue;
        }
    }

    return;
}

And here's the output.

As an example of what I've found during the debug, let's say that:

i = 0
j = 2
k = 0
m = 0

Here, instead of sumRed getting the value of image[0 - 0][2 - 0] (RGB 70, 80, 90), it's getting the values from image[2][2] (RGB 240, 250, 255).

I've not yet tested the other error cases, but I suppose something similar is happening there.

Any help would be greatly appreciated.


回答1:


This is prefaced by my top comment:

It might be better if counter were an int. Then, do: round((double) sumRed / counter), But, the output cell is only eight bits. You may need: sumRed = round((double) sumRed / counter); temp[i][j].rgbtRed = (sumRed < 255) ? sumRed : 255; This is saturation math. Otherwise, when you assign to an 8 bit cell, it's modulo math, equivalent to sumRed % 256. That would yield 257 --> 1 (nearly black) instead of 257 --> 255 (bright red)

Your biggest problem is that your convolution kernel index calculations are incorrect.

Instead of:

(i - k)
(j - m)

You want:

(i + k)
(j + m)

Also, your the limits on your final loops to copy back from temp to image are off by 1.

Plus, I'd use more descriptive variables. And, your code can be simplified a bit. Here's a refactored version that incorporates the bug fixes:

#include <math.h>

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

// Blur image
void
blur(int height, int width, RGBTRIPLE image[height][width])
{
    // Declares temporary structure to avoid overwriting of original values
    // while running loops
    RGBTRIPLE temp[height][width];
#if 1
    RGBTRIPLE *tmp;
    RGBTRIPLE *img;
#endif

    // For loop to set the value of yctr, rows or height
    for (int yctr = 0; yctr < height; yctr++) {
        // For loop to set the value of xctr, columns or width
        for (int xctr = 0; xctr < width; xctr++) {
#if 0
            float counter = 0.0;
#else
            int counter = 0;
#endif
            int sumRed = 0;
            int sumGreen = 0;
            int sumBlue = 0;

            // For loop to set the value of yoff, to get surrounding pixels
            for (int yoff = -1; yoff < 2; yoff++) {
// NOTE/BUG: this is the main bug
#if 0
                int ycur = yctr - yoff;
#else
                int ycur = yctr + yoff;
#endif
                if (ycur < 0)
                    continue;
                if (ycur >= height)
                    continue;

                for (int xoff = -1; xoff < 2; xoff++) {
// NOTE/BUG: this is the main bug
#if 0
                    int xcur = xctr - xoff;
#else
                    int xcur = xctr + xoff;
#endif
                    if (xcur < 0)
                        continue;
                    if (xcur >= width)
                        continue;

                    // Adds the value of verified pixel to the sum
                    tmp = &image[ycur][xcur];
                    sumRed += tmp->rgbtRed;
                    sumGreen += tmp->rgbtGreen;
                    sumBlue += tmp->rgbtBlue;
                    counter++;      // To get the average
                }
            }

            // Sets new color based on average of surrounding pixels
            tmp = &temp[yctr][xctr];

#if 0
            tmp->rgbtRed = round(sumRed / counter);
            tmp->rgbtGreen = round(sumGreen / counter);
            tmp->rgbtBlue = round(sumBlue / counter);
#else

            sumRed = round((double) sumRed / counter);
            tmp->rgbtRed = (sumRed < 255) ? sumRed : 255;

            sumGreen = round((double) sumGreen / counter);
            tmp->rgbtGreen = (sumGreen < 255) ? sumGreen : 255;

            sumBlue = round((double) sumBlue / counter);
            tmp->rgbtBlue = (sumBlue < 255) ? sumBlue : 255;
#endif
        }
    }

    // Start new loops to switch original values with temp values
// NOTE/BUG: the for loop ranges are incorrect
#if 0
    for (int yctr = 0; yctr < height - 1; yctr++) {
        for (int xctr = 0; xctr < width - 1; xctr++) {
            image[yctr][xctr].rgbtRed = temp[yctr][xctr].rgbtRed;
            image[yctr][xctr].rgbtGreen = temp[yctr][xctr].rgbtGreen;
            image[yctr][xctr].rgbtBlue = temp[yctr][xctr].rgbtBlue;
        }
    }
#endif

#if 0
    for (int yctr = 0; yctr < height; yctr++) {
        for (int xctr = 0; xctr < width; xctr++) {
            image[yctr][xctr] = temp[yctr][xctr];
        }
    }
#endif

#if 1
    tmp = &temp[0][0];
    img = &image[0][0];

    int idxlim = width * height;
    for (int idxcur = 0; idxcur < idxlim; idxcur++)
        img[idxcur] = tmp[idxcur];
#endif
}


来源:https://stackoverflow.com/questions/61394007/cs50-issue-with-pset4-filter-blur

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!