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

挑战是使用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;
}

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

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;
}

一切都很好,生成的图像看起来也很好,正如我所预期的那样.然而,在运行课程判断时,绿色通道出现了一些问题,如下所示:

testing with sample 3x3 image
first row: (0, 10, 25), (0, 10, 30), (40, 60, 80)
second row: (20, 30, 90), (30, 40, 100), (80, 70, 90)
third row: (20, 20, 40), (30, 10, 30), (50, 40, 10)

Expected Output:
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

Actual Output:
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


As you can see, there was a specific issue with the green channel. My first instinct was, obviously, double check every part of the code responsible for dealing with green, but there was nothing! It was EXACTLY the same code for the other colors, not even a single space different apart from gx/yGreen and .rgbtGreen. Then I went to the edge cases, but again, how can the other channels work fine and only green be off? They are all handled by the same logic, and I made sure of that by defining an array for Gx and Gy. It seemed just impossible to me that only the green channel of the pixel was misbehaving. If there was a problem with the code, the whole RGB values should be off. Well, I could notice, though, that the problem happened when green was 255 in the expected output, even though I treated this case the same way I did for blue and red. After days of headaches and almost giving up (I had already submitted the -less version, so this was optional), I just created a temporary variable to store the computation of Gx/y before addressing the 255 range, as below:
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;

这是相同的代码,我只是添加了变量,问题就解决了.我通过了所有的判断.为什么?如果这就是问题所在,难道蓝色和红色不应该也是这样吗?这一直困扰着我,所以我决定在这里分享.我为这篇超长的帖子道歉,这是我的第一篇,所以也欢迎任何关于如何更好地在这里写作的技巧.

非常提前感谢您!

推荐答案

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

不是的.这是不同的代码.

tempGreenint,而.rgbtGreenuint8_t.

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

因此,if (image[i][j].rgbtRed > 255)永远不可能为真,因为当您将其赋给该变量时,任何大于255的值都已经溢出.

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

您的固定代码会先判断较大的值,然后再将它们砍成适合uint8_t的值.

C++相关问答推荐

从STdin读写超过4096个字节

如何判断宏参数是否为C语言中的整型文字

使用NameSurname扫描到两个单独的字符串

当多个线程在C中写入相同的文件描述符时,如何防止争用情况?

变量>;-1如何在C中准确求值?

调用mProtection将堆栈上的内存设置为只读,直接导致程序SIGSEGV

Make Node函数.S有什么问题吗?

VS代码';S C/C++扩展称C23真关键字和假关键字未定义

用C语言计算文本文件中的整数个数

按长度对argv中的单词进行排序

如何将C中的两个字符串与从文件接收的字符串中的字符数进行比较

初始成员、公共初始序列、匿名联合和严格别名如何在C中交互?

CS50判断灯泡运动的问题,判断时多出一个灯泡,但不在终端上

我正在try 将QSORT算法实现为C++中的泛型函数

从整型转换为浮点型可能会改变其值.

是否有单独的缓冲区用于读写库调用?

解密Chrome加密密钥

我正在使用 klib 库 我可以使用 (khash) KHASH_SET_INIT_INT64() 负值作为键.因为我在头文件中看到它使用 unsigned long int

GDB 用内容初始化数组

如何确定 C 程序中的可用堆内存