CS50 Week4 Filter模块:Blur与Edges函数计算结果异常求助
图像模糊与边缘检测代码缺陷排查
模糊(Blur)实现要求
- 实现盒式模糊(box blur)效果:每个像素的新颜色值为其3×3邻域内(含自身)所有像素对应颜色值的平均值
- 边缘/角落像素仅取有效邻域内的像素计算平均
边缘检测(Edges)实现要求
- 采用Sobel算子:对每个像素的RGB通道分别计算Gx、Gy加权和,再通过√(Gx²+Gy²)得到最终值
- 结果需取整并限制在0-255范围内
- 图像边缘外视为黑色像素(RGB值为0)
问题描述
代码无语法错误,但Blur和Edges函数计算结果不符合预期,无法定位具体问题,请求排查代码缺陷。
原代码
void calculateAverage(int height, int width, RGBTRIPLE image[height][width], int i, int j) { int sumR = 0; int sumG = 0; int sumB = 0; int count = 0; for (int row = i - 1; row <= i + 1; row++) { for (int col = j - 1; col <= j + 1; col++) { // Check if the indices are within bounds if (row >= 0 && row < height && col >= 0 && col < width) { sumR += image[row][col].rgbtRed; sumG += image[row][col].rgbtGreen; sumB += image[row][col].rgbtBlue; count++; } } } // Avoid division by zero if (count > 0) { image[i][j].rgbtRed = sumR / count; image[i][j].rgbtGreen = sumG / count; image[i][j].rgbtBlue = sumB / count; } } // Blur image void blur(int height, int width, RGBTRIPLE image[height][width]) { for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { calculateAverage(height, width, image, i, j); } } return; } int gxgy(int narray[3][3]) { int gx[][3] = { {-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}}; int gxsum = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { gxsum += narray[i][j] * gx[i][j]; } } int gy[][3] = { {-1, -2, -1}, {0, 0, 0}, {1, 2, 1}}; int gysum = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { gysum += narray[i][j] * gy[i][j]; } } double gradientMagnitude = sqrt(pow(gxsum, 2) + pow(gysum, 2)); int result = gradientMagnitude + 0.5; return (result > 255)? 255 : result; } void edgedetection(int height, int width, RGBTRIPLE image[height][width], int i, int j) { int garry[3][3]; int rarry[3][3]; int barry[3][3]; for (int row = i - 1, ni = 0; row <= i + 1; row++, ni++) { for (int col = j - 1, nj = 0; col <= j + 1; col++, nj++) { // Check if the neighbor is within bounds if (row >= 0 && row < height && col >= 0 && col < width) { garry[ni][nj] = image[row][col].rgbtRed; rarry[ni][nj] = image[row][col].rgbtGreen; barry[ni][nj] = image[row][col].rgbtBlue; } else { garry[ni][nj] = 0; rarry[ni][nj] = 0; barry[ni][nj] = 0; } } } image[i][j].rgbtRed = gxgy(rarry); image[i][j].rgbtGreen = gxgy(garry); image[i][j].rgbtBlue = gxgy(barry); } // Detect edges void edges(int height, int width, RGBTRIPLE image[height][width]) { for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { edgedetection(height, width, image, i, j); } } return; }
代码缺陷排查与修复
Blur函数核心问题
直接修改原图像导致计算污染:遍历计算模糊值时,直接修改了原图像的像素数据。后续像素计算会使用已被修改的像素值(而非原始图像数据),导致模糊结果严重偏差。
修复方案:先创建原图像的副本,所有计算基于副本数据,最后将结果写回原图像。
Edges函数核心问题
- 通道赋值颠倒:
edgedetection函数中,将红色通道值赋值给了绿色通道数组,绿色通道值赋值给了红色通道数组,导致RGB通道的Sobel计算完全错误。 - 同样存在原图像污染问题:计算边缘时直接修改原图像,后续像素使用已修改的数据计算,结果失真。
其他细节优化
gxgy函数中,用整数乘法替代pow函数计算平方,避免不必要的浮点数开销与精度问题;同时用long long存储平方结果,防止int溢出。
修正后的代码
修正后的Blur函数
// Blur image 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++) { copy[i][j] = image[i][j]; } } for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int sumR = 0; int sumG = 0; int sumB = 0; int count = 0; for (int row = i - 1; row <= i + 1; row++) { for (int col = j - 1; col <= j + 1; col++) { if (row >= 0 && row < height && col >= 0 && col < width) { sumR += copy[row][col].rgbtRed; sumG += copy[row][col].rgbtGreen; sumB += copy[row][col].rgbtBlue; count++; } } } image[i][j].rgbtRed = sumR / count; image[i][j].rgbtGreen = sumG / count; image[i][j].rgbtBlue = sumB / count; } } return; }
修正后的Edges函数
// Detect edges void edges(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++) { copy[i][j] = image[i][j]; } } for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int rarry[3][3]; int garry[3][3]; int barry[3][3]; for (int row = i - 1, ni = 0; row <= i + 1; row++, ni++) { for (int col = j - 1, nj = 0; col <= j + 1; col++, nj++) { if (row >= 0 && row < height && col >= 0 && col < width) { rarry[ni][nj] = copy[row][col].rgbtRed; garry[ni][nj] = copy[row][col].rgbtGreen; barry[ni][nj] = copy[row][col].rgbtBlue; } else { rarry[ni][nj] = 0; garry[ni][nj] = 0; barry[ni][nj] = 0; } } } image[i][j].rgbtRed = gxgy(rarry); image[i][j].rgbtGreen = gxgy(garry); image[i][j].rgbtBlue = gxgy(barry); } } return; }
优化后的gxgy函数
int gxgy(int narray[3][3]) { int gx[3][3] = { {-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}}; int gxsum = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { gxsum += narray[i][j] * gx[i][j]; } } int gy[3][3] = { {-1, -2, -1}, {0, 0, 0}, {1, 2, 1}}; int gysum = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { gysum += narray[i][j] * gy[i][j]; } } // 用long long避免平方后int溢出 long long gx_sq = (long long)gxsum * gxsum; long long gy_sq = (long long)gysum * gysum; double gradientMagnitude = sqrt(gx_sq + gy_sq); int result = (int)(gradientMagnitude + 0.5); return (result > 255) ? 255 : result; }
内容的提问来源于stack exchange,提问作者JW Ngiam
相关产品推荐
相关产品推荐

