CS50 Pset 4-滤镜-Helpers.c-模糊

时间:2020-05-11 19:57:26

标签: c computer-science cs50

以下是我的代码。编译时,代码中没有明显的错误。但是,我没有通过所有Check50测试。我的算法推理有什么缺陷?

基本上,我的代码旨在将所有像素复制到另一个称为“旧”的结构中,该结构将保留原始图像的内容。

接下来,我创建一个称为“ temp”的临时像素结构数组。数组由9个元素组成,包括它本身和周围的每个像素。以下4个“ if语句”测试像素是否为边框像素。如果是,则将'temp'数组中相关元素的红色分配为负值-1。这本质上是要在以后的算法中将其丢弃。

接下来,我声明三个整数变量,以跟踪周围像素的总红色,绿色和蓝色值。然后,我检查每个周围的像素是否红色值是负数,如果是,我将其丢弃。如果确实是一个正数,则将红色,蓝色和绿色的总数加起来。我同时跟踪周围像素的总数,以便最终可以将红色,绿色和蓝色的总值除以该计数。对每个像素重复以上步骤。从理论上讲,这应该会产生模糊的图像,但显然不会。我的推理或代码有什么问题?

  void blur(int height, int width, RGBTRIPLE image[height][width])
 {
 RGBTRIPLE old[height][width];
 RGBTRIPLE temp[9];

for (int i = 0; i < height; i++)
{
    for (int j = 0; j < width; j++)
    {
        old[i][j] = image[i][j];
    }
}
for (int i = 0; i < height; i++)
{
    for (int j = 0; j < width; j++)
    {
        temp[0] = old[i-1][j-1];
        temp[1] = old[i][j-1];
        temp[2] = old[i+1][j-1];
        temp[3] = old[i-1][j];
        temp [4] = old[i][j];
        temp [5] = old[i+1][j];
        temp [6] = old[i-1][j+1];
        temp [7] = old[i][j+1];
        temp [8] = old[i+1][j+1];

        if (i == 0)
        {
            temp[0].rgbtRed = -1;
            temp[3].rgbtRed = -1;
            temp[6].rgbtRed = -1;
        }
        else if (i == height-1)
        {
            temp[2].rgbtRed = -1;
            temp[5].rgbtRed = -1;
            temp[8].rgbtRed = -1;
        }
        if (j == 0)
        {
            temp[0].rgbtRed = -1;
            temp[1].rgbtRed = -1;
            temp[2].rgbtRed = -1;
        }
        else if (j == width-1)
        {
            temp[6].rgbtRed = -1;
            temp[7].rgbtRed = -1;
            temp[8].rgbtRed = -1;
        }

        int Red = 0;
        int Green = 0;
        int Blue = 0;

        int c = 0;

        for (int m = 0; m <= 8; m++)
        {
            if (temp[m].rgbtRed >= 0)
            {
                c++;
                Red = Red + temp[m].rgbtRed;
                Green = Green + temp[m].rgbtGreen;
                Blue = Blue + temp[m].rgbtBlue;
            }
        }
        image[i][j].rgbtRed = round(Red/c);
        image[i][j].rgbtGreen = round(Green/c);
        image[i][j].rgbtBlue = round(Blue/c);
    }
}

}

[编辑]主要代码:

  #include <getopt.h>
  #include <stdio.h>
  #include <stdlib.h>

  #include "helpers.h"

  int main(int argc, char *argv[])
  {

// Define allowable filters
char *filters = "bgrs";

// Get filter flag and check validity
char filter = getopt(argc, argv, filters);
if (filter == '?')
{
    fprintf(stderr, "Invalid filter.\n");
    return 1;
}

// Ensure only one filter
if (getopt(argc, argv, filters) != -1)
{
    fprintf(stderr, "Only one filter allowed.\n");
    return 2;
}

// Ensure proper usage
if (argc != optind + 2)
{
    fprintf(stderr, "Usage: filter [flag] infile outfile\n");
    return 3;
}

// Remember filenames
char *infile = argv[optind];
char *outfile = argv[optind + 1];

// Open input file
FILE *inptr = fopen(infile, "r");
if (inptr == NULL)
{
    fprintf(stderr, "Could not open %s.\n", infile);
    return 4;
}

// Open output file
FILE *outptr = fopen(outfile, "w");
if (outptr == NULL)
{
    fclose(inptr);
    fprintf(stderr, "Could not create %s.\n", outfile);
    return 5;
}

// Read infile's BITMAPFILEHEADER
BITMAPFILEHEADER bf;
fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);

