Open Son-Guhun opened 4 years ago
http://dev.theomader.com/gaussian-kernel-calculator/ https://en.wikipedia.org/wiki/Gaussian_blur
var GaussianKernelCalculator = { init : function() { var gaussianDistribution = function(x, mu, sigma) { var d = x - mu; var n = 1.0 / (Math.sqrt(2 * Math.PI) * sigma); return Math.exp(-d*d/(2 * sigma * sigma)) * n; }; var sampleInterval = function(f, minInclusive, maxInclusive, sampleCount) { var result = []; var stepSize = (maxInclusive - minInclusive) / (sampleCount-1); for(var s=0; s<sampleCount; ++s) { var x = minInclusive + s * stepSize; var y = f(x); result.push([x, y]); } return result; }; var integrateSimphson = function(samples) { var result = samples[0][1] + samples[samples.length-1][1]; for(var s = 1; s < samples.length-1; ++s) { var sampleWeight = (s % 2 == 0) ? 2.0 : 4.0; result += sampleWeight * samples[s][1]; } var h = (samples[samples.length-1][0] - samples[0][0]) / (samples.length-1); return result * h / 3.0; }; var roundTo = function(num, decimals) { var shift = Math.pow(10, decimals); return Math.round(num * shift) / shift; }; var updateKernel = function(sigma, kernelSize, sampleCount) { var samplesPerBin = Math.ceil(sampleCount / kernelSize); if(samplesPerBin % 2 == 0) // need an even number of intervals for simpson integration => odd number of samples ++samplesPerBin; var weightSum = 0; var kernelLeft = -Math.floor(kernelSize/2); var calcSamplesForRange = function(minInclusive, maxInclusive) { return sampleInterval( function(x) { return gaussianDistribution(x, 0, sigma); }, minInclusive, maxInclusive, samplesPerBin ); } // get samples left and right of kernel support first var outsideSamplesLeft = calcSamplesForRange(-5 * sigma, kernelLeft - 0.5); var outsideSamplesRight = calcSamplesForRange(-kernelLeft+0.5, 5 * sigma); var allSamples = [[outsideSamplesLeft, 0]]; // now sample kernel taps and calculate tap weights for(var tap=0; tap<kernelSize; ++tap) { var left = kernelLeft - 0.5 + tap; var tapSamples = calcSamplesForRange(left, left+1); var tapWeight = integrateSimphson(tapSamples); allSamples.push([tapSamples, tapWeight]); weightSum += tapWeight; } allSamples.push([outsideSamplesRight, 0]); // renormalize kernel and round to 6 decimals for(var i=0; i<allSamples.length; ++i) { allSamples[i][1] = roundTo(allSamples[i][1] / weightSum, 6); } // update kernel weights tables var weightsTable1d = document.getElementById("GaussianKernelCalculator_kernelWeights1d"); var weightsTable2d = document.getElementById("GaussianKernelCalculator_kernelWeights2d"); var tableRow = "<tr>"; for(var i=1; i<allSamples.length-1; ++i) { tableRow += "<td>" + roundTo(allSamples[i][1], 6) + "</td>"; } tableRow += "</tr>" weightsTable1d.innerHTML = tableRow; var tableData = ""; for(var i=1; i<allSamples.length-1; ++i) { tableData += "<tr>"; for(var j=1; j<allSamples.length-1; ++j) { tableData += "<td>" + roundTo(allSamples[i][1] * allSamples[j][1], 6) + "</td>"; } tableData += "</tr>" } weightsTable2d.innerHTML = tableData; // area outside kernel Support var errorField = document.getElementById("GaussianKernelCalculator_approximationError"); errorField.innerHTML = roundTo((1.0 - weightSum) * 100.0, 2) + "%"; // Create and populate the data table. var chartData = new google.visualization.DataTable(); chartData.addColumn('number','Pixel'); chartData.addColumn('number','Continuous Distribution'); chartData.addColumn('number', 'Discrete Kernel'); for(var tap = 0; tap < allSamples.length; ++tap) { var tapSamples = allSamples[tap][0]; var tapWeight = allSamples[tap][1]; for(var s=0; s<tapSamples.length; ++s) { chartData.addRow([tapSamples[s][0], tapSamples[s][1], tapWeight]); } var lastRow = tapSamples[tapSamples.length-1]; chartData.addRow([lastRow[0], lastRow[1], 0]); } // finally draw the chart var chartOptions = { 'vAxis': {title: "Kernel Weight"}, 'hAxis': {title: "Pixel"}, 'seriesType': "area", 'series': {1: {type: "line"}}, }; var chart = new google.visualization.ChartWrapper( { chartType: 'ComboChart', dataTable: chartData, options: { 'vAxis': {title: "Kernel Weight"}, 'hAxis': {title: "Pixel"}, 'seriesType': "area", 'series': {1: {type: "line"}}, }, containerId: 'GaussianKernelCalculator_distributionChart' }); chart.draw(); }; var showKernel = function(show) { document.getElementById("GaussianKernelCalculator_result").style.display = show ? 'block' : 'none'; document.getElementById("GaussianKernelCalculator_inputError").style.display = show ? 'none' : 'block'; }; var updatePage = function() { var sigma = parseFloat(document.getElementById("GaussianKernelCalculator_sigma").value); var kernelSize = parseInt(document.getElementById("GaussianKernelCalculator_kernelSize").value); var sampleCount = 1000.0; showKernel(false); // parameter validation if(sigma<=0 || isNaN(sigma)) { document.getElementById("GaussianKernelCalculator_inputError").innerHTML = "Invalid Sigma: Please enter a positive number greater than zero"; } else if(kernelSize<=0 || isNaN(kernelSize) || kernelSize%2==0 || kernelSize>999) { document.getElementById("GaussianKernelCalculator_inputError").innerHTML = "Invalid Kernel Size: Please enter an odd positive integer smaller than 999"; } else { showKernel(true); updateKernel(sigma, kernelSize, sampleCount); } }; GaussianKernelCalculator.updatePage = updatePage; }, drawPrecomputedKernel : function() { var chartDataJSON= { "containerId":"GaussianKernelCalculator_distributionChart", "dataTable": { "cols":[ {"id":"","label":"Pixel","pattern":"","type":"number","p":{}}, {"id":"","label":"Continuous Distribution","pattern":"","type":"number","p":{}}, {"id":"","label":"Discrete Kernel","pattern":"","type":"number"} ], "rows":[ {"c":[{"v":-5,"f":null},{"v":0.0000014867195147342977,"f":null},{"v":0,"f":null}]}, {"c":[{"v":-4.75,"f":null},{"v":0.000005029507288592445,"f":null},{"v":0,"f":null}]}, {"c":[{"v":-4.5,"f":null},{"v":0.000015983741106905475,"f":null},{"v":0,"f":null}]}, {"c":[{"v":-4.25,"f":null},{"v":0.00004771863654120495,"f":null},{"v":0,"f":null}]}, {"c":[{"v":-4,"f":null},{"v":0.00013383022576488537,"f":null},{"v":0,"f":null}]}, {"c":[{"v":-3.75,"f":null},{"v":0.0003525956823674454,"f":null},{"v":0,"f":null}]}, {"c":[{"v":-3.5,"f":null},{"v":0.0008726826950457602,"f":null},{"v":0,"f":null}]}, {"c":[{"v":-3.25,"f":null},{"v":0.002029048057299768,"f":null},{"v":0,"f":null}]}, {"c":[{"v":-3,"f":null},{"v":0.0044318484119380075,"f":null},{"v":0,"f":null}]}, {"c":[{"v":-2.75,"f":null},{"v":0.009093562501591053,"f":null},{"v":0,"f":null}]}, {"c":[{"v":-2.5,"f":null},{"v":0.01752830049356854,"f":null},{"v":0,"f":null}]}, {"c":[{"v":-2.5,"f":null},{"v":0.01752830049356854,"f":null},{"v":0,"f":null}]}, {"c":[{"v":-2.5,"f":null},{"v":0.01752830049356854,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":-2.4,"f":null},{"v":0.0223945302948429,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":-2.3,"f":null},{"v":0.028327037741601186,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":-2.2,"f":null},{"v":0.035474592846231424,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":-2.1,"f":null},{"v":0.04398359598042719,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":-2,"f":null},{"v":0.05399096651318806,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":-1.9,"f":null},{"v":0.0656158147746766,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":-1.7999999999999998,"f":null},{"v":0.07895015830089418,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":-1.7,"f":null},{"v":0.09404907737688695,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":-1.6,"f":null},{"v":0.11092083467945554,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":-1.5,"f":null},{"v":0.12951759566589174,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":-1.5,"f":null},{"v":0.12951759566589174,"f":null},{"v":0,"f":null}]}, {"c":[{"v":-1.5,"f":null},{"v":0.12951759566589174,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":-1.4,"f":null},{"v":0.14972746563574488,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":-1.3,"f":null},{"v":0.17136859204780736,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":-1.2,"f":null},{"v":0.19418605498321295,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":-1.1,"f":null},{"v":0.21785217703255053,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":-1,"f":null},{"v":0.24197072451914337,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":-0.8999999999999999,"f":null},{"v":0.26608524989875487,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":-0.7999999999999999,"f":null},{"v":0.2896915527614828,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":-0.7,"f":null},{"v":0.31225393336676127,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":-0.6,"f":null},{"v":0.33322460289179967,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":-0.5,"f":null},{"v":0.3520653267642995,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":-0.5,"f":null},{"v":0.3520653267642995,"f":null},{"v":0,"f":null}]}, {"c":[{"v":-0.5,"f":null},{"v":0.3520653267642995,"f":null},{"v":0.387741,"f":null}]}, {"c":[{"v":-0.4,"f":null},{"v":0.36827014030332333,"f":null},{"v":0.387741,"f":null}]}, {"c":[{"v":-0.3,"f":null},{"v":0.38138781546052414,"f":null},{"v":0.387741,"f":null}]}, {"c":[{"v":-0.19999999999999996,"f":null},{"v":0.39104269397545594,"f":null},{"v":0.387741,"f":null}]}, {"c":[{"v":-0.09999999999999998,"f":null},{"v":0.3969525474770118,"f":null},{"v":0.387741,"f":null}]}, {"c":[{"v":0,"f":null},{"v":0.3989422804014327,"f":null},{"v":0.387741,"f":null}]}, {"c":[{"v":0.10000000000000009,"f":null},{"v":0.3969525474770118,"f":null},{"v":0.387741,"f":null}]}, {"c":[{"v":0.20000000000000007,"f":null},{"v":0.3910426939754559,"f":null},{"v":0.387741,"f":null}]}, {"c":[{"v":0.30000000000000004,"f":null},{"v":0.3813878154605241,"f":null},{"v":0.387741,"f":null}]}, {"c":[{"v":0.4,"f":null},{"v":0.36827014030332333,"f":null},{"v":0.387741,"f":null}]}, {"c":[{"v":0.5,"f":null},{"v":0.3520653267642995,"f":null},{"v":0.387741,"f":null}]}, {"c":[{"v":0.5,"f":null},{"v":0.3520653267642995,"f":null},{"v":0,"f":null}]}, {"c":[{"v":0.5,"f":null},{"v":0.3520653267642995,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":0.6,"f":null},{"v":0.33322460289179967,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":0.7,"f":null},{"v":0.31225393336676127,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":0.8,"f":null},{"v":0.28969155276148273,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":0.9,"f":null},{"v":0.2660852498987548,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":1,"f":null},{"v":0.24197072451914337,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":1.1,"f":null},{"v":0.21785217703255053,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":1.2000000000000002,"f":null},{"v":0.19418605498321292,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":1.3,"f":null},{"v":0.17136859204780736,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":1.4,"f":null},{"v":0.14972746563574488,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":1.5,"f":null},{"v":0.12951759566589174,"f":null},{"v":0.24477,"f":null}]}, {"c":[{"v":1.5,"f":null},{"v":0.12951759566589174,"f":null},{"v":0,"f":null}]}, {"c":[{"v":1.5,"f":null},{"v":0.12951759566589174,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":1.6,"f":null},{"v":0.11092083467945554,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":1.7,"f":null},{"v":0.09404907737688695,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":1.8,"f":null},{"v":0.07895015830089415,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":1.9,"f":null},{"v":0.0656158147746766,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":2,"f":null},{"v":0.05399096651318806,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":2.1,"f":null},{"v":0.04398359598042719,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":2.2,"f":null},{"v":0.035474592846231424,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":2.3,"f":null},{"v":0.028327037741601186,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":2.4,"f":null},{"v":0.0223945302948429,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":2.5,"f":null},{"v":0.01752830049356854,"f":null},{"v":0.061359,"f":null}]}, {"c":[{"v":2.5,"f":null},{"v":0.01752830049356854,"f":null},{"v":0,"f":null}]}, {"c":[{"v":2.5,"f":null},{"v":0.01752830049356854,"f":null},{"v":0,"f":null}]}, {"c":[{"v":2.75,"f":null},{"v":0.009093562501591053,"f":null},{"v":0,"f":null}]}, {"c":[{"v":3,"f":null},{"v":0.0044318484119380075,"f":null},{"v":0,"f":null}]}, {"c":[{"v":3.25,"f":null},{"v":0.002029048057299768,"f":null},{"v":0,"f":null}]}, {"c":[{"v":3.5,"f":null},{"v":0.0008726826950457602,"f":null},{"v":0,"f":null}]}, {"c":[{"v":3.75,"f":null},{"v":0.0003525956823674454,"f":null},{"v":0,"f":null}]}, {"c":[{"v":4,"f":null},{"v":0.00013383022576488537,"f":null},{"v":0,"f":null}]}, {"c":[{"v":4.25,"f":null},{"v":0.00004771863654120495,"f":null},{"v":0,"f":null}]}, {"c":[{"v":4.5,"f":null},{"v":0.000015983741106905475,"f":null},{"v":0,"f":null}]}, {"c":[{"v":4.75,"f":null},{"v":0.000005029507288592445,"f":null},{"v":0,"f":null}]}, {"c":[{"v":5,"f":null},{"v":0.0000014867195147342977,"f":null},{"v":0,"f":null}]}, {"c":[{"v":5,"f":null},{"v":0.0000014867195147342977,"f":null},{"v":0,"f":null}]} ], "p":null }, "options":{ "vAxis":{"title":"Kernel Weight"}, "hAxis":{"title":"Pixel"}, "seriesType":"area", "series":{"1":{"type":"line"}} }, "state":{}, "isDefaultVisualization":true, "chartType":"ComboChart" }; var chart = new google.visualization.ChartWrapper(chartDataJSON); chart.draw(); } }; google.load('visualization', '1', {packages: ['corechart']}); google.setOnLoadCallback(function() { GaussianKernelCalculator.init(); // draw precalculated kernel to improve page loading times GaussianKernelCalculator.drawPrecomputedKernel(); });
http://dev.theomader.com/gaussian-kernel-calculator/ https://en.wikipedia.org/wiki/Gaussian_blur