我错误地修复了一个错误,想了解原因

问题描述 投票:0回答:1

我是编程新手,目前正在学习 CS50x 课程。我最近遇到了 PSET 4 - Filter(更多),其中我必须用 C 语言编写一个程序来对 BMP 图片执行一些操作。 在分享这个问题之前,我想指出我确实遵循学术诚实的准则,并且我自己解决了这个问题。它已提交并计算(我不会分享完整的解决方案,仅分享每个步骤的前几行)。话虽这么说,我只是想要一些帮助来理解为什么我的更改修复了我的代码,因为我花了几天时间却无法给出解释。我相信这对我的学习过程很重要。

挑战是使用 Sorbel 算子来识别和过滤图像内的边缘。复制图像后(这样我就不会在像素上创建多米诺骨牌效应),我创建了一个 2D 数组来存储内核并初始化了一些变量:

double gxRed = 0, gxBlue = 0, gxGreen = 0;
double gyRed = 0, gyBlue = 0, gyGreen = 0;

int gx[3][3] = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}};
int gy[3][3] = {{-1, -2, -1}, {0, 0, 0}, {1, 2, 1}};

然后我通过取消 Gx/y 的值来解决边缘情况:

if (i - 1 < 0)
{
    gx[0][0] = 0, gx[0][1] = 0, gx[0][2] = 0;
    gy[0][0] = 0, gy[0][1] = 0, gy[0][2] = 0;
}

接下来,我根据内核数组计算每个颜色通道:

gxRed += (imageCopy[i - 1][j - 1].rgbtRed * gx[0][0]) + (imageCopy[i - 1][j].rgbtRed * gx[0][1]) +
                     (imageCopy[i - 1][j + 1].rgbtRed * gx[0][2]);
gxRed += (imageCopy[i][j - 1].rgbtRed * gx[1][0]) + (imageCopy[i][j].rgbtRed * gx[1][1]) +
                     (imageCopy[i][j + 1].rgbtRed * gx[1][2]);
gxRed += (imageCopy[i + 1][j - 1].rgbtRed * gx[2][0]) + (imageCopy[i + 1][j].rgbtRed * gx[2][1]) +
                     (imageCopy[i + 1][j + 1].rgbtRed * gx[2][2]);

计算幅度并应用于原始图片:

image[i][j].rgbtRed = round(sqrt((gxRed * gxRed) + (gyRed * gyRed)));

考虑 255 范围并应用修正(如果有):

if (image[i][j].rgbtRed > 255)
{
    image[i][j].rgbtRed = 255;
}

一切顺利,生成的图像看起来不错,正如我所预期的那样。然而,在运行课程检查时,绿色通道出现了一些问题,如下所示:

使用示例 3x3 图像进行测试
第一行:(0, 10, 25), (0, 10, 30), (40, 60, 80)
第二行:(20,30,90),(30,40,100),(80,70,90)
第三行:(20,20,40),(30,10,30),(50,40,10)

预期输出:
76 117 255
213 228 255
192 190 255
114 102 255
210 150 60
103 108 255
114 117 255
200 197 255
210 190 255

实际产量:
76 117 66
213 228 140
192 190 66
114 102 6
210 150 60
103 108 39
114 117 66
200 197 129
210 190 66


正如您所看到的,绿色通道存在一个特定问题。显然,我的第一直觉是仔细检查负责处理绿色的代码的每个部分,但什么也没有!其他颜色的代码完全相同,除了 gx/yGreen 和 .rgbtGreen 之外,甚至没有一个空格不同。然后我去了边缘情况,但同样,其他通道如何工作正常而只有绿色关闭?它们都由相同的逻辑处理,我通过为 Gx 和 Gy 定义一个数组来确保这一点。对我来说,只有像素的绿色通道出现异常似乎是不可能的。如果代码有问题,整个 RGB 值应该关闭。好吧,不过我注意到,当绿色在预期输出中为 255 时,问题就发生了,尽管我以与处理蓝色和红色相同的方式处理这种情况。经过几天的头痛和几乎放弃(我已经提交了 -less 版本,所以这是可选的),我只是在寻址 255 范围之前创建了一个临时变量来存储 Gx/y 的计算,如下所示:
int tempGreen = round(sqrt((gxGreen * gxGreen) + (gyGreen * gyGreen)));
int tempRed = round(sqrt((gxRed * gxRed) + (gyRed * gyRed)));
int tempBlue = round(sqrt((gxBlue * gxBlue) + (gyBlue * gyBlue)));

if (tempGreen > 255)
{
    tempGreen = 255;
}
if (tempRed > 255)
{
    tempRed = 255;
}
if (tempBlue > 255)
{
    tempBlue = 255;
}

image[i][j].rgbtGreen = tempGreen;
image[i][j].rgbtRed = tempRed;
image[i][j].rgbtBlue = tempBlue;

这是相同的代码,我只是添加了变量,问题就解决了。我通过了所有检查。为什么?如果这是问题所在,那么蓝色和红色不应该也会发生这种情况吗?这一直困扰着我,所以我决定在这里分享。我对这篇超长的文章表示歉意,这是我的第一篇文章,所以也欢迎任何关于如何更好地在这里写作的建议。

提前非常感谢!

c cs50
1个回答
0
投票

这是相同的代码,我只是添加了变量,问题就解决了。

不。这不是同一个代码。

tempGreen
int
,而
.rgbtGreen
uint8_t

(我知道这一点是因为我读过很多 CS50 问题,但通常您有责任提供所有必需的信息。所有定义等)

因此,

if (image[i][j].rgbtRed > 255)
永远不可能为真,因为任何大于
255
的值在将其分配给该变量时都会溢出。

在溢出或回绕已经发生之后,您无法阻止它。

您的固定代码会在将其截断以适合

uint8_t
之前检查较大的值。

© www.soinside.com 2019 - 2024. All rights reserved.