Обратите внимание, что переменные average*
являются неинициализированными , поэтому, когда вы суммируете их, у вас есть UB. Их нужно предварительно установить на 0, конечно, вначале, но, возможно, перед каждым основным l oop.
Кроме того, помимо других ваших проблем, отмеченных другими, вам может потребоваться сделать насыщенность математика.
Это потому, что для rgbt*
(например, rgbtRed
) это байт , поэтому значение может быть обрезано неправильно.
Вы делаете:
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;
Изменить: При дальнейшем размышлении вам нужно сделать это только в том случае, если правая сторона может превышать 255, но я [сейчас] не уверен, что это возможно. Чтобы проверить это, вы можете добавить (например):
if (averageRed > 255) {
fprintf(stderr,"value overflow\n");
exit(1);
}
Вы можете обернуть это в #ifdef
, провести тесты, и, если он не сработает, вы можете удалить его позже.
ОБНОВЛЕНИЕ:
Каким бы глупым ни казался вопрос, но как это значение может достигнуть 256? Даже если каждый пиксель белый, ни одно из значений не может достигнуть 256 или в чем моя ошибка? (1 белый Px: 255 255 255 -> 10 белый Px: 2550 2550 2550/10 -> .....
Да, согласно моему "Edit:" выше, это может не быть. Я недавно ответил на аналогичный вопрос, где значение могло превышать 255.
Но ваша ошибка времени выполнения показывает, что значение действительно превышает емкость байта (т.е. unsigned char
).
Вероятно, это из-за неинициализированных переменных суммы.
Но также равно , потому что переменные суммы / среднего не сбрасываются в начале al oop. Вы никогда не сбрасываете их, поэтому они просто продолжают расти и расти.
Их нужно сбрасывать после завершения каждого ядра свертки 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;
}
}
UPDATE # 2:
Может быть проще Используйте один набор циклов, используя некоторые дополнительные ограничивающие переменные.
Кроме того, для каждого пикселя использование с плавающей запятой (например, round
) может быть медленным . Хотя я этого не делал, его достаточно легко заменить целочисленной математикой.
Кроме того, использование более описательных имен вместо 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);
}
}
}