CS50图像模糊边缘功能异常 求助排查问题
问题
我知道代码看起来不够规范,但打算先实现功能再优化结构。我在CS50中编写的图像blur函数,运行check50时提示无法正确模糊边缘,但在测试固定RGB值的文件中该技术能正常工作。
代码如下:
void blur(int height, int width, RGBTRIPLE image[height][width]) { RGBTRIPLE copy[height][width]; for(int i = 0; i < height; i++) { for(int j = 0; j < width; j++) { blurcorner(i,j,height,width,image,copy); bluredge(i,j,height,width,image,copy); image[i][j] = copy[i][j]; } } return; } //////// void blurcorner (int i, int j, int height, int width, RGBTRIPLE image[height][width],RGBTRIPLE copy[height][width]) { if (i == height - 1 && j == width - 1) { int redav = (image[i - 1][j].rgbtRed + image[i][j-1].rgbtRed + image[i-1][j-1].rgbtRed + image[i][j].rgbtRed) / 4; copy[i][j].rgbtRed = redav; int greenav = (image[i - 1][j].rgbtGreen + image[i][j-1].rgbtGreen + image[i-1][j-1].rgbtGreen + image[i][j].rgbtGreen) / 4; copy[i][j].rgbtGreen = greenav; int blueav = (image[i - 1][j].rgbtBlue + image[i][j-1].rgbtBlue + image[i-1][j-1].rgbtBlue + image[i][j].rgbtBlue) / 4; copy[i][j].rgbtBlue = blueav; } else if (i == height - 1 && j == 0) { int redav = (image[i - 1][j].rgbtRed + image[i][j+1].rgbtRed + image[i+1][j+1].rgbtRed + image[i][j].rgbtRed) / 4; copy[i][j].rgbtRed = redav; int greenav = (image[i - 1][j].rgbtGreen + image[i][j+1].rgbtGreen + image[i+1][j+1].rgbtGreen + image[i][j].rgbtGreen) / 4; copy[i][j].rgbtGreen = greenav; int blueav = (image[i - 1][j].rgbtBlue + image[i][j+1].rgbtBlue + image[i+1][j+1].rgbtBlue + image[i][j].rgbtBlue) / 4; copy[i][j].rgbtBlue = blueav; } else if (i == 0 && j == 0) { int redav = (image[i + 1][j].rgbtRed + image[i][j+1].rgbtRed + image[i+1][j+1].rgbtRed + image[i][j].rgbtRed) / 4; copy[i][j].rgbtRed = redav; int greenav = (image[i + 1][j].rgbtGreen + image[i][j+1].rgbtGreen + image[i+1][j+1].rgbtGreen + image[i][j].rgbtGreen) / 4; copy[i][j].rgbtGreen = greenav; int blueav = (image[i + 1][j].rgbtBlue + image[i][j+1].rgbtBlue + image[i+1][j+1].rgbtBlue + image[i][j].rgbtBlue) / 4; copy[i][j].rgbtBlue = blueav; } else if (i == 0 && j == width - 1) { int redav = (image[i - 1][j].rgbtRed + image[i][j-1].rgbtRed + image[i-1][j-1].rgbtRed + image[i][j].rgbtRed) / 4; copy[i][j].rgbtRed = redav; int greenav = (image[i - 1][j].rgbtGreen + image[i][j-1].rgbtGreen + image[i-1][j-1].rgbtGreen + image[i][j].rgbtGreen) / 4; copy[i][j].rgbtGreen = greenav; int blueav = (image[i - 1][j].rgbtBlue + image[i][j-1].rgbtBlue + image[i-1][j-1].rgbtBlue + image[i][j].rgbtBlue) / 4; copy[i][j].rgbtBlue = blueav; } } void bluredge (int i, int j, int height, int width, RGBTRIPLE image[height][width],RGBTRIPLE copy[height][width]) { if (i == 0 && j > 0 && j < width - 1) { int redav = (image[i][j].rgbtRed + image[i][j-1].rgbtRed + image[i+1][j-1].rgbtRed + image[i+1][j].rgbtRed + image[i+1][j+1].rgbtRed + image[i][j+1].rgbtRed) / 6; copy[i][j].rgbtRed = redav; int greenav = (image[i][j].rgbtGreen + image[i][j-1].rgbtGreen + image[i+1][j-1].rgbtGreen + image[i+1][j].rgbtGreen + image[i+1][j+1].rgbtGreen + image[i][j+1].rgbtGreen) / 6; copy[i][j].rgbtGreen = greenav; int blueav = (image[i][j].rgbtBlue + image[i][j-1].rgbtBlue + image[i+1][j+1].rgbtBlue + image[i+1][j].rgbtBlue + image[i+1][j+1].rgbtBlue + image[i][j+1].rgbtBlue) / 6; copy[i][j].rgbtBlue = blueav; } else if (i == height - 1 && j > 0 && j < width - 1) { int redav = (image[i][j].rgbtRed + image[i][j-1].rgbtRed + image[i-1][j-1].rgbtRed + image[i-1][j].rgbtRed + image[i-1][j+1].rgbtRed + image[i][j+1].rgbtRed) / 6; copy[i][j].rgbtRed = redav; int greenav = (image[i][j].rgbtGreen + image[i][j-1].rgbtGreen + image[i-1][j-1].rgbtGreen + image[i-1][j].rgbtGreen + image[i-1][j+1].rgbtGreen + image[i][j+1].rgbtGreen) / 6; copy[i][j].rgbtGreen = greenav; int blueav = (image[i][j].rgbtBlue + image[i][j-1].rgbtBlue + image[i-1][j-1].rgbtBlue + image[i-1][j].rgbtBlue + image[i-1][j+1].rgbtBlue + image[i][j+1].rgbtBlue) / 6; copy[i][j].rgbtBlue = blueav; } else if (i > 0 && i < height - 1 && j == width - 1) { int redav = (image[i][j].rgbtRed + image[i-1][j].rgbtRed + image[i+1][j].rgbtRed + image[i+1][j-1].rgbtRed + image[i][j - 1].rgbtRed + image[i-1][j-1].rgbtRed) / 6; copy[i][j].rgbtRed = redav; int greenav = (image[i][j].rgbtGreen + image[i-1][j].rgbtGreen + image[i+1][j].rgbtGreen + image[i+1][j-1].rgbtGreen + image[i][j-1].rgbtGreen + image[i-1][j-1].rgbtGreen) / 6; copy[i][j].rgbtGreen = greenav; int blueav = (image[i][j].rgbtBlue + image[i-1][j].rgbtBlue + image[i+1][j].rgbtBlue + image[i+1][j-1].rgbtBlue + image[i][j-1].rgbtBlue + image[i-1][j-1].rgbtBlue) / 6; copy[i][j].rgbtBlue = blueav; } else if (i > 0 && i < height - 1 && j == 0) { int redav = (image[i][j].rgbtRed + image[i-1][j].rgbtRed + image[i+1][j].rgbtRed + image[i+1][j+1].rgbtRed + image[i][j+1].rgbtRed + image[i-1][j+1].rgbtRed) / 6; copy[i][j].rgbtRed = redav; int greenav = (image[i][j].rgbtGreen + image[i-1][j].rgbtGreen + image[i+1][j].rgbtGreen + image[i+1][j+1].rgbtGreen + image[i][j+1].rgbtGreen + image[i-1][j+1].rgbtGreen) / 6; copy[i][j].rgbtGreen = greenav; int blueav = (image[i][j].rgbtBlue + image[i-1][j].rgbtBlue + image[i+1][j].rgbtBlue + image[i+1][j+1].rgbtBlue + image[i][j+1].rgbtBlue + image[i-1][j+1].rgbtBlue) / 6; copy[i][j].rgbtBlue = blueav; } else { return; } }
check50报错:
:( blur correctly filters pixel on edge
expected "80 95 105
", not "80 95 108
"
我怀疑问题出在蓝色通道的计算上,请求帮忙排查。
问题排查与修复
1. 核心逻辑错误:修改原图导致计算污染
你的blur函数中,在循环里直接把copy的值写回image,后续像素计算时会用到已经修改过的原图数据,导致模糊结果错误。正确的做法是先完成所有像素的模糊计算到copy数组,最后一次性把copy复制回image。
修改后的blur函数:
void blur(int height, int width, RGBTRIPLE image[height][width]) { RGBTRIPLE copy[height][width]; // 先计算所有像素的模糊结果到copy for(int i = 0; i < height; i++) { for(int j = 0; j < width; j++) { blurcorner(i,j,height,width,image,copy); bluredge(i,j,height,width,image,copy); // 补充中间区域的像素模糊逻辑 if (!(i == 0 || i == height-1 || j ==0 || j == width-1)) { int red_sum = 0, green_sum = 0, blue_sum = 0; for(int di = -1; di <=1; di++){ for(int dj = -1; dj <=1; dj++){ red_sum += image[i+di][j+dj].rgbtRed; green_sum += image[i+di][j+dj].rgbtGreen; blue_sum += image[i+di][j+dj].rgbtBlue; } } copy[i][j].rgbtRed = red_sum /9; copy[i][j].rgbtGreen = green_sum /9; copy[i][j].rgbtBlue = blue_sum /9; } } } // 最后一次性复制回原图 for(int i = 0; i < height; i++) { for(int j = 0; j < width; j++) { image[i][j] = copy[i][j]; } } return; }
2. blurcorner函数的越界错误
- 当
i == 0 && j == width -1时,你使用了image[i-1][j](即image[-1][...]),数组下标越界,读取非法内存导致计算错误。正确的应该是取i+1方向的像素:
else if (i == 0 && j == width - 1) { int redav = (image[i + 1][j].rgbtRed + image[i][j-1].rgbtRed + image[i+1][j-1].rgbtRed + image[i][j].rgbtRed) / 4; copy[i][j].rgbtRed = redav; int greenav = (image[i + 1][j].rgbtGreen + image[i][j-1].rgbtGreen + image[i+1][j-1].rgbtGreen + image[i][j].rgbtGreen) / 4; copy[i][j].rgbtGreen = greenav; int blueav = (image[i + 1][j].rgbtBlue + image[i][j-1].rgbtBlue + image[i+1][j-1].rgbtBlue + image[i][j].rgbtBlue) / 4; copy[i][j].rgbtBlue = blueav; }
- 当
i == height -1 && j ==0时,你使用了image[i+1][j+1](即image[height][...]),同样越界,应该改为image[i-1][j+1]:
else if (i == height - 1 && j == 0) { int redav = (image[i - 1][j].rgbtRed + image[i][j+1].rgbtRed + image[i-1][j+1].rgbtRed + image[i][j].rgbtRed) / 4; copy[i][j].rgbtRed = redav; int greenav = (image[i - 1][j].rgbtGreen + image[i][j+1].rgbtGreen + image[i-1][j+1].rgbtGreen + image[i][j].rgbtGreen) / 4; copy[i][j].rgbtGreen = greenav; int blueav = (image[i - 1][j].rgbtBlue + image[i][j+1].rgbtBlue + image[i-1][j+1].rgbtBlue + image[i][j].rgbtBlue) / 4; copy[i][j].rgbtBlue = blueav; }
3. bluredge函数的蓝色通道重复计算错误
在i ==0 && j>0 && j<width-1的分支中,蓝色通道的计算重复加了image[i+1][j+1].rgbtBlue两次,漏掉了image[i+1][j-1].rgbtBlue:
// 修正后的蓝色计算 int blueav = (image[i][j].rgbtBlue + image[i][j-1].rgbtBlue + image[i+1][j-1].rgbtBlue + image[i+1][j].rgbtBlue + image[i+1][j+1].rgbtBlue + image[i][j+1].rgbtBlue) / 6;
4. 补充中间区域的模糊逻辑
你之前的代码只处理了边角和边缘像素,完全漏掉了中间区域(非边缘非边角)的像素模糊,这也是功能缺失的一部分,已在修改后的blur函数中补充。
其他优化建议
- 可以把边角、边缘、中间区域的计算逻辑合并,用双重循环遍历当前像素周围的有效像素(判断下标是否在合法范围内),统计总和和计数后求平均,这样代码会更简洁,也不容易出错。
- 计算平均值时,建议先求和再除以计数,避免整数截断误差(不过CS50的题目要求可能允许直接整除)。
内容的提问来源于stack exchange,提问作者ME Designs
相关产品推荐
相关产品推荐

