CS50 Filter-More项目Edges函数未通过check50,求问题排查
我在CS50 Filter-More项目中实现的Edges函数无法通过check50测试,以下是我的代码和测试失败结果:
头文件与宏定义
#include "helpers.h" #include "math.h" #include "stdlib.h" #define RED_COLOR 0 #define GREEN_COLOR 1 #define BLUE_COLOR 2 #define POS_X 0 #define POS_Y 1
getEdge函数
int getEdge(int i, int j, int height, int width, RGBTRIPLE image[height][width], int color_position, int position) { 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} }; int row_count = 0; int col_count = 0; int sum = 0; for (int row = i - 1; row <= (i + 1); row++) { col_count = 0; for (int column = j - 1; column <= (j + 1); column++) { if (row < 0 || row >= height || column < 0 || column >= width) { sum += 0; } if (color_position == RED_COLOR) { if (position == POS_X) sum += image[row][column].rgbtRed * gx[row_count][col_count]; else sum += image[row][column].rgbtRed * gy[row_count][col_count]; } else if (color_position == GREEN_COLOR) { if (position == POS_X) sum += image[row][column].rgbtGreen * gx[row_count][col_count]; else sum += image[row][column].rgbtGreen * gy[row_count][col_count]; } else { if (position == POS_X) sum += image[row][column].rgbtBlue * gx[row_count][col_count]; else sum += image[row][column].rgbtBlue * gy[row_count][col_count]; } col_count++; } row_count++; } return sum; }
sobel函数与edges主函数
// Calculate sobel value for each channel (capping at 255) int sobel (int Gx, int Gy) { int n = sqrt(Gx^2 + Gy^2); n = fmin(255, n); return n; } // Detect edges void edges(int height, int width, RGBTRIPLE image[height][width]) { RGBTRIPLE copy[height][width]; // copy image for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) { copy[i][j] = image[i][j]; } for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) { image[i][j].rgbtRed = sobel(getEdge(i, j, height, width, copy, RED_COLOR, POS_X), getEdge(i, j, height, width, copy, RED_COLOR, POS_Y)); image[i][j].rgbtGreen = sobel(getEdge(i, j, height, width, copy, GREEN_COLOR, POS_X), getEdge(i, j, height, width, copy, GREEN_COLOR, POS_Y)); image[i][j].rgbtBlue = sobel(getEdge(i, j, height, width, copy, BLUE_COLOR, POS_X), getEdge(i, j, height, width, copy, BLUE_COLOR, POS_Y)); } return; }
check50测试失败结果
❌ 正确过滤中间像素
原因
预期输出:"210 150 60\n",实际输出:"4 15 10\n"
日志
测试使用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)
❌ 正确过滤边缘像素
原因
预期输出:"213 228 255\n",实际输出:"19 20 15\n"
日志
测试使用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\n",实际输出:"0 0 0\n"
日志
测试使用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)
❌ 正确过滤3x3图像
原因
预期输出:"76 117 255\n21...",实际输出:"0 17 0\n15 11 ..."
日志
测试使用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)
问题定位与修复方案
1. Sobel垂直卷积核定义错误(核心问题)
你定义的gy垂直边缘检测核第一行最后一个元素错误,正确的垂直核应为:
int gy[3][3]={ {-1, -2, -1}, {0, 0, 0}, {1, 2, 1} };
原代码中该位置写为1,导致垂直边缘计算完全偏离预期。
2. 边界越界访问问题
getEdge函数中,检测到坐标越界后仅执行sum += 0,但后续仍会访问image[row][column],触发非法内存访问,导致结果异常。需调整逻辑跳过越界情况:
for (int column = j - 1; column <= (j + 1); column++) { // 越界则跳过当前循环,不执行后续计算 if (row < 0 || row >= height || column < 0 || column >= width) { col_count++; continue; } // 颜色通道计算代码... col_count++; }
或更简洁的写法:
for (int column = j - 1; column <= (j + 1); column++) { if (!(row < 0 || row >= height || column < 0 || column >= width)) { // 颜色通道计算代码... } col_count++; }
3. 平方运算使用错误运算符
C语言中^是位异或运算符,不是幂运算。计算平方应使用乘法(效率更高)或pow函数,同时要避免int溢出:
// 修正后的sobel函数 int sobel (int Gx, int Gy) { // 转为long long避免平方后溢出 long long gx_sq = (long long)Gx * Gx; long long gy_sq = (long long)Gy * Gy; // 用round取整,避免直接截断小数导致结果偏差 int n = round(sqrt(gx_sq + gy_sq)); n = fmin(255, n); return n; }
内容的提问来源于stack exchange,提问作者Larisa P

