CS50作业:Sobel算子边缘检测函数蓝通道值计算错误排查
CS50 Filter More作业:Sobel算子蓝通道计算错误排查
问题情况
- 实现了Sobel算子的位图边缘检测函数,红、绿通道输出正确,但蓝通道无法通过CS50测试用例
- 执行
check50 cs50/problems/2024/x/filter/more时,蓝通道测试失败,预期值为255但代码计算结果错误 - 已添加溢出处理逻辑(超过255时设为255),但未解决问题
实现代码
void edges(int height, int width, RGBTRIPLE image[height][width]) { int Gx_Matrix[3][3] = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}}; int Gy_Matrix[3][3] = {{-1, -2, -1}, {0, 0, 0}, {1, 2, 1}}; RGBTRIPLE copy[height][width]; // Create a copy of the original image // for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { copy[i][j] = image[i][j]; } } // Loop over each pixel // // Calculate the weighted sum of each colour channel // // Combine the Gx and Gy weight sum to attain a single value for each channel // for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { float Gx_SumRed = 0; float Gy_SumRed = 0; float Gx_SumGreen = 0; float Gy_SumGreen = 0; float Gx_SumBlue = 0; float Gy_SumBlue = 0; for (int di = -1; di <= 1; di++) { for (int dj = -1; dj <= 1; dj++) { int ni = i + di; int nj = j + dj; if((ni >= 0) && (ni < height) && (nj >= 0) && (nj < width)) { Gx_SumRed += Gx_Matrix[di + 1][dj + 1] * (copy[ni][nj].rgbtRed); Gx_SumGreen += Gx_Matrix[di + 1][dj + 1] * (copy[ni][nj].rgbtGreen); Gx_SumBlue += Gx_Matrix[di + 1][dj + 1] * (copy[ni][nj].rgbtBlue); Gy_SumRed += Gy_Matrix[di + 1][dj + 1] * (copy[ni][nj].rgbtRed); Gy_SumGreen += Gy_Matrix[di + 1][dj + 1] * (copy[ni][nj].rgbtGreen); Gy_SumBlue += Gy_Matrix[di + 1][dj + 1] * (copy[ni][nj].rgbtBlue); } else { continue; } } } image[i][j].rgbtRed = round(sqrt((Gx_SumRed * Gx_SumRed) + (Gy_SumRed * Gy_SumRed))); image[i][j].rgbtGreen = round(sqrt((Gx_SumGreen * Gx_SumGreen) + (Gy_SumGreen * Gy_SumGreen))); image[i][j].rgbtBlue = round(sqrt((Gx_SumBlue * Gx_SumBlue) + (Gy_SumBlue * Gy_SumBlue))); if (image[i][j].rgbtRed > 255) { image[i][j].rgbtRed = 255; } if (image[i][j].rgbtGreen > 255) { image[i][j].rgbtGreen = 255; } if (image[i][j].rgbtBlue > 255) { image[i][j].rgbtBlue = 255; } } } return; }
错误原因
问题出在溢出处理的顺序上:RGBTRIPLE中的rgbtRed、rgbtGreen、rgbtBlue都是无符号字符类型(unsigned char),取值范围仅为0-255。当你直接把超过255的计算结果赋值给这些字段时,数值会被自动截断(比如260会变成4),之后再判断>255时,截断后的数值已经小于255,无法触发修正逻辑。
蓝通道的测试用例中,计算结果超过了255,赋值时被截断成了错误的小值,导致测试失败;而红、绿通道的测试用例计算结果可能未超过255,或者截断后刚好符合预期,所以没有暴露问题。
修复方案
先将计算结果存入临时变量,判断并修正溢出后,再赋值给图像通道:
// 替换原有的赋值和溢出判断代码 float red = round(sqrt((Gx_SumRed * Gx_SumRed) + (Gy_SumRed * Gy_SumRed))); float green = round(sqrt((Gx_SumGreen * Gx_SumGreen) + (Gy_SumGreen * Gy_SumGreen))); float blue = round(sqrt((Gx_SumBlue * Gx_SumBlue) + (Gy_SumBlue * Gy_SumBlue))); image[i][j].rgbtRed = (red > 255) ? 255 : red; image[i][j].rgbtGreen = (green > 255) ? 255 : green; image[i][j].rgbtBlue = (blue > 255) ? 255 : blue;
或者用if语句的形式:
float red_val = round(sqrt((Gx_SumRed * Gx_SumRed) + (Gy_SumRed * Gy_SumRed))); if (red_val > 255) { image[i][j].rgbtRed = 255; } else { image[i][j].rgbtRed = red_val; } // 绿、蓝通道同理处理
这样就能确保超过255的数值在赋值前被修正为255,避免截断错误。
内容的提问来源于stack exchange,提问作者Aditya Raja
相关产品推荐
相关产品推荐

