Написал программу, которая применяет фильтр Гаусса на зашумленное одноканальное изображение. Проблема в том, что на выходе оно получается несколько темнее, чем ожидалось. Не подскажете, в чем может быть проблема?
double** getGaussian(int height, int width, double sigma) {
double** filter = new double * [width];
for (size_t i = 0; i < width; ++i) {
filter[i] = new double[height];
}
double sum = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
filter[i][j] = exp(-(i * i + j * j) / (2 * sigma * sigma)) / (2 * 3.14 * sigma * sigma);
sum += filter[i][j];
}
}
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
filter[i][j] /= sum;
}
}
return filter;
}
Image GaussianBlur(Image img, double** filter, int c, int r) {
Image newimg;
newimg.cols = img.cols - c + 1;;
newimg.rows = img.rows - r + 1;;
newimg.data = new unsigned char * [newimg.rows];
for (size_t i = 0; i < newimg.rows; ++i) {
newimg.data[i] = new uchar[newimg.cols];
}
for (size_t y = 0; y < newimg.rows; y++) {
for (size_t x = 0; x < newimg.cols; x++) {
int sum = 0;
for (int h = y; h < y + r; h++) {
for (int w = x; w < x + c; w++) {
sum += filter[h - y][w - x] * img.data[h][w];
}
}
newimg.data[y][x] = sum;
}
}
for (size_t y = 0; y < c; ++y) {
delete[] filter[y];
}
delete[] filter;
return newimg;
}
double FindSigma(const Image& img) {
double mean = 0;
double sum = 0;
double count = 0;
for (size_t y = 0; y < img.rows; y++) {
for (size_t x = 0; x < img.cols; x++) {
count += 1;
sum += img.data[y][x];
}
}
mean = sum / count;
double sigma = 0;
for (size_t y = 0; y < img.rows; y++) {
for (size_t x = 0; x < img.cols; x++) {
sigma += (img.data[y][x] - mean) * (img.data[y][x] - mean);
}
}
sigma /= count;
return sigma;
}
Функция getGaussian создает массив заданного размера (height, width), в котором хранятся значения фильтра Гаусса. Формула для расчета значений такая -g(x, y) = 1 / (2 * pi * sigma ^ 2) * exp(-(x^2 + y ^2)/(2*sigma^2))
(из Википедии), где сигма - стандартное отклонение, а g(x,y) - значения в фильтре. Тип double
выбран для того, чтобы при умножении на unsigned char
(тип данных во входном изображении) не получались нули. Image - это такая структура:
struct Image {
unsigned char** data = nullptr;
size_t rows = 0;
size_t cols = 0;
};
Вызов функции происходит так
double sigma = FindSigma(image);
double** filter = getGaussian(5, 5, sigma);
Image gauss = GaussianBlur(image, filter, 5, 5);
Помогите найти ошибку, пожалуйста.
Для начала - пространственный параметр сигма ядра Гаусса не связан с вариацией элементов массива. Он выбирается таким образом, чтобы на краях ядра коэффициенты были малЫ. Для ядра 5x5 радиус 2, и сигма=1 - хороший выбор. Либо наоборот - для заданной сигмы r=2*sigma
.
Далее - ядро фильтра Гаусса - центрированное нечётного размера, наибольший коэффициент находится в центре. Таким образом, имея r=2
, получаем size=2*r+1 = 5
. Коэффициент перед экспонентой не нужен, т.к. далее идёт нормировка. А отклонения считаются от центра.
getGaussian(int r, double sigma) //r=2, sigma=1 для size=5x5
...
double sum = 0;
for (int i = 0; i <= 2*r; i++) {
for (int j = 0; j <= 2*r; j++) {
filter[i][j] = exp(-((i-r)*(i-r)+(j-r)*(j-r))/(2*sigma*sigma));
sum += filter[i][j];
}
}
...
Теперь применение - тоже к центральному элементу, если не ошибаюсь, то выглядеть может так (края я игнорировал, для них лучше сделать нормировку на сумму задействованных коэффициентов)
for (size_t y = r; y < newimg.rows - r; y++) {
for (size_t x = r; x < newimg.cols - r; x++) {
int sum = 0;
for (int h = 0; h < r; h++) {
for (int w = 0; w < r; w++) {
sum += filter[h][w] * img.data[y + h - r][x + w - r];
}
}
newimg.data[y][x] = sum;
}
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Имеется 3 табличкиЗадание, типы заданий (категории грубо, их может быть несколько к одному заданию) и связывающая их табличка
Очень странная ситуация, глупая, но не решаемая уже много часов
Всем привет! Решил переехать на Slim Framework 4Возникла проблема