我是编程新手,目前正在学习CS50x课程。我最近遇到PSET 4 - Filter(更多),其中我不得不用C编写一个程序来执行BMP图片的一些操作。在我分享这个问题之前,我想指出的是,我确实遵循学术诚实的准则,我自己解决了这个问题。它已经提交并计算过了(我不会分享完整的解决方案,只是每个步骤的前几行)。话虽如此,我只是想得到一些帮助来理解为什么我的更改修复了我的代码,因为我花了几天时间也找不到解释。我认为这对我的学习过程很重要。
挑战是使用Sobel算子来识别和过滤图像内部的边缘。在复制了图像之后(这样我就不会在像素上产生多米诺骨牌效应),我创建了一个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;
}
一切都很好,结果图像看起来很好,正如我所料。但是,在运行路线检查时,绿色通道存在一些问题,如下所示:
- 使用样本3x 3图像进行测试 *
- 第一行:(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
如您所见,绿色通道存在特定问题。显然,我的第一React是仔细检查负责处理绿色的代码的每一部分,但什么也没有!这是完全相同的代码为其他颜色,甚至没有一个单一的空间不同,除了gx/yGreen和. rgbtGreen。然后我去了边缘的情况下,但再次,如何能其他渠道的工作很好,只有绿色关闭?它们都是由相同的逻辑处理的,我通过为Gx和戈伊定义一个数组来确保这一点。在我看来,只有像素的绿色通道行为不端是不可能的。如果代码有问题,整个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;
这是相同的代码,我只是添加了变量,问题得到了解决。我通过了所有的检查。为什么?如果这是问题所在,难道不应该也发生在蓝色和红色身上吗?这是我一直在寻找的,所以我决定在这里分享。我为这个超长的帖子道歉,这是我的第一个,所以任何关于如何更好地写在这里的建议也很受欢迎。
非常感谢你提前!
2条答案
按热度按时间xtfmy6hx1#
这是相同的代码,我只是添加了变量,问题得到了解决。
不,不是同一个密码.
tempGreen
是int
,而.rgbtGreen
是uint8_t
。(我知道这一点,因为我读了很多CS50的问题,但一般来说,你有责任提供所有必要的信息。所有定义等)
因此,
if (image[i][j].rgbtRed > 255)
永远不会为true,因为任何大于255
的值在赋值给该变量时都会溢出。在溢出或回绕已经发生之后,您无法阻止它们。
您的固定代码在将较大的值切碎以适合
uint8_t
之前检查它们。gojuced72#
“我通过了所有的检查。为什么?”
最简单的第一步是启用所有警告。
一个好的编译器会警告
image[i][j].rgbtRed > 255
总是为false。保存时间-启用所有警告。