Last active
April 17, 2018 00:03
-
-
Save nick-thompson/aad8830d887d14fa5a97ee11fa37a0fc to your computer and use it in GitHub Desktop.
Some sketchwork on gaussian blur processing on a simple matrix. Kernel generation and convolution. Original work: https://jsfiddle.net/2e9o35xc/53/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** Calculate and return the euclidean distance between two points. */ | |
function hypot(xi, yi, xf, yf) { | |
return Math.sqrt(Math.pow(xi - xf, 2) + Math.pow(yi - yf, 2)); | |
} | |
/** Generates an identity matrix of size (dim x dim). */ | |
function eye(dim) { | |
var mat = new Array(dim * dim); | |
for (var i = 0; i < dim; i++) { | |
for (var j = 0; j < dim; j++) { | |
mat[i * dim + j] = (j == i) ? 1.0 : 0.0; | |
} | |
} | |
return mat; | |
} | |
/** Generates a Gaussian Blur kernel for matrix processing. | |
@param dim Length of one side of the kernel (Must be odd). | |
@param sigma Standard deviation of the gaussian function. | |
@returns A 1D array holding the resulting (dim x dim) kernel. | |
*/ | |
function buildKernel(dim, sigma) { | |
var kernel = []; | |
var center = (dim - 1) / 2; | |
for (var i = 0; i < dim; i++) { | |
for (var j = 0; j < dim; j++) { | |
var dist = hypot(i, j, center, center); | |
var a = (1 / Math.sqrt(Math.PI * 2 * sigma * sigma)); | |
var samp = a * Math.exp(-1 * (Math.pow(dist, 2) / (2 * sigma * sigma))); | |
kernel.push(samp); | |
} | |
} | |
return normalize(kernel); | |
} | |
/** Returns a normalized array such that the sum of all elements is 1.0 */ | |
function normalize(arr) { | |
let sum = 0.0; | |
for (let i = 0; i < arr.length; i++) { | |
sum += arr[i]; | |
} | |
for (let i = 0; i < arr.length; i++) { | |
arr[i] = arr[i] / sum; | |
} | |
return arr; | |
} | |
/** Mutates and returns an array with normalized column sums. */ | |
function markovNormalize(arr) { | |
let dim = +Math.sqrt(arr); | |
for (let j = 0; j < dim; j++) { | |
let sum = 0.0; | |
for (let i = 0; i < dim; i++) { | |
sum += arr[i * dim + j]; | |
} | |
for (let i = 0; i < dim; i++) { | |
arr[i * dim + j] = arr[i * dim + j] / sum; | |
} | |
} | |
return arr; | |
} | |
function scalarMultiply(arr, s) { | |
for (let i = 0; i < arr.length; i++) { | |
arr[i] = Math.floor(arr[i] * s); | |
} | |
return arr; | |
} | |
/** Convolves a matrix with a given kernel. */ | |
function convolve(mat, kernel) { | |
var matDim = Math.sqrt(mat.length); | |
var kernDim = Math.sqrt(kernel.length); | |
var out = new Array(mat.length); | |
// Center of the convolution kernel | |
var kc = +((kernDim - 1) / 2); | |
for (var i = 0; i < matDim; i++) { | |
for (var j = 0; j < matDim; j++) { | |
var acc = 0; | |
for (var ki = 0; ki < kernDim; ki++) { | |
for (var kj = 0; kj < kernDim; kj++) { | |
var ix = i - kc + ki; | |
var iy = j - kc + kj; | |
if (ix >= 0 && ix < matDim && iy >= 0 && iy < matDim) { | |
var inputSamp = mat[ix * matDim + iy]; | |
var kernSamp = kernel[ki * kernDim + kj]; | |
acc += inputSamp * kernSamp; | |
} | |
} | |
} | |
out[i * matDim + j] = acc; | |
} | |
} | |
return out; | |
} | |
function main() { | |
var kernSize = 5; | |
var kernel = buildKernel(kernSize, 1.9); | |
var matSize = 6; | |
var mat = scalarMultiply(markovNormalize(convolve(eye(matSize), kernel)), 100); | |
console.log('KERNEL...'); | |
for (let i = 0; i < kernSize; i++) { | |
let row = kernel.slice(i * kernSize, i * kernSize + kernSize); | |
console.log(row); | |
} | |
console.log('CONVOLVED...'); | |
for (let i = 0; i < matSize; i++) { | |
let row = mat.slice(i * matSize, i * matSize + matSize); | |
console.log(row); | |
} | |
} | |
main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment