CS50 - проблема с фильтром pset4 "размытие" - PullRequest
0 голосов
/ 23 апреля 2020

Моя функция размытия ведет себя странно. Я воссоздал растровое изображение 3x3 из check50, чтобы получить более приблизительные результаты моих тестов, но по какой-то причине каждый правый или нижний край пикселей не работает должным образом.

Во время отладки я обнаружил, что для по какой-то причине, мои циклы for не ведут себя должным образом. Я покажу свой код и пример ниже.

Код:

// 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;
}

А вот вывод .

Как пример того, что Я обнаружил во время отладки, скажем, что:

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

Здесь вместо sumRed, получающего значение image[0 - 0][2 - 0] (RGB 70, 80, 90), он получает значения из image[2][2] (RGB 240, 250, 255).

Я еще не проверял другие случаи ошибок, но я предполагаю, что там происходит нечто подобное.

Любая помощь будет принята с благодарностью.

1 Ответ

0 голосов
/ 23 апреля 2020

Это предшествует моему главному комментарию:

Возможно, было бы лучше, если бы counter было int. Затем выполните: round((double) sumRed / counter), но выходная ячейка составляет всего восемь битов. Вам может понадобиться: sumRed = round((double) sumRed / counter); temp[i][j].rgbtRed = (sumRed < 255) ? sumRed : 255; Это математика насыщения. В противном случае, когда вы назначаете 8-битную ячейку, это по модулю математика, эквивалентная sumRed % 256. Это даст 257 --> 1 (почти черный) вместо 257 --> 255 (ярко-красный)

Ваша самая большая проблема в том, что ваши вычисления индекса ядра свертки неверны.

Вместо:

(i - k)
(j - m)

Вы хотите:

(i + k)
(j + m)

Кроме того, ваши предельные значения для ваших последних циклов для копирования обратно с temp на image отключены на 1.

Плюс, я бы использовал более описательные переменные. И ваш код может быть немного упрощен. Вот переработанная версия, которая включает исправления ошибок:

#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
}
...