CS50 Week4 Filter(简易版):blur与sepia函数测试未通过求助
CS50 Week4 Filter(Less Comfortable)问题排查
问题描述
完成Filter的四个函数实现后,遇到以下问题:
- blur函数仅通过边角像素测试,中间像素测试未通过;
- sepia函数仅通过简单33图像测试,复杂33及4*4图像测试未通过,部分测试值差异仅为1,部分差异高达100。
原实现代码
#include "helpers.h" #include "math.h" // Convert image to grayscale void grayscale(int height, int width, RGBTRIPLE image[height][width]) { for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { image[i][j].rgbtGreen = round((image[i][j].rgbtGreen + image[i][j].rgbtBlue + image[i][j].rgbtRed) / 3.0); image[i][j].rgbtBlue = image[i][j].rgbtGreen; image[i][j].rgbtRed = image[i][j].rgbtGreen; } } return; } // Convert image to sepia void sepia(int height, int width, RGBTRIPLE image[height][width]) { for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int sepiaRed = round(.393 * image[i][j].rgbtRed + .769 * image[i][j].rgbtGreen + .189 * image[i][j].rgbtBlue); int sepiaGreen = round(.349 * image[i][j].rgbtRed + .686 * image[i][j].rgbtGreen + .168 * image[i][j].rgbtBlue); int sepiaBlue = round(.272 * image[i][j].rgbtRed + .534 * image[i][j].rgbtGreen + .131 * image[i][j].rgbtBlue); image[i][j].rgbtGreen = sepiaGreen; if (image[i][j].rgbtGreen > 255) { image[i][j].rgbtGreen = 255; } image[i][j].rgbtBlue = sepiaBlue; if (image[i][j].rgbtBlue > 255) { image[i][j].rgbtBlue = 255; } image[i][j].rgbtRed = sepiaRed; if (image[i][j].rgbtRed > 255) { image[i][j].rgbtRed = 255; } } } return; } // Reflect image horizontally void reflect(int height, int width, RGBTRIPLE image[height][width]) { for (int i = 0; i < height; i++) { for (int j = 0; j < (width / 2); j++) { RGBTRIPLE temp = image[i][j]; image[i][j] = image[i][width - j - 1]; image[i][width - j - 1] = temp; } } return; } // Blur image void blur(int height, int width, RGBTRIPLE image[height][width]) { RGBTRIPLE copy[height][width]; int blue = 0; int red = 0; int green = 0; int counter = 0; 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++) { blue = 0; red = 0; green = 0; counter = 0; for (int s = i - 1; s < i + 2; s++) { for (int m = j - 1; m < j + 2; m++) { if (s < 0 || m < 0 || s > height - 1 || m > width - 1) { continue; } else { blue += copy[s][m].rgbtBlue; green += copy[s][m].rgbtGreen; red += copy[s][m].rgbtRed; counter++; } } } image [i][j].rgbtBlue = round(blue / counter); image [i][j].rgbtGreen = round(green / counter); image [i][j].rgbtRed = round(red / counter); } } return; }
问题分析与修正
1. Sepia函数问题
核心错误:rgbtRed/rgbtGreen/rgbtBlue属于unsigned char类型(取值范围0-255),当计算出的sepia值超过255时,直接赋值会触发溢出截断,此时再判断是否大于255已经无效。比如sepiaGreen=300,赋值给unsigned char后会被截断为300-256=44,后续判断44>255不成立,无法修正为255,这就是部分测试值差异极大的原因。
修正方案:先判断sepia值是否超出范围,再赋值给图像通道:
// Convert image to sepia void sepia(int height, int width, RGBTRIPLE image[height][width]) { for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int sepiaRed = round(.393 * image[i][j].rgbtRed + .769 * image[i][j].rgbtGreen + .189 * image[i][j].rgbtBlue); int sepiaGreen = round(.349 * image[i][j].rgbtRed + .686 * image[i][j].rgbtGreen + .168 * image[i][j].rgbtBlue); int sepiaBlue = round(.272 * image[i][j].rgbtRed + .534 * image[i][j].rgbtGreen + .131 * image[i][j].rgbtBlue); // 先截断超出范围的值,再赋值 image[i][j].rgbtRed = sepiaRed > 255 ? 255 : sepiaRed; image[i][j].rgbtGreen = sepiaGreen > 255 ? 255 : sepiaGreen; image[i][j].rgbtBlue = sepiaBlue > 255 ? 255 : sepiaBlue; } } return; }
2. Blur函数问题
核心错误:blue/green/red和counter都是整数类型,blue / counter执行的是整数除法(直接截断小数部分),之后调用round()完全无效。比如blue=5、counter=2,整数除法得到2,round(2)还是2,但正确结果应该是round(5.0/2)=3,这导致中间像素的模糊计算结果错误。
修正方案:将除法运算转换为浮点数除法后再取整:
// Blur image void blur(int height, int width, RGBTRIPLE image[height][width]) { RGBTRIPLE copy[height][width]; int blue = 0; int red = 0; int green = 0; int counter = 0; 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++) { blue = 0; red = 0; green = 0; counter = 0; for (int s = i - 1; s < i + 2; s++) { for (int m = j - 1; m < j + 2; m++) { if (s < 0 || m < 0 || s > height - 1 || m > width - 1) { continue; } else { blue += copy[s][m].rgbtBlue; green += copy[s][m].rgbtGreen; red += copy[s][m].rgbtRed; counter++; } } } // 转换为浮点数除法后再取整 image[i][j].rgbtBlue = round((float)blue / counter); image[i][j].rgbtGreen = round((float)green / counter); image[i][j].rgbtRed = round((float)red / counter); } } return; }
内容的提问来源于stack exchange,提问作者joan
相关产品推荐
相关产品推荐