// Read infile's BITMAPINFOHEADER
BITMAPINFOHEADER bi;
fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr);

// Ensure infile is (likely) a 24-bit uncompressed BMP 4.0
if (bf.bfType != 0x4d42 || bf.bfOffBits != 54 || bi.biSize != 40 ||
    bi.biBitCount != 24 || bi.biCompression != 0)
{
    fclose(outptr);
    fclose(inptr);
    fprintf(stderr, "Unsupported file format.\n");
    return 6;
}

int height = abs(bi.biHeight);
int width = bi.biWidth;

// Allocate memory for image
RGBTRIPLE(*image)[width] = calloc(height, width * sizeof(RGBTRIPLE));
if (image == NULL)
{
    fprintf(stderr, "Not enough memory to store image.\n");
    fclose(outptr);
    fclose(inptr);
    return 7;
}

// Determine padding for scanlines
int padding = (4 - (width * sizeof(RGBTRIPLE)) % 4) % 4;

// Iterate over infile's scanlines
for (int i = 0; i < height; i++)
{
    // Read row into pixel array
    fread(image[i], sizeof(RGBTRIPLE), width, inptr);

    // Skip over padding
    fseek(inptr, padding, SEEK_CUR);
}

// Filter image
switch (filter)
{
    // Blur
    case 'b':
        blur(height, width, image);
        break;

    // Grayscale
    case 'g':
        grayscale(height, width, image);
        break;

    // Reflection
    case 'r':
        reflect(height, width, image);
        break;

    // Sepia
    case 's':
        sepia(height, width, image);
        break;
}

// Write outfile's BITMAPFILEHEADER
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);

// Write outfile's BITMAPINFOHEADER
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);

// Write new pixels to outfile
for (int i = 0; i < height; i++)
{
    // Write row to outfile
    fwrite(image[i], sizeof(RGBTRIPLE), width, outptr);

    // Write padding at end of row
    for (int k = 0; k < padding; k++)
    {
        fputc(0x00, outptr);
    }
}

// Free memory for image
free(image);

// Close infile
fclose(inptr);

// Close outfile
fclose(outptr);

return 0;
}

[RGB三重防御]

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

1 个答案:

答案 0 :(得分:1)

代码以temp[0] = old[i-1][j-1];的第一个迭代超出范围访问内存


代码需要确保对边缘和角落的访问保持在数组之内。

我不清楚OP如何处理这些情况。

举个例子:下面是对8、5或3个相邻像素的取平均值。效率不高,只是说明性的。

void blur(int height, int width, RGBTRIPLE image[height][width]) {
  RGBTRIPLE old[height][width];
  memcpy(old, image, sizeof image[height][width] * height * width);

  for (int i = 0; i < height; i++) {
    for (int j = 0; j < width; j++) {
      int Red = 0;
      int Green = 0;
      int Blue = 0;
      int count = 0;
      for (int di = -1; di <= 1; di++) {
        int pi = i + di;
        if (pi >= 0 && pi < height) {
          for (int dj = -1; dj <= 1; dj++) {
            int pj = j + dj;
            if (pj >= 0 && pj < width) {
              Red += old[pj][pj].rgbtRed;
              Green += old[pj][pj].rgbtGreen;
              Blue += old[pj][pj].rgbtBlue;
              count++;
            }
          }
        }
      }
      // I am suspicious of using FP code here.
      // I'd use image[i][j].rgbtRed = (Red + count/2) / count;
      image[i][j].rgbtRed = round(Red / count);
      image[i][j].rgbtGreen = round(Green / count);
      image[i][j].rgbtBlue = round(Blue / count);
    }
  }
}

对我来说,我会在所有4条边上都增大old 1,然后将原始边复制到新边,将角复制到新边。然后轻松对原始图像进行平均,每个像素有8个邻居。