[英]cs50 pset4 filter “edges”
当我通过edges
代码运行照片时,图像返回全白色,除了底部的三行像素,看起来类似于 Rainbow tv static。 我试图调试我的代码,但我仍然无法弄清楚:
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 已更新。
您需要重新考虑代码的设计方式。 这显然是一种处理边缘和角落的尝试,这在理论上涉及使用阵列外的像素进行计算,但还有其他解决方案。 这是这个问题的重点,因此考虑并实施两个或多个解决方案将是一个很好的练习。
^
用于尝试在(redx)^2
中求幂。 在 C 中, ^
是 XOR 运算符。 在这种情况下,要对一个数字求平方,只需将其自身相乘,就像redx*redx
。 C中有一个求幂运算符,但它是用于浮点运算的,所以不适合这个问题,你将在另一课中学习。
这些行:
image[i][j].rgbtRed = finalred;
image[i][j].rgbtGreen = finalgreen;
image[i][j].rgbtBlue = finalblue;
在i
和j
上的循环内,因此它们会在处理每个像素时更新图像。 这意味着尚未更新的像素将使用为先前更新的像素分配的新值。 这是不正确的; 在计算新像素的值时,应使用原始更新前的值。 对此的解决方案需要使用单独的缓冲区来临时保存新值。 (一个简单的解决方案是使用一个完整的单独数组来保存新值,但还有更节省空间的解决方案。)
此代码取平方根并将其截断为 integer:
finalred = sqrt((redx)^2 + (redy)^2);
但是,问题规范说“并且由于通道值只能采用从 0 到 255 的 integer 值,因此请确保将结果值四舍五入到最接近的 integer 和
像这样的代码多次出现:
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
。 因此,没有必要对 arrays 的 select 索引0
、 1
或2
使用if
语句; 我们可以简单地计算它,对于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);
在需要的地方定义变量会限制他们的 scope,这限制了他们犯错的机会。 这适用于上面的redx
和相关变量:通过在每像素代码中定义和初始化它们,它们的使用仅限于计算单个像素,因此让总和累积在多个像素上的错误是不可能犯的.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.