Skip to content

Instantly share code, notes, and snippets.

@nick-thompson
Last active April 17, 2018 00:03
Show Gist options
  • Save nick-thompson/aad8830d887d14fa5a97ee11fa37a0fc to your computer and use it in GitHub Desktop.
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/
/** 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