TransWikia.com

gaussian kernel для сглаживания

Stack Overflow на русском Asked by Cheshire Cat on November 30, 2021

Здраствуйте, изучаю компьюторное зрение смотря курс The Ancient Secrets of Computer Vision и делаю домашки . Столкнулся со сглаживаем изображения с помощью gaussian kernel.
Преподаватель даёт формулу примерного расчета матрицы:

введите сюда описание изображения

При этом в его же видео лекции на слайде на 49:21 видно что пик функции доходит практически до 1. Но по этой же формуле видно что сама она по себе не может дать такого, ведь при сигме = 1, дробь будет примерно равна 1/6, а значит экспанента должнабыть сильно больше еденицы, но если x и y = 0, то экспанента будет равна 1. А значит функция будет примерно равна 1/6.

В тексте домашки преподаватель говорит, что нужно нормализовать матрицу. То есть сделать так чтобы сумма матрицы была равна 1. Но сумма при сигме = 1 и размерах матрицы 7*7 (рамер матрицы в домашке задаётся = сигма * 6+1 по x и по y) равна 0.999459, то есть даже нормализация не увеличит так сильно пик функции.

Ну в домашке есть тест в котором создается фильтр с сигмой = 7, который у преподавателя выглядит так:

введите сюда описание изображения

У меня же получается абсолютно чёрный квадрат, понятно по каким причинам.

В общем я явно чего-то не понимаю, помогите понять чего.

На всякий случай добалю код нормализиции и создании матрицы gaussian:

Нормализация:

//im - по факту просто структора в которой хранится колличество каналов, ширина и высота изображения. А само изображение хранится как одномерный массив float от 0 до 1.
void l1_normalize(image im)
{
    double sum = 0;
    for (int chanel = 0; chanel < im.c; chanel++)
        for (int row = 0; row < im.h; row++)
            for (int column = 0; column < im.w; column++)
            { 
                sum += get_pixel(im, column, row, chanel);
            }

    for (int chanel = 0; chanel < im.c; chanel++)
        for (int row = 0; row < im.h; row++)
            for (int column = 0; column < im.w; column++)
            {
                float pixel = get_pixel(im, column, row, chanel);
                set_pixel(im, column, row, chanel, pixel / sum);
            }            
}

Создание матрицы:

  image make_gaussian_filter(float sigma)
{
    image filter = make_image(6 * sigma + 1, 6 * sigma + 1, 1);
    for (int y = 0; y < filter.h; y++)
        for (int x = 0; x < filter.w; x++)
        {   
            //считаю экспоненту
            //в матрице 0, 0 - это верхинй левый угол, поэтому нужно сместить координаты на половину высоты и ширины картинки
            float a = pow(x - ceil(filter.w/2), 2) + pow(y - ceil(filter.h/2), 2);
            float b = 2 * pow(sigma, 2);
            float ex = exp(-(a/b));
            //считаю основную дробь
            a = 1;
            b = TWOPI * pow(sigma, 2); //TWOPI = 6.2831853
            float value = (a/b) * ex;
            set_pixel(filter, x, y, 0, value);
        }
    l1_normalize(filter);
    return filter;
}

One Answer

Максимальное значение гауссиана не достигает единицы. А вот площадь под ним (и сумма элементов дискретной матрицы) равна единице - собственно, для этого множитель перед экспонентой и введён.

Для дискретной матрицы сумма после расчёта может немного отличаться от единицы, при этом можно выполнить нормализацию, разделив на сумму. Однако пик единицы не достигнет (он тем меньше, чем больше сигма).

Если нужно отрисовать это ядро так, чтоб пик был белым - масштабируйте его, разделите на величину пика при выводе, если значения вещественные (формат image float) в диапазоне 0..1, а если целые в диапазоне 0..255, то ещё и на 255 умножьте.

Answered by MBo on November 30, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP