注意average*
变量是未初始化的,所以当你对它们求和时,你就得到了 UB。它们需要预设为 0,当然是在一开始,但可能是在每个主循环之前。
此外,除了其他人注意到的其他问题之外,您可能还需要执行以下操作饱和 math.
那是因为为了rgbt*
(e.g. rgbtRed
) is a byte,因此该值可能会被错误地裁剪。
你正在做:
image[i][j].rgbtRed = round((float)averageRed / 6);
这可以重写为:
averageRed = round((float)averageRed / 6);
image[i][j].rgbtRed = averageRed;
但是,如果(例如)averageRed
是 256,那么rgbtRed
最终结果为 1 [因为分配给image
是[有效地]:
image[i][j].rgbtRed = averageRed & 0xFF;
因此,您存储的不是鲜红色,而是接近黑色。最终需要为 255,即“饱和”最大颜色值。
因此,要解决这个问题[或只是为了防止它],请执行以下操作:
averageRed = round((float)averageRed / 6);
if (averageRed > 255)
averageRed = 255;
image[i][j].rgbtRed = averageRed;
Edit:经过进一步思考,只有在右侧的情况下才需要执行此操作can超过 255,但我[现在]不确定是否可以。要检查这一点,您可以添加(例如):
if (averageRed > 255) {
fprintf(stderr,"value overflow\n");
exit(1);
}
你可以把它包装在一个#ifdef
,进行测试,如果不触发,可以稍后将其删除。
UPDATE:
这个问题听起来可能很愚蠢,但是这个值怎么可能达到 256呢?即使每个像素都是白色,没有一个值可以达到 256 或者我的错误在哪里? (1 白色 Px: 255 255 255 -> 10 白色 Px: 2550 2550 2550 / 10 --> .....
是的,根据我上面的“编辑:”,可能不会。我最近回答了一个类似的问题,其中的价值could超过255。
但是,您的运行时错误表明该值does超过一个字节的容量(即unsigned char
).
这可能是由于未初始化的 sum 变量造成的。
但是,也有它is因为总和/平均值变量是not在循环开始时被重置。你never重置它们,让它们继续成长。
在完成每个 3x3 卷积核后(即存储每个输出像素后),需要重置它们。
而且,我不认为你的for (n = j; n <= 1; n++)
循环是正确的。您正在混淆绝对坐标值(来自j
)和坐标偏移。
你可能想要这样的东西:
for (m = -1; m <= 1; m++) {
for (n = -1; n <= 1; n++) {
averageRed += image[i + m][j + n].rgbtRed;
}
}
更新#2:
使用一些额外的限制变量来拥有一组循环可能会更容易。
此外,在每个像素的基础上,使用浮点(即round
) 可slow。虽然我没有这样做,但它可以很容易地用整数数学代替。
此外,使用更具描述性的名称而不是i, j, m, n
可以帮助使代码更容易理解和维护。
不管怎样,这是你的函数的一个稍微重构的版本,它更简单一些:
#include <math.h>
#if 1
typedef struct {
unsigned char rgbtRed;
unsigned char rgbtGreen;
unsigned char rgbtBlue;
} __attribute__((__packed__)) RGBTRIPLE;
#endif
// Blur image
void
blur(int height, int width,
RGBTRIPLE image[height][width],
RGBTRIPLE imgout[height][width])
{
int wid = width - 1;
int hgt = height - 1;
RGBTRIPLE *pixel;
// For each row..
for (int ycur = 0; ycur <= hgt; ++ycur) {
int ylo = (ycur == 0) ? 0 : -1;
int yhi = (ycur == hgt) ? 0 : 1;
// ..and then for each pixel in that row...
for (int xcur = 0; xcur <= wid; ++xcur) {
int xlo = (xcur == 0) ? 0 : -1;
int xhi = (xcur == wid) ? 0 : 1;
int avgRed = 0;
int avgGreen = 0;
int avgBlue = 0;
for (int yoff = ylo; yoff <= yhi; ++yoff) {
for (int xoff = xlo; xoff <= xhi; ++xoff) {
pixel = &image[ycur + yoff][xcur + xoff];
avgRed += pixel->rgbtRed;
avgGreen += pixel->rgbtGreen;
avgBlue += pixel->rgbtBlue;
}
}
int tot = ((yhi - ylo) + 1) * ((xhi - xlo) + 1);
pixel = &imgout[ycur][xcur];
pixel->rgbtRed = roundf((float) avgRed / tot);
pixel->rgbtGreen = roundf((float) avgGreen / tot);
pixel->rgbtBlue = roundf((float) avgBlue / tot);
}
}
}