Двусторонний фильтр алгоритм - PullRequest
3 голосов
/ 22 сентября 2011

Я пытаюсь реализовать простой двусторонний фильтр в JavaScript.Это то, что я до сих пор придумал:

// For each pixel
for (var y = kernelSize; y < height-kernelSize; y++) {
    for (var x = kernelSize; x < width-kernelSize; x++) {
        var pixel = (y*width + x)*4;
        var sumWeight = 0;
        outputData[pixel] = 0;
        outputData[pixel+1] = 0;
        outputData[pixel+2] = 0;
        outputData[pixel+3] = inputData[pixel+3];

        // For each neighbouring pixel
        for(var i=-kernelSize; i<=kernelSize; i++) {
            for(var j=-kernelSize; j<=kernelSize; j++) {
                var kernel = ((y+i)*width+x+j)*4;
                var dist = Math.sqrt(i*i+j*j);
                var colourDist = Math.sqrt((inputData[kernel]-inputData[pixel])*(inputData[kernel]-inputData[pixel])+
                        (inputData[kernel+1]-inputData[pixel+1])*(inputData[kernel+1]-inputData[pixel+1])+
                        (inputData[kernel+2]-inputData[pixel+2])*(inputData[kernel+2]-inputData[pixel+2]));
                var curWeight = 1/(Math.exp(dist*dist/72)*Math.exp(colourDist*colourDist*8));
                sumWeight += curWeight;
                outputData[pixel] += curWeight*inputData[pixel];
                outputData[pixel+1] += curWeight*inputData[pixel+1];
                outputData[pixel+2] += curWeight*inputData[pixel+2];
            }
        }

        outputData[pixel] /= sumWeight;
        outputData[pixel+1] /= sumWeight;
        outputData[pixel+2] /= sumWeight;
    }
}

inputData от объекта холста html5 и имеет форму rgba.Мои изображения либо появляются без изменений, либо с пятнами черного по краям, в зависимости от того, как я изменяю эту формулу:

var curWeight = 1/(Math.exp(dist*dist/72)*Math.exp(colourDist*colourDist*8));

К сожалению, я все еще новичок в алгоритмах html / javascript и изображений, а также в моем поискепришли без ответов.Я предполагаю, что с вычислением curWeight что-то не так.Что я здесь не так делаю?Должен ли я сначала преобразовать входное изображение в CIElab / hsv?

Ответы [ 3 ]

2 голосов
/ 22 сентября 2011

Я не эксперт по Javasript: значения RGB 0..255? Если это так, Math.exp(colourDist*colourDist*8) даст чрезвычайно большие значения - вы, вероятно, захотите масштабировать colourDist до диапазона [0..1].

Кстати: почему вы вычисляете sqrt из dist и colourDist, если впоследствии вам нужно только квадрат расстояния?

1 голос
/ 22 сентября 2011

Прежде всего, ваши изображения становятся черными / странными по краям, потому что вы не фильтруете края.Короткий взгляд на ваш код покажет, что вы начинаете с (kernelSize, kernelSize) и заканчиваете (width-kernelSize, height-kernelSize) - это означает, что вы фильтруете только меньший прямоугольник внутри изображения, где у вас есть запас по kernelSize.каждая сторона, которая нефильтрована.Не зная ваш javscript / html5, я бы предположил, что ваш массив outputData инициализируется нулями (что означает черный), а затем, не касаясь их, оставит их черными.Посмотрите мою ссылку в комментарии к вашему сообщению, чтобы узнать код, который обрабатывает края.

Кроме этого, следуйте ответу @ nikie - вы, вероятно, хотите убедиться, что цветовое расстояние ограничено диапазоном [0,1] - вы можете сделать это, добавив строку colourDist = colourDist / (MAX_COMP * Math,sqrt(3)) (непосредственно после первой строки для ее вычисления).где MAX_COMP - максимальное значение, которое может иметь компонент цвета в изображении (обычно 255)

0 голосов
/ 23 сентября 2011

Я нашел ошибку в коде. Проблема была в том, что я добавлял каждый пиксель к себе, а не к соседям. Я оставлю здесь исправленный код на случай, если кому-то понадобится алгоритм двустороннего фильтра.

outputData[pixel] += curWeight*inputData[kernel];
outputData[pixel+1] += curWeight*inputData[kernel+1];
outputData[pixel+2] += curWeight*inputData[kernel+2];
...