Cs50 的问题集 4 - 无滤波器 - 反射函数

标签 c filter cs50

我编写了函数来反射(reflect) zip 文件中提供的 .bmps 图像。

经过一些研究,我发现很多解决这个问题的人都将图像的宽度除以2。但是,我觉得这不适用于我的代码。

该代码确实反射(reflect)了肉眼所见的图像,但它不符合 check50 提供的任何标准。

如果 width/2 确实是必要的,即使在我的代码中,请解释在我的代码实例中实现它背后的逻辑:

void reflect(int height, int width, RGBTRIPLE image[height][width])
{
    RGBTRIPLE coloursofaddress[width];
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            // Step 3
            coloursofaddress[width - 1 - j].rgbtRed = image[i][j].rgbtRed;
            coloursofaddress[width - 1 - j].rgbtGreen = image[i][j].rgbtGreen;
            coloursofaddress[width - 1 - j].rgbtBlue = image[i][j].rgbtBlue;
            
            // Step 4
            image[i][j].rgbtRed = coloursofaddress[j].rgbtRed;
            image[i][j].rgbtGreen = coloursofaddress[j].rgbtGreen;
            image[i][j].rgbtBlue = coloursofaddress[j].rgbtBlue;
        }
    }
    return;
}

以下是错误消息:

:( reflect correctly filters 1x2 image
    expected "0 0 255\n255 0...", not "5 0 0\n255 0 0..."
:( reflect correctly filters 1x3 image
    expected "0 0 255\n0 255...", not "5 0 0\n0 255 0..."
:( reflect correctly filters image that is its own mirror image
    expected "255 0 0\n255 0...", not "5 0 0\n255 0 0..."
:( reflect correctly filters 3x3 image
    expected "70 80 90\n40 5...", not "5 0 0\n40 50 6..."
:( reflect correctly filters 4x4 image
    expected "100 110 120\n7...", not "5 0 0\n0 0 0\n..." 

编辑: 通过进一步仔细检查上述代码输出的反射图像,一切似乎都很完美,除了带有随机颜色的细细附加行像素 - 不知道为什么。通过放大图片底部可以看到它,但在输入 .bmp 中不可见。

编辑2: 更仔细地检查反射图像输出后,底部的“杂散”像素线似乎正好在中间结束。看起来反射图像的整个左半部分比预期高了 1 个像素单位,而右半部分则很好。一条显示这种清晰高度划分的线依稀可见,沿着图片的中心向下延伸。这开始变得有趣了。

最佳答案

你有两个问题。

在步骤 4 中,一半的数组尚未赋值。您对第一行使用不确定的值,对其他行使用旧值。这看起来就像将图像的一半移动了 1 行。

您应该使用标准交换机制来交换值。 正如评论中提到的,您不需要费心处理单独的字段,而只需交换整个结构:

void reflect(int height, int width, RGBTRIPLE image[height][width])
{
    RGBTRIPLE temp;
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            temp = image[i][j];
            image[i][width - 1 - j] = image[i][j];
            image[i][j] = temp;
        }
    }
    return;
}

此外,如果您运行交换 0..width-1 的整个范围你最终会交换 image[i][0]image[i][width-1]及以后image[i][width-1]image[i][0]它将相同的像素交换两次,得到原始图像。

只需运行条件为 j < width/2 的循环:

// define a SWAP macro just for convenience during following explanation
#define SWAP(x,y)   \
  do {              \
    RGBTRIPLE temp = (x); \
    (x) = (y);      \
    (y) = temp;     \
  } while (0)


void reflect(int height, int width, RGBTRIPLE image[height][width])
{
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width/2; j++)
        {
            // Replace image[i] to make code shorter during explanation.
            RGBTRIPLE *row=image[i];
            SWAP(row[j], row[width - 1 - j]);
        }
    }
    return;
}

我做了 2 个并非真正需要的替换,但使以下文本变得更短。

为什么只循环直到 j < width/2 ?如果我们想要反转整数数组,让我们看看每次迭代中的内存:

width==15
row: +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|
     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

j=0; SWAP(row[0],row[14]);
row: +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     |14| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13| 0|
     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

...

j=5; SWAP(row[5],row[9]);
row: +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     |14|13|12|11|10| 9| 6| 7| 8| 5| 4| 3| 2| 1| 0|
     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

j=6; SWAP(row[6],row[8]);
row: +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     |14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

j=7; SWAP(row[7],row[7]);
row: +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     |14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

你可以看到,交换一半元素后,我们就完成了。对于奇数个元素,最后一次交换只会交换自身,没有任何效果。

如果您现在继续运行到 width ,你再次交换回来:

j=8; SWAP(row[8],row[6]);
row: +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     |14|13|12|11|10| 9| 6| 7| 8| 5| 4| 3| 2| 1| 0|
     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

...

j=13; SWAP(row[13],row[1]);
row: +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     |14| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13| 0|
     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

j=14; SWAP(row[14],row[0]);
row: +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|
     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

这就是我们开始的地方。

很明显我们运行了SWAP(row[j],row[width-j-1]);稍后与交换索引相同:SWAP(row[width-j-1],row[j]);其作用相同。

交换两次会恢复初始状态,并且您的图像不会改变。

关于Cs50 的问题集 4 - 无滤波器 - 反射函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63461237/

相关文章:

c - 如何在不使用 c 中的格式说明符的情况下打印 char、integer、float 和 double 值

c++ - 如何停止通过分层包含传播声明?

django - 如何在自定义模板标签上使用模板过滤器?

filter - Logstash Grok筛选器Apache访问日志

c - Pset4 (cs50) 恢复无法正常工作。它可以编译,但不能恢复超过 2 个 jpeg。检查 JPEG 签名是否有问题?

c - -lcs50 命令行参数在 clang 中有什么作用?

c - 在 Windows 上使用 GCC (MinGW) 编译 OpenGL

c - 从 C 中的终端获取所有输出

javascript - 使用列和全局过滤器过滤表 - 最有效的方法?

c - 如何使这段代码形成的金字塔(CS50马里奥程序)右对齐?