首页 > 解决方案 > CS50 模糊过滤器在小测试用例中给出了不正确的输出

问题描述

我正在为 CS50(更舒适的版本)中的过滤任务编写平均模糊过滤器。当我用我的一些图片对其进行测试时,它似乎工作正常。但是,当我使用 CS50 测试用例对其进行测试时,它对小矩阵给出了错误的结果。下面是我的代码

#define KERNEL_HEIGHT 3
#define KERNEL_WIDTH 3
#define KERNEL_SIZE 9
#define CORNER 4
#define EDGE 6
void blur(int height, int width, RGBTRIPLE image[height][width])
{
    // height and width are the height and width of the input image.
    RGBTRIPLE(*extension)[width + 2] = calloc(height + 2, (width + 2) * sizeof(RGBTRIPLE)); // I will handle edge and corner cases by creating a new 2d array with 0s around 
    RGBTRIPLE(*newImage)[width] = calloc(height, width * sizeof(RGBTRIPLE)); //output 
    int cof = 0, redSum = 0, greenSum = 0, blueSum = 0;
    int kernel[3][3] = {{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}; // Kernel for mean blur
    if (newImage == NULL || extension == NULL)
    {
        fprintf(stderr, "Not enough memory to create a new image.\n");
        return;
    }
    for(int i = 0; i < height; ++i)
    {
        memcpy(extension[i + 1], image[i], sizeof(image[i])); // Copy values from original images into extension, note that I intentionally copy at the i + 1 position.
    }
    for(int i = 1; i < height + 1; ++i)
    {
        for(int j = 1; j < width + 1; ++j)
        {
            redSum = 0; greenSum = 0; blueSum = 0; //Reset red, green, blue sum values.
            for(int k = 0; k < KERNEL_HEIGHT; ++k)
            {
                for(int t = 0; t < KERNEL_WIDTH; ++t) 
                {
                    cof = kernel[k][t]; // I will multiply each value in the kernel with the pixel value and its neighbors.
                    redSum += cof * extension[i - 1 + k][j - 1 + t].rgbtRed;
                    greenSum += cof * extension[i - 1 + k][j - 1 + t].rgbtGreen;
                    blueSum += cof * extension[i - 1 + k][j - 1 + t].rgbtBlue;
                }
            }
            if(i == 1 || i == height) // Detecting edge cases and corner
            {
                if(j == 1 || j == width) // Corner
                {
                    newImage[i - 1][j - 1].rgbtRed = (int) round((float) redSum / (float) CORNER);
                    newImage[i - 1][j - 1].rgbtGreen = (int) round((float) greenSum / (float) CORNER);
                    newImage[i - 1][j - 1].rgbtBlue = (int) round((float) blueSum / (float) CORNER);
                }
                else // Edges
                {
                    newImage[i - 1][j - 1].rgbtRed = (int) round((float) redSum / (float) EDGE);
                    newImage[i - 1][j - 1].rgbtGreen = (int) round((float) greenSum / (float) EDGE);
                    newImage[i - 1][j - 1].rgbtBlue = (int) round((float) blueSum / (float) EDGE);
                }
            }
            else //Normal cases
            {
                newImage[i - 1][j - 1].rgbtRed = (int) round((float) redSum / (float) KERNEL_SIZE);
                newImage[i - 1][j - 1].rgbtGreen = (int) round((float) greenSum / (float) KERNEL_SIZE);
                newImage[i - 1][j - 1].rgbtBlue = (int) round((float) blueSum / (float) KERNEL_SIZE);
            }
        }
    }
    for(int i = 0; i < height; ++i)
    {
        memcpy(image[i], newImage[i], sizeof(newImage[i])); // Copy back the results into my original image.
    }
    free(extension);
    free(newImage);
    return;
}

这是一个测试用例:
使用样本 3x3 图像进行测试(过滤中间像素)
第一行:(10、20、30)、(40、50、60)、(70、80、90)
第二行:(110 , 130, 140), (120, 140, 150), (130, 150, 160)
第三排:(200, 210, 220), (220, 230, 240), (240, 250, 255)

预期产量:127 140 149
实际产量:91 100 106

几天来我一直在尝试修复此功能(gg搜索,阅读文档),但仍然没有结果。我认为这与我如何为扩展矩阵分配内存以及如何遍历它有关。我对动态内存分配很陌生,所以也许这就是我出错的部分。

标签: cimage-processingconvolutioncs50

解决方案


我讨厌这样做,并且会在我有更多时间时重新访问,但是...以下内容尚未经过测试并且故意不完整-仅用作样式指南。

我将发布 BlurPixel() 的大部分内容,向您展示如何以逻辑方式处理每个像素。请注意,我们没有疯狂的索引,并且每个写入都由 if 语句检查。

      int r=0, g=0, b=0;  // Sums accumulators
      int numElements = 0; // Counts number of items accumulated.

      // Loop from 1 less to 1 more than the current X and Y position.
      for(int xOffset=-1; xOffset<=1; xOffset++)
      {
        for(int yOffset=-1; yOffset<=1; yOffset++)
        {
          const int newX = x + xOffset;
          const int newY = y + yOffset;

          // Bounds check... 
          if(newX >= 0 && newX < width &&
             newY >= 0 && newY < height) 
          {
            // In range, add to accumulators and increment element counter.
            r += image[newY][newX].red;
            g += image[newY][newX].green;
            b += image[newY][newX].blue;
            numElements++;
          }
        }
      }  

      // Assign the rounded values to the new structure.  Could do this with integers
      // if we added numElements/2 to list before divide.
      newImage[j][i].red = (int)round((float) r / numElements);
      newImage[j][i].green = (int)round((float) g / numElements);
      newImage[j][i].blue = (int)round((float) b / numElements);

推荐阅读