cs50 pset4 过滤器 "edges"
cs50 pset4 filter "edges"
当我通过我的 edges
代码 运行 一张照片时,返回的图像全是白色,除了底部的三行像素,看起来类似于静态彩虹电视。我试过调试我的代码,但我还是想不通:
void edges(int height, int width, RGBTRIPLE image[height][width])
{
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 redx = 0;
int greenx = 0;
int bluex = 0;
int redy = 0;
int greeny = 0;
int bluey = 0;
int finalred = 0;
int finalgreen = 0;
int finalblue = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
for (int k = i - 1; k <= i + 1 && k < height && k >= 0; k++)
{
for (int m = j - 1; m <= j + 1 && m < width && m >= 0; m++)
{
if (k < i)
{
if (m < j)
{
redx += image[k][m].rgbtRed * gx[0][0];
greenx += image[k][m].rgbtGreen * gx[0][0];
bluex += image[k][m].rgbtBlue * gx[0][0];
redy += image[k][m].rgbtRed * gy[0][0];
greeny += image[k][m].rgbtGreen * gy[0][0];
bluey += image[k][m].rgbtBlue * gy[0][0];
// gx[?][0]
}
else if (m > j)
{
redx += image[k][m].rgbtRed * gx[0][2];
greenx += image[k][m].rgbtGreen * gx[0][2];
bluex += image[k][m].rgbtBlue * gx[0][2];
redy += image[k][m].rgbtRed * gy[0][2];
greeny += image[k][m].rgbtGreen * gy[0][2];
bluey += image[k][m].rgbtBlue * gy[0][2];
// gx[?][2]
}
else
{
redx += image[k][m].rgbtRed * gx[0][1];
greenx += image[k][m].rgbtGreen * gx[0][1];
bluex += image[k][m].rgbtBlue * gx[0][1];
redy += image[k][m].rgbtRed * gy[0][1];
greeny += image[k][m].rgbtGreen * gy[0][1];
bluey += image[k][m].rgbtBlue * gy[0][1];
// gx[?][1]
}
// gx[0][?]
}
else if (k > i)
{
if (m < j)
{
redx += image[k][m].rgbtRed * gx[2][0];
greenx += image[k][m].rgbtGreen * gx[2][0];
bluex += image[k][m].rgbtBlue * gx[1][0];
redy += image[k][m].rgbtRed * gy[2][0];
greeny += image[k][m].rgbtGreen * gy[2][0];
bluey += image[k][m].rgbtBlue * gy[2][0];
// gx[?][0]
}
else if (m > j)
{
redx += image[k][m].rgbtRed * gx[2][2];
greenx += image[k][m].rgbtGreen * gx[2][2];
bluex += image[k][m].rgbtBlue * gx[2][2];
redy += image[k][m].rgbtRed * gy[2][2];
greeny += image[k][m].rgbtGreen * gy[2][2];
bluey += image[k][m].rgbtBlue * gy[2][2];
// gx[?][2]
}
else
{
redx += image[k][m].rgbtRed * gx[2][1];
greenx += image[k][m].rgbtGreen * gx[2][1];
bluex += image[k][m].rgbtBlue * gx[2][1];
redy += image[k][m].rgbtRed * gy[2][1];
greeny += image[k][m].rgbtGreen * gy[2][1];
bluey += image[k][m].rgbtBlue * gy[2][1];
// gx[?][1]
}
// gx[2][?]
}
else
{
if (m < j)
{
redx += image[k][m].rgbtRed * gx[1][0];
greenx += image[k][m].rgbtGreen * gx[1][0];
bluex += image[k][m].rgbtBlue * gx[1][0];
redy += image[k][m].rgbtRed * gy[1][0];
greeny += image[k][m].rgbtGreen * gy[1][0];
bluey += image[k][m].rgbtBlue * gy[1][0];
// gx[?][0]
}
else if (m > j)
{
redx += image[k][m].rgbtRed * gx[1][2];
greenx += image[k][m].rgbtGreen * gx[1][2];
bluex += image[k][m].rgbtBlue * gx[1][2];
redy += image[k][m].rgbtRed * gy[1][2];
greeny += image[k][m].rgbtGreen * gy[1][2];
bluey += image[k][m].rgbtBlue * gy[1][2];
// gx[?][2]
}
else
{
redx += image[k][m].rgbtRed * gx[1][1];
greenx += image[k][m].rgbtGreen * gx[1][1];
bluex += image[k][m].rgbtBlue * gx[1][1];
redy += image[k][m].rgbtRed * gy[1][1];
greeny += image[k][m].rgbtGreen * gy[1][1];
bluey += image[k][m].rgbtBlue * gy[1][1];
// gx[?][1]
}
// gx[1][?]
}
}
}
finalred = (redx)^2 + (redy)^2;
finalgreen = (greenx)^2 + (greeny)^2;
finalblue = (bluex)^2 + (bluey)^2;
if (finalred > 255)
{
finalred = 255;
}
if (finalgreen > 255)
{
finalgreen = 255;
}
if (finalblue > 255)
{
finalblue = 255;
}
image[i][j].rgbtRed = finalred;
image[i][j].rgbtGreen = finalgreen;
image[i][j].rgbtBlue = finalblue;
}
}
return;
}
初始化变量
这些初始化:
int redx = 0;
int greenx = 0;
int bluex = 0;
int redy = 0;
int greeny = 0;
int bluey = 0;
出现在i
和j
的for
语句之前,但是这些变量为每个像素累加和,所以必须为每个像素初始化它们。那是在 j
上的 for
声明中以及 k
和 m
.
上的 for
声明之前
(由于在评论中指出了这一点,问题中的代码已被编辑为在更新每个像素后将零分配给这些变量。这可行,但这是一个糟糕的解决方案。只需移动定义和初始化外部两个 for
循环内的变量。)
不正确的循环条件
这条语句会失败:
for (int k = i - 1; k <= i + 1 && k < height && k >= 0; k++)
考虑当 i
为 0 时会发生什么。然后 int k = i - 1
将 k
初始化为 −1。那么 k >= 0
为假,所以测试 k <= i + 1 && k < height && k >= 0
为假,所以循环体永远不会执行,并且 i
=0 的行中的像素的 none已更新。
您需要重新考虑代码的设计方式。这显然是一种处理边角的尝试,理论上涉及对阵列外像素的计算,但还有其他解决方案。这是这个问题的重点,所以考虑并实施两个或更多解决方案将是一个很好的练习。
运算符不正确
^
用于在 (redx)^2
中尝试求幂。在 C 语言中,^
是异或运算符。在这种情况下,要对一个数求平方,只需将其自身相乘即可,如 redx*redx
。 C中有求幂运算符,但它是用于floating-point算术运算的,所以不适合做这道题,你会在另一课学习。
图像过早更新
这些行:
image[i][j].rgbtRed = finalred;
image[i][j].rgbtGreen = finalgreen;
image[i][j].rgbtBlue = finalblue;
是 i
和 j
的内部循环,因此它们会在处理每个像素时更新图像。这意味着尚未更新的像素将使用为先前更新的像素分配的新值。这是不正确的;计算新像素值时应使用原始 pre-updated 值。对此的解决方案需要使用单独的缓冲区来临时保存新值。 (一个简单的解决方案是使用一个完整的单独数组来保存新值,但还有更多 space-efficient 解决方案。)
计算未四舍五入
此代码取平方根并将其截断为整数:
finalred = sqrt((redx)^2 + (redy)^2);
但是,problem specification 表示“并且由于通道值只能采用 0 到 255 之间的整数值,因此请确保将结果值四舍五入为最接近的整数并且
代码过多
多次出现这样的代码:
if (k < i)
{
if (m < j)
{
redx += image[k][m].rgbtRed * gx[0][0];
greenx += image[k][m].rgbtGreen * gx[0][0];
bluex += image[k][m].rgbtBlue * gx[0][0];
redy += image[k][m].rgbtRed * gy[0][0];
greeny += image[k][m].rgbtGreen * gy[0][0];
bluey += image[k][m].rgbtBlue * gy[0][0];
// gx[?][0]
}
根据这些循环的结构,k
只能等于i-1
、i
或i+1
。因此,不需要使用if
语句来select索引数组的0
、1
或2
;我们可以简单地计算一下,m
也类似,然后一组代码就可以满足所有情况:
redx += image[k][m].rgbtRed * gx[k-(i-1)][m-(j-1)];
greenx += image[k][m].rgbtGreen * gx[k-(i-1)][m-(j-1)];
bluex += image[k][m].rgbtBlue * gx[k-(i-1)][m-(j-1)];
redy += image[k][m].rgbtRed * gy[k-(i-1)][m-(j-1)];
greeny += image[k][m].rgbtGreen * gy[k-(i-1)][m-(j-1)];
bluey += image[k][m].rgbtBlue * gy[k-(i-1)][m-(j-1)];
请注意,处理边角的问题仍然存在,如上所述。
不必要的初始化
这些初始化和重置是不必要的:
int finalred = 0;
int finalgreen = 0;
int finalblue = 0;
finalred = 0;
finalgreen = 0;
finalblue = 0;
相反,只需在需要的地方定义这些变量即可;变化:
finalred = sqrt((redx)^2 + (redy)^2);
finalgreen = sqrt((greenx)^2 + (greeny)^2);
finalblue = sqrt((bluex)^2 + (bluey)^2);
至:
int finalred = sqrt((redx)^2 + (redy)^2);
int finalgreen = sqrt((greenx)^2 + (greeny)^2);
int finalblue = sqrt((bluex)^2 + (bluey)^2);
仅在需要变量的地方定义变量会限制它们的范围,从而限制使用它们出错的机会。这适用于上面的 redx
和相关变量:通过在 per-pixel 代码中定义和初始化它们,它们的使用仅限于计算单个像素,因此让总和累加多个像素是错误的本来不可能做的。
当我通过我的 edges
代码 运行 一张照片时,返回的图像全是白色,除了底部的三行像素,看起来类似于静态彩虹电视。我试过调试我的代码,但我还是想不通:
void edges(int height, int width, RGBTRIPLE image[height][width])
{
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 redx = 0;
int greenx = 0;
int bluex = 0;
int redy = 0;
int greeny = 0;
int bluey = 0;
int finalred = 0;
int finalgreen = 0;
int finalblue = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
for (int k = i - 1; k <= i + 1 && k < height && k >= 0; k++)
{
for (int m = j - 1; m <= j + 1 && m < width && m >= 0; m++)
{
if (k < i)
{
if (m < j)
{
redx += image[k][m].rgbtRed * gx[0][0];
greenx += image[k][m].rgbtGreen * gx[0][0];
bluex += image[k][m].rgbtBlue * gx[0][0];
redy += image[k][m].rgbtRed * gy[0][0];
greeny += image[k][m].rgbtGreen * gy[0][0];
bluey += image[k][m].rgbtBlue * gy[0][0];
// gx[?][0]
}
else if (m > j)
{
redx += image[k][m].rgbtRed * gx[0][2];
greenx += image[k][m].rgbtGreen * gx[0][2];
bluex += image[k][m].rgbtBlue * gx[0][2];
redy += image[k][m].rgbtRed * gy[0][2];
greeny += image[k][m].rgbtGreen * gy[0][2];
bluey += image[k][m].rgbtBlue * gy[0][2];
// gx[?][2]
}
else
{
redx += image[k][m].rgbtRed * gx[0][1];
greenx += image[k][m].rgbtGreen * gx[0][1];
bluex += image[k][m].rgbtBlue * gx[0][1];
redy += image[k][m].rgbtRed * gy[0][1];
greeny += image[k][m].rgbtGreen * gy[0][1];
bluey += image[k][m].rgbtBlue * gy[0][1];
// gx[?][1]
}
// gx[0][?]
}
else if (k > i)
{
if (m < j)
{
redx += image[k][m].rgbtRed * gx[2][0];
greenx += image[k][m].rgbtGreen * gx[2][0];
bluex += image[k][m].rgbtBlue * gx[1][0];
redy += image[k][m].rgbtRed * gy[2][0];
greeny += image[k][m].rgbtGreen * gy[2][0];
bluey += image[k][m].rgbtBlue * gy[2][0];
// gx[?][0]
}
else if (m > j)
{
redx += image[k][m].rgbtRed * gx[2][2];
greenx += image[k][m].rgbtGreen * gx[2][2];
bluex += image[k][m].rgbtBlue * gx[2][2];
redy += image[k][m].rgbtRed * gy[2][2];
greeny += image[k][m].rgbtGreen * gy[2][2];
bluey += image[k][m].rgbtBlue * gy[2][2];
// gx[?][2]
}
else
{
redx += image[k][m].rgbtRed * gx[2][1];
greenx += image[k][m].rgbtGreen * gx[2][1];
bluex += image[k][m].rgbtBlue * gx[2][1];
redy += image[k][m].rgbtRed * gy[2][1];
greeny += image[k][m].rgbtGreen * gy[2][1];
bluey += image[k][m].rgbtBlue * gy[2][1];
// gx[?][1]
}
// gx[2][?]
}
else
{
if (m < j)
{
redx += image[k][m].rgbtRed * gx[1][0];
greenx += image[k][m].rgbtGreen * gx[1][0];
bluex += image[k][m].rgbtBlue * gx[1][0];
redy += image[k][m].rgbtRed * gy[1][0];
greeny += image[k][m].rgbtGreen * gy[1][0];
bluey += image[k][m].rgbtBlue * gy[1][0];
// gx[?][0]
}
else if (m > j)
{
redx += image[k][m].rgbtRed * gx[1][2];
greenx += image[k][m].rgbtGreen * gx[1][2];
bluex += image[k][m].rgbtBlue * gx[1][2];
redy += image[k][m].rgbtRed * gy[1][2];
greeny += image[k][m].rgbtGreen * gy[1][2];
bluey += image[k][m].rgbtBlue * gy[1][2];
// gx[?][2]
}
else
{
redx += image[k][m].rgbtRed * gx[1][1];
greenx += image[k][m].rgbtGreen * gx[1][1];
bluex += image[k][m].rgbtBlue * gx[1][1];
redy += image[k][m].rgbtRed * gy[1][1];
greeny += image[k][m].rgbtGreen * gy[1][1];
bluey += image[k][m].rgbtBlue * gy[1][1];
// gx[?][1]
}
// gx[1][?]
}
}
}
finalred = (redx)^2 + (redy)^2;
finalgreen = (greenx)^2 + (greeny)^2;
finalblue = (bluex)^2 + (bluey)^2;
if (finalred > 255)
{
finalred = 255;
}
if (finalgreen > 255)
{
finalgreen = 255;
}
if (finalblue > 255)
{
finalblue = 255;
}
image[i][j].rgbtRed = finalred;
image[i][j].rgbtGreen = finalgreen;
image[i][j].rgbtBlue = finalblue;
}
}
return;
}
初始化变量
这些初始化:
int redx = 0;
int greenx = 0;
int bluex = 0;
int redy = 0;
int greeny = 0;
int bluey = 0;
出现在i
和j
的for
语句之前,但是这些变量为每个像素累加和,所以必须为每个像素初始化它们。那是在 j
上的 for
声明中以及 k
和 m
.
for
声明之前
(由于在评论中指出了这一点,问题中的代码已被编辑为在更新每个像素后将零分配给这些变量。这可行,但这是一个糟糕的解决方案。只需移动定义和初始化外部两个 for
循环内的变量。)
不正确的循环条件
这条语句会失败:
for (int k = i - 1; k <= i + 1 && k < height && k >= 0; k++)
考虑当 i
为 0 时会发生什么。然后 int k = i - 1
将 k
初始化为 −1。那么 k >= 0
为假,所以测试 k <= i + 1 && k < height && k >= 0
为假,所以循环体永远不会执行,并且 i
=0 的行中的像素的 none已更新。
您需要重新考虑代码的设计方式。这显然是一种处理边角的尝试,理论上涉及对阵列外像素的计算,但还有其他解决方案。这是这个问题的重点,所以考虑并实施两个或更多解决方案将是一个很好的练习。
运算符不正确
^
用于在 (redx)^2
中尝试求幂。在 C 语言中,^
是异或运算符。在这种情况下,要对一个数求平方,只需将其自身相乘即可,如 redx*redx
。 C中有求幂运算符,但它是用于floating-point算术运算的,所以不适合做这道题,你会在另一课学习。
图像过早更新
这些行:
image[i][j].rgbtRed = finalred;
image[i][j].rgbtGreen = finalgreen;
image[i][j].rgbtBlue = finalblue;
是 i
和 j
的内部循环,因此它们会在处理每个像素时更新图像。这意味着尚未更新的像素将使用为先前更新的像素分配的新值。这是不正确的;计算新像素值时应使用原始 pre-updated 值。对此的解决方案需要使用单独的缓冲区来临时保存新值。 (一个简单的解决方案是使用一个完整的单独数组来保存新值,但还有更多 space-efficient 解决方案。)
计算未四舍五入
此代码取平方根并将其截断为整数:
finalred = sqrt((redx)^2 + (redy)^2);
但是,problem specification 表示“并且由于通道值只能采用 0 到 255 之间的整数值,因此请确保将结果值四舍五入为最接近的整数并且
代码过多
多次出现这样的代码:
if (k < i)
{
if (m < j)
{
redx += image[k][m].rgbtRed * gx[0][0];
greenx += image[k][m].rgbtGreen * gx[0][0];
bluex += image[k][m].rgbtBlue * gx[0][0];
redy += image[k][m].rgbtRed * gy[0][0];
greeny += image[k][m].rgbtGreen * gy[0][0];
bluey += image[k][m].rgbtBlue * gy[0][0];
// gx[?][0]
}
根据这些循环的结构,k
只能等于i-1
、i
或i+1
。因此,不需要使用if
语句来select索引数组的0
、1
或2
;我们可以简单地计算一下,m
也类似,然后一组代码就可以满足所有情况:
redx += image[k][m].rgbtRed * gx[k-(i-1)][m-(j-1)];
greenx += image[k][m].rgbtGreen * gx[k-(i-1)][m-(j-1)];
bluex += image[k][m].rgbtBlue * gx[k-(i-1)][m-(j-1)];
redy += image[k][m].rgbtRed * gy[k-(i-1)][m-(j-1)];
greeny += image[k][m].rgbtGreen * gy[k-(i-1)][m-(j-1)];
bluey += image[k][m].rgbtBlue * gy[k-(i-1)][m-(j-1)];
请注意,处理边角的问题仍然存在,如上所述。
不必要的初始化
这些初始化和重置是不必要的:
int finalred = 0;
int finalgreen = 0;
int finalblue = 0;
finalred = 0;
finalgreen = 0;
finalblue = 0;
相反,只需在需要的地方定义这些变量即可;变化:
finalred = sqrt((redx)^2 + (redy)^2);
finalgreen = sqrt((greenx)^2 + (greeny)^2);
finalblue = sqrt((bluex)^2 + (bluey)^2);
至:
int finalred = sqrt((redx)^2 + (redy)^2);
int finalgreen = sqrt((greenx)^2 + (greeny)^2);
int finalblue = sqrt((bluex)^2 + (bluey)^2);
仅在需要变量的地方定义变量会限制它们的范围,从而限制使用它们出错的机会。这适用于上面的 redx
和相关变量:通过在 per-pixel 代码中定义和初始化它们,它们的使用仅限于计算单个像素,因此让总和累加多个像素是错误的本来不可能做的。