diff --git a/helpers.js b/helpers.js new file mode 100644 index 0000000000000000000000000000000000000000..ce5128a8bf42e4f2bac4ed1d1d730d9d00cb32eb --- /dev/null +++ b/helpers.js @@ -0,0 +1,810 @@ +const pipe = (first, ...more) => more.reduce((acc,curr) => (...arguments) => curr(acc(...arguments)) , first); + +const offsetHelper = (distances, offset, width, height) => { + var w = width; + var h = height; + var offset = offset; + var input = distances; + var output = new Uint8ClampedArray(4 * h * w); + for (var row = 0; row < h; ++row) { + for (var col = 0; col < w; ++col) { + if (input[(h - 1 - row) * w + col] <= offset) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } + } + } + + const imgData = new ImageData(output, w, h); + + return imgData; +}; + +const edgeDetectHelper = imageRGBA => { + var h = imageRGBA.height; + var w = imageRGBA.width; + var input = imageRGBA.data; + var output = new Uint8ClampedArray(h * w * 4); + var i00, i0m, i0p, im0, ip0, imm, imp, ipm, ipp, row, col; + // + // find edges - interior + // + for (row = 1; row < h - 1; ++row) { + for (col = 1; col < w - 1; ++col) { + i00 = + input[(h - 1 - row) * w * 4 + col * 4 + 0] + + input[(h - 1 - row) * w * 4 + col * 4 + 1] + + input[(h - 1 - row) * w * 4 + col * 4 + 2]; + i0p = + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 0] + + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 1] + + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 2]; + ip0 = + input[(h - 2 - row) * w * 4 + col * 4 + 0] + + input[(h - 2 - row) * w * 4 + col * 4 + 1] + + input[(h - 2 - row) * w * 4 + col * 4 + 2]; + ipp = + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 0] + + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 1] + + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 2]; + i0m = + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 0] + + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 1] + + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 2]; + im0 = + input[(h - row) * w * 4 + col * 4 + 0] + + input[(h - row) * w * 4 + col * 4 + 1] + + input[(h - row) * w * 4 + col * 4 + 2]; + imm = + input[(h - row) * w * 4 + (col - 1) * 4 + 0] + + input[(h - row) * w * 4 + (col - 1) * 4 + 1] + + input[(h - row) * w * 4 + (col - 1) * 4 + 2]; + imp = + input[(h - row) * w * 4 + (col + 1) * 4 + 0] + + input[(h - row) * w * 4 + (col + 1) * 4 + 1] + + input[(h - row) * w * 4 + (col + 1) * 4 + 2]; + ipm = + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 0] + + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 1] + + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 2]; + if ( + i00 != i0p || + i00 != ip0 || + i00 != ipp || + i00 != i0m || + i00 != im0 || + i00 != imm || + i00 != imp || + i00 != ipm + ) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else if (i00 == 0) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } + } + } + // + // left and right edges + // + for (row = 1; row < h - 1; ++row) { + col = w - 1; + i00 = + input[(h - 1 - row) * w * 4 + col * 4 + 0] + + input[(h - 1 - row) * w * 4 + col * 4 + 1] + + input[(h - 1 - row) * w * 4 + col * 4 + 2]; + i0m = + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 0] + + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 1] + + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 2]; + imm = + input[(h - row) * w * 4 + (col - 1) * 4 + 0] + + input[(h - row) * w * 4 + (col - 1) * 4 + 1] + + input[(h - row) * w * 4 + (col - 1) * 4 + 2]; + ipm = + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 0] + + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 1] + + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 2]; + im0 = + input[(h - row) * w * 4 + col * 4 + 0] + + input[(h - row) * w * 4 + col * 4 + 1] + + input[(h - row) * w * 4 + col * 4 + 2]; + ip0 = + input[(h - 2 - row) * w * 4 + col * 4 + 0] + + input[(h - 2 - row) * w * 4 + col * 4 + 1] + + input[(h - 2 - row) * w * 4 + col * 4 + 2]; + if (i00 != i0m || i00 != ip0 || i00 != ipm || i00 != im0 || i00 != imm) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else if (i00 == 0) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } + col = 0; + i00 = + input[(h - 1 - row) * w * 4 + col * 4 + 0] + + input[(h - 1 - row) * w * 4 + col * 4 + 1] + + input[(h - 1 - row) * w * 4 + col * 4 + 2]; + i0p = + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 0] + + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 1] + + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 2]; + imp = + input[(h - row) * w * 4 + (col + 1) * 4 + 0] + + input[(h - row) * w * 4 + (col + 1) * 4 + 1] + + input[(h - row) * w * 4 + (col + 1) * 4 + 2]; + ipp = + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 0] + + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 1] + + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 2]; + im0 = + input[(h - row) * w * 4 + col * 4 + 0] + + input[(h - row) * w * 4 + col * 4 + 1] + + input[(h - row) * w * 4 + col * 4 + 2]; + ip0 = + input[(h - 2 - row) * w * 4 + col * 4 + 0] + + input[(h - 2 - row) * w * 4 + col * 4 + 1] + + input[(h - 2 - row) * w * 4 + col * 4 + 2]; + if (i00 != i0p || i00 != ip0 || i00 != ipp || i00 != im0 || i00 != imp) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else if (i00 == 0) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } + } + // + // top and bottom edges + // + for (col = 1; col < w - 1; ++col) { + row = h - 1; + i00 = + input[(h - 1 - row) * w * 4 + col * 4 + 0] + + input[(h - 1 - row) * w * 4 + col * 4 + 1] + + input[(h - 1 - row) * w * 4 + col * 4 + 2]; + i0m = + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 0] + + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 1] + + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 2]; + i0p = + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 0] + + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 1] + + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 2]; + imm = + input[(h - row) * w * 4 + (col - 1) * 4 + 0] + + input[(h - row) * w * 4 + (col - 1) * 4 + 1] + + input[(h - row) * w * 4 + (col - 1) * 4 + 2]; + im0 = + input[(h - row) * w * 4 + col * 4 + 0] + + input[(h - row) * w * 4 + col * 4 + 1] + + input[(h - row) * w * 4 + col * 4 + 2]; + imp = + input[(h - row) * w * 4 + (col + 1) * 4 + 0] + + input[(h - row) * w * 4 + (col + 1) * 4 + 1] + + input[(h - row) * w * 4 + (col + 1) * 4 + 2]; + if (i00 != i0m || i00 != i0p || i00 != imm || i00 != im0 || i00 != imp) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else if (i00 == 0) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } + row = 0; + i00 = + input[(h - 1 - row) * w * 4 + col * 4 + 0] + + input[(h - 1 - row) * w * 4 + col * 4 + 1] + + input[(h - 1 - row) * w * 4 + col * 4 + 2]; + i0m = + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 0] + + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 1] + + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 2]; + i0p = + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 0] + + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 1] + + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 2]; + ipm = + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 0] + + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 1] + + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 2]; + ip0 = + input[(h - 2 - row) * w * 4 + col * 4 + 0] + + input[(h - 2 - row) * w * 4 + col * 4 + 1] + + input[(h - 2 - row) * w * 4 + col * 4 + 2]; + ipp = + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 0] + + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 1] + + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 2]; + if (i00 != i0m || i00 != i0p || i00 != ipm || i00 != ip0 || i00 != ipp) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else if (i00 == 0) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } + } + // + // corners + // + row = 0; + col = 0; + i00 = + input[(h - 1 - row) * w * 4 + col * 4 + 0] + + input[(h - 1 - row) * w * 4 + col * 4 + 1] + + input[(h - 1 - row) * w * 4 + col * 4 + 2]; + i0p = + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 0] + + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 1] + + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 2]; + ip0 = + input[(h - 2 - row) * w * 4 + col * 4 + 0] + + input[(h - 2 - row) * w * 4 + col * 4 + 1] + + input[(h - 2 - row) * w * 4 + col * 4 + 2]; + ipp = + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 0] + + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 1] + + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 2]; + if (i00 != i0p || i00 != ip0 || i00 != ipp) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else if (i00 == 0) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } + row = 0; + col = w - 1; + i00 = + input[(h - 1 - row) * w * 4 + col * 4 + 0] + + input[(h - 1 - row) * w * 4 + col * 4 + 1] + + input[(h - 1 - row) * w * 4 + col * 4 + 2]; + i0m = + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 0] + + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 1] + + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 2]; + ip0 = + input[(h - 2 - row) * w * 4 + col * 4 + 0] + + input[(h - 2 - row) * w * 4 + col * 4 + 1] + + input[(h - 2 - row) * w * 4 + col * 4 + 2]; + ipm = + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 0] + + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 1] + + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 2]; + if (i00 != i0m || i00 != ip0 || i00 != ipm) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else if (i00 == 0) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } + row = h - 1; + col = 0; + i00 = + input[(h - 1 - row) * w * 4 + col * 4 + 0] + + input[(h - 1 - row) * w * 4 + col * 4 + 1] + + input[(h - 1 - row) * w * 4 + col * 4 + 2]; + i0p = + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 0] + + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 1] + + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 2]; + im0 = + input[(h - row) * w * 4 + col * 4 + 0] + + input[(h - row) * w * 4 + col * 4 + 1] + + input[(h - row) * w * 4 + col * 4 + 2]; + imp = + input[(h - row) * w * 4 + (col + 1) * 4 + 0] + + input[(h - row) * w * 4 + (col + 1) * 4 + 1] + + input[(h - row) * w * 4 + (col + 1) * 4 + 2]; + if (i00 != i0p || i00 != im0 || i00 != imp) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else if (i00 == 0) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } + row = h - 1; + col = w - 1; + i00 = + input[(h - 1 - row) * w * 4 + col * 4 + 0] + + input[(h - 1 - row) * w * 4 + col * 4 + 1] + + input[(h - 1 - row) * w * 4 + col * 4 + 2]; + i0m = + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 0] + + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 1] + + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 2]; + im0 = + input[(h - row) * w * 4 + col * 4 + 0] + + input[(h - row) * w * 4 + col * 4 + 1] + + input[(h - row) * w * 4 + col * 4 + 2]; + imm = + input[(h - row) * w * 4 + (col - 1) * 4 + 0] + + input[(h - row) * w * 4 + (col - 1) * 4 + 1] + + input[(h - row) * w * 4 + (col - 1) * 4 + 2]; + if (i00 != i0m || i00 != im0 || i00 != imm) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else if (i00 == 0) { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } else { + output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; + output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; + } + + const imgData = new ImageData(output, w, h); + + return imgData; +}; + +const orientEdgesHelper = imageRGBA => { + var h = imageRGBA.height; + var w = imageRGBA.width; + var input = imageRGBA.data; + var output = new Uint8ClampedArray(h * w * 4); + var row, col; + var boundary = 0; + var interior = 1; + var exterior = 2; + var alpha = 3; + var northsouth = 0; + var north = 128; + var south = 64; + var eastwest = 1; + var east = 128; + var west = 64; + var startstop = 2; + var start = 128; + var stop = 64; + // + // orient body states + // + for (row = 1; row < h - 1; ++row) { + for (col = 1; col < w - 1; ++col) { + output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; + if (input[(h - 1 - row) * w * 4 + col * 4 + boundary] != 0) { + if ( + input[(h - 1 - (row + 1)) * w * 4 + col * 4 + boundary] != 0 && + (input[(h - 1 - row) * w * 4 + (col + 1) * 4 + interior] != 0 || + input[(h - 1 - (row + 1)) * w * 4 + (col + 1) * 4 + interior] != + 0) + ) + output[(h - 1 - row) * w * 4 + col * 4 + northsouth] |= north; + if ( + input[(h - 1 - (row - 1)) * w * 4 + col * 4 + boundary] != 0 && + (input[(h - 1 - row) * w * 4 + (col - 1) * 4 + interior] != 0 || + input[(h - 1 - (row - 1)) * w * 4 + (col - 1) * 4 + interior] != + 0) + ) + output[(h - 1 - row) * w * 4 + col * 4 + northsouth] |= south; + if ( + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + boundary] != 0 && + (input[(h - 1 - (row - 1)) * w * 4 + col * 4 + interior] != 0 || + input[(h - 1 - (row - 1)) * w * 4 + (col + 1) * 4 + interior] != + 0) + ) + output[(h - 1 - row) * w * 4 + col * 4 + eastwest] |= east; + if ( + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + boundary] != 0 && + (input[(h - 1 - (row + 1)) * w * 4 + col * 4 + interior] != 0 || + input[(h - 1 - (row + 1)) * w * 4 + (col - 1) * 4 + interior] != + 0) + ) + output[(h - 1 - row) * w * 4 + col * 4 + eastwest] |= west; + } + } + } + // + // orient edge states + // + for (col = 1; col < w - 1; ++col) { + row = 0; + output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; + if (input[(h - 1 - row) * w * 4 + col * 4 + boundary] != 0) { + if ( + input[(h - 1 - (row + 1)) * w * 4 + col * 4 + boundary] != 0 && + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + interior] != 0 + ) { + output[(h - 1 - row) * w * 4 + col * 4 + northsouth] |= north; + output[(h - 1 - row) * w * 4 + col * 4 + startstop] |= start; + } + if (input[(h - 1 - row) * w * 4 + (col - 1) * 4 + interior] != 0) + output[(h - 1 - row) * w * 4 + col * 4 + startstop] |= stop; + } + row = h - 1; + output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; + if (input[(h - 1 - row) * w * 4 + col * 4 + boundary] != 0) { + if (input[(h - 1 - row) * w * 4 + (col + 1) * 4 + interior] != 0) + output[(h - 1 - row) * w * 4 + col * 4 + startstop] |= stop; + if ( + input[(h - 1 - (row - 1)) * w * 4 + col * 4 + boundary] != 0 && + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + interior] != 0 + ) { + output[(h - 1 - row) * w * 4 + col * 4 + northsouth] |= south; + output[(h - 1 - row) * w * 4 + col * 4 + startstop] |= start; + } + } + } + for (row = 1; row < h - 1; ++row) { + col = 0; + output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; + if (input[(h - 1 - row) * w * 4 + col * 4 + boundary] != 0) { + if ( + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + boundary] != 0 && + input[(h - 1 - (row - 1)) * w * 4 + col * 4 + interior] != 0 + ) { + output[(h - 1 - row) * w * 4 + col * 4 + eastwest] |= east; + output[(h - 1 - row) * w * 4 + col * 4 + startstop] |= start; + } + if (input[(h - 1 - (row + 1)) * w * 4 + col * 4 + interior] != 0) + output[(h - 1 - row) * w * 4 + col * 4 + startstop] |= stop; + } + col = w - 1; + output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; + if (input[(h - 1 - row) * w * 4 + col * 4 + boundary] != 0) { + if (input[(h - 1 - (row - 1)) * w * 4 + col * 4 + interior] != 0) + output[(h - 1 - row) * w * 4 + col * 4 + startstop] |= stop; + if ( + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + boundary] != 0 && + input[(h - 1 - (row + 1)) * w * 4 + col * 4 + interior] != 0 + ) { + output[(h - 1 - row) * w * 4 + col * 4 + eastwest] |= west; + output[(h - 1 - row) * w * 4 + col * 4 + startstop] |= start; + } + } + } + // + // orient corner states (todo) + // + row = 0; + col = 0; + output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; + row = h - 1; + col = 0; + output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; + row = 0; + col = w - 1; + output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; + row = h - 1; + col = w - 1; + output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; + output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; + + // var display = new Uint8ClampedArray(h*w*4) + // var r,g,b,i + // for (row = 0; row < h; ++row) { + // for (col = 0; col < w; ++col) { + // r = output[(h-1-row)*w*4+col*4+0] + // g = output[(h-1-row)*w*4+col*4+1] + // b = output[(h-1-row)*w*4+col*4+2] + // i = r+g+b + // if (i != 0) { + // display[(h-1-row)*w*4+col*4+0] = output[(h-1-row)*w*4+col*4+0] + // display[(h-1-row)*w*4+col*4+1] = output[(h-1-row)*w*4+col*4+1] + // display[(h-1-row)*w*4+col*4+2] = output[(h-1-row)*w*4+col*4+2] + // display[(h-1-row)*w*4+col*4+3] = output[(h-1-row)*w*4+col*4+3] + // } + // else { + // display[(h-1-row)*w*4+col*4+0] = 255 + // display[(h-1-row)*w*4+col*4+1] = 255 + // display[(h-1-row)*w*4+col*4+2] = 255 + // display[(h-1-row)*w*4+col*4+3] = 255 + // } + // } + // } + + const imgData = new ImageData(output, w, h); + + return imgData; +}; + +const vectorizeHelper = (imageRGBA, vectorFit = 1, sort = true) => { + var h = imageRGBA.height; + var w = imageRGBA.width; + var input = imageRGBA.data; + var northsouth = 0; + var north = 128; + var south = 64; + var eastwest = 1; + var east = 128; + var west = 64; + var startstop = 2; + var start = 128; + var stop = 64; + var path = []; + // + // edge follower + // + function follow_edges(row, col) { + if ( + input[(h - 1 - row) * w * 4 + col * 4 + northsouth] != 0 || + input[(h - 1 - row) * w * 4 + col * 4 + eastwest] != 0 + ) { + path[path.length] = [[col, row]]; + while (1) { + if ( + input[(h - 1 - row) * w * 4 + col * 4 + northsouth] & north + ) { + input[(h - 1 - row) * w * 4 + col * 4 + northsouth] = + input[(h - 1 - row) * w * 4 + col * 4 + northsouth] & + ~north; + row += 1; + path[path.length - 1][path[path.length - 1].length] = [ + col, + row + ]; + } else if ( + input[(h - 1 - row) * w * 4 + col * 4 + northsouth] & south + ) { + input[(h - 1 - row) * w * 4 + col * 4 + northsouth] = + input[(h - 1 - row) * w * 4 + col * 4 + northsouth] & + ~south; + row -= 1; + path[path.length - 1][path[path.length - 1].length] = [ + col, + row + ]; + } else if ( + input[(h - 1 - row) * w * 4 + col * 4 + eastwest] & east + ) { + input[(h - 1 - row) * w * 4 + col * 4 + eastwest] = + input[(h - 1 - row) * w * 4 + col * 4 + eastwest] & ~east; + col += 1; + path[path.length - 1][path[path.length - 1].length] = [ + col, + row + ]; + } else if ( + input[(h - 1 - row) * w * 4 + col * 4 + eastwest] & west + ) { + input[(h - 1 - row) * w * 4 + col * 4 + eastwest] = + input[(h - 1 - row) * w * 4 + col * 4 + eastwest] & ~west; + col -= 1; + path[path.length - 1][path[path.length - 1].length] = [ + col, + row + ]; + } else break; + } + } + } + // + // follow boundary starts + // + for (var row = 1; row < h - 1; ++row) { + col = 0; + follow_edges(row, col); + col = w - 1; + follow_edges(row, col); + } + for (var col = 1; col < w - 1; ++col) { + row = 0; + follow_edges(row, col); + row = h - 1; + follow_edges(row, col); + } + // + // follow interior paths + // + for (var row = 1; row < h - 1; ++row) { + for (var col = 1; col < w - 1; ++col) { + follow_edges(row, col); + } + } + // + // vectorize path + // + var error = vectorFit; + var vecpath = []; + for (var seg = 0; seg < path.length; ++seg) { + var x0 = path[seg][0][0]; + var y0 = path[seg][0][1]; + vecpath[vecpath.length] = [[x0, y0]]; + var xsum = x0; + var ysum = y0; + var sum = 1; + for (var pt = 1; pt < path[seg].length; ++pt) { + var xold = x; + var yold = y; + var x = path[seg][pt][0]; + var y = path[seg][pt][1]; + if (sum == 1) { + xsum += x; + ysum += y; + sum += 1; + } else { + var xmean = xsum / sum; + var ymean = ysum / sum; + var dx = xmean - x0; + var dy = ymean - y0; + var d = Math.sqrt(dx * dx + dy * dy); + var nx = dy / d; + var ny = -dx / d; + var l = Math.abs(nx * (x - x0) + ny * (y - y0)); + if (l < error) { + xsum += x; + ysum += y; + sum += 1; + } else { + vecpath[vecpath.length - 1][ + vecpath[vecpath.length - 1].length + ] = [xold, yold]; + x0 = xold; + y0 = yold; + xsum = xold; + ysum = yold; + sum = 1; + } + } + if (pt == path[seg].length - 1) { + vecpath[vecpath.length - 1][ + vecpath[vecpath.length - 1].length + ] = [x, y]; + } + } + } + // + // sort path + // + if (vecpath.length > 1 && sort == true) { + var dmin = w * w + h * h; + var segmin = null; + for (var seg = 0; seg < vecpath.length; ++seg) { + var x = vecpath[seg][0][0]; + var y = vecpath[seg][0][0]; + var d = x * x + y * y; + if (d < dmin) { + dmin = d; + segmin = seg; + } + } + if (segmin != null) { + var sortpath = [vecpath[segmin]]; + vecpath.splice(segmin, 1); + } + while (vecpath.length > 0) { + var dmin = w * w + h * h; + var x0 = + sortpath[sortpath.length - 1][ + sortpath[sortpath.length - 1].length - 1 + ][0]; + var y0 = + sortpath[sortpath.length - 1][ + sortpath[sortpath.length - 1].length - 1 + ][1]; + segmin = null; + for (var seg = 0; seg < vecpath.length; ++seg) { + var x = vecpath[seg][0][0]; + var y = vecpath[seg][0][1]; + var d = (x - x0) * (x - x0) + (y - y0) * (y - y0); + if (d < dmin) { + dmin = d; + segmin = seg; + } + } + if (segmin != null) { + sortpath[sortpath.length] = vecpath[segmin]; + vecpath.splice(segmin, 1); + } + } + } else if ( + (vecpath.length > 1 && sort == false) || + vecpath.length == 1 + ) + sortpath = vecpath; + else sortpath = []; + + return sortpath; +}; + +const test = () => console.log("import is working"); + diff --git a/hunks/flowcontrol/while.js b/hunks/flowcontrol/while.js new file mode 100644 index 0000000000000000000000000000000000000000..6315918a3570ba465a8d6a99dc1cb08c16e0fb19 --- /dev/null +++ b/hunks/flowcontrol/while.js @@ -0,0 +1,44 @@ +/* + +thou shall ? pass : not + +*/ + +import { + Hunkify, + Input, + Output, + State + } from '../hunks.js' + + function While(){ + Hunkify(this) + + // also wants to be polymorphic + let condition = new Input('boolean', 'thru', this) + this.inputs.push(condition) + + let evtOut = new Output('boolean', 'thru', this) + this.outputs.push(evtOut) + + let runState = new State('boolean', 'run', false) + this.states.push(runState) + + this.init = () => { + console.log('hello gate') + } + + this.loop = () => { + if(runStateIn.io()){ + runState.set(runStateIn.get()) + } + if(evtIn.io()){ + if(runState.value && !evtOut.io()){ + evtOut.put(evtIn.get()) + } + } + } + } + + export default While + \ No newline at end of file diff --git a/hunks/image/multipleOffsets.js b/hunks/image/multipleOffsets.js new file mode 100644 index 0000000000000000000000000000000000000000..b4429940b6137b8e3bb20fb4cd51b959a19e8324 --- /dev/null +++ b/hunks/image/multipleOffsets.js @@ -0,0 +1,114 @@ +/* + +hunk template + +*/ + +// these are ES6 modules +import { Hunkify, Input, Output, State } from "../hunks.js"; +import { TSET } from "../../typeset.js"; + +/* + import { + html, + svg, + render + } from 'https://unpkg.com/lit-html?module'; + */ + +export default function MultipleOffsets() { + // this fn attaches handles to our function-object, + Hunkify(this); + + // inputs + let imageIn = new Input("Float32Array", "image", this); + this.inputs.push(imageIn); + + // states + let totalOffset = new State("number", "totalOffset", 0.5); + this.states.push(totalOffset); + + let offsetDiameter = new State("number", "offsetDiameter", 0.5); + this.states.push(offsetDiameter); + + let stepover = new State("number", "stepover", 0.5); + this.states.push(stepover); + + let width = new State("number", "width", 190); + this.states.push(width); + + let height = new State("number", "height", 266); + this.states.push(height); + + // outputs + let vectors = new Output("array", "Vectors", this); + this.outputs.push(vectors); + + // view + // this.dom = {} + this.init = () => { + //this.dom = $('<div>').get(0) + }; + + /* + this.onload = () => {} + */ + + this.loop = () => { + if (imageIn.io() && !vectors.io()) { + function work() { + self.importScripts("http://localhost:8080/helpers.js"); + + self.onmessage = function(e) { + + let vectors = []; + let offset = e.data.offsetDiameter; + + let newVectors; + + while (offset <= e.data.totalOffset) { + + newVectors = pipe( + x => offsetHelper(x.imageIn, offset, x.width, x.height), + edgeDetectHelper, + orientEdgesHelper, + vectorizeHelper + )(e.data); + + vectors = [...vectors, ...newVectors]; + + if (offset === e.data.totalOffset) break; + + offset += e.data.stepover; + + if (offset > e.data.totalOffset) { + offset = e.data.totalOffset; + } + + } + + self.postMessage(vectors); + }; + } + + var blob = new Blob(["(" + work.toString() + "())"]); + var url = window.URL.createObjectURL(blob); + var worker = new Worker(url); + + worker.onmessage = e => { + const message = e.data; + vectors.put(message); + worker.terminate(); + }; + + worker.postMessage({ + imageIn: imageIn.get(), + width: width.value, + height: height.value, + totalOffset: totalOffset.value, + offsetDiameter: offsetDiameter.value, + stepover: stepover.value, + }); + } + }; +} diff --git a/hunks/image/renderVectors.js b/hunks/image/renderVectors.js index 2e2acfa27512b2143e12f6cad86dd33f229cbcdc..9860fca5932c3d8155a5fc298d9e5fa92c7a4069 100644 --- a/hunks/image/renderVectors.js +++ b/hunks/image/renderVectors.js @@ -60,7 +60,7 @@ export default function RenderVectors() { $(this.dom).append(target); const view = html` - <svg id="svg" width="300" height="300"></svg> + <svg id=${svgUid} width="300" height="300"></svg> `; render(view, target); }; @@ -69,7 +69,12 @@ export default function RenderVectors() { this.loop = () => { if (vectors.io()) { const newView = renderVectorsHelper(vectors.get()); - const svgTarget = document.getElementById("svg"); + + let svgTarget = $(this.dom) + .find("svg") + .get(0); + + // const svgTarget = document.getElementById(svgUid); render(newView, svgTarget); } }; diff --git a/save/contexts/cuttlefish/imageTest2.json b/save/contexts/cuttlefish/imageTest2.json new file mode 100644 index 0000000000000000000000000000000000000000..75cc45cb73fe5cbe4470cff754938edd7ee468d2 --- /dev/null +++ b/save/contexts/cuttlefish/imageTest2.json @@ -0,0 +1,253 @@ +{ + "interpreterName": "cuttlefish", + "interpreterVersion": "v0.1", + "hunks": [ + { + "type": "manager", + "name": "nrol", + "inputs": [ + { + "name": "msgs", + "type": "byteArray" + } + ], + "outputs": [ + { + "name": "msgs", + "type": "byteArray", + "connections": [ + { + "inHunkIndex": "1", + "inHunkInput": "0" + } + ] + } + ] + }, + { + "type": "view", + "name": "tlview", + "inputs": [ + { + "name": "msgs", + "type": "byteArray" + } + ], + "outputs": [ + { + "name": "msgs", + "type": "byteArray", + "connections": [ + { + "inHunkIndex": "0", + "inHunkInput": "0" + } + ] + } + ] + }, + { + "type": "image/thresholdrgba", + "name": "image/thresholdrgba_3", + "inputs": [ + { + "name": "image", + "type": "ImageData" + } + ], + "outputs": [ + { + "name": "image", + "type": "ImageData", + "connections": [ + { + "inHunkIndex": "5", + "inHunkInput": "0" + } + ] + } + ], + "states": [ + { + "name": "threshold", + "type": "number", + "value": "0.5" + } + ] + }, + { + "type": "image/readpng", + "name": "image/readpng_3", + "outputs": [ + { + "name": "image", + "type": "ImageData", + "connections": [ + { + "inHunkIndex": "2", + "inHunkInput": "0" + } + ] + } + ], + "states": [ + { + "name": "release", + "type": "boolean", + "value": "false" + } + ] + }, + { + "type": "image/displayimagedata", + "name": "image/displayimagedata_4", + "inputs": [ + { + "name": "image", + "type": "ImageData" + } + ] + }, + { + "type": "image/distanceTransform", + "name": "image/distanceTransform_6", + "inputs": [ + { + "name": "image", + "type": "ImageData" + } + ], + "outputs": [ + { + "name": "image", + "type": "Float32Array", + "connections": [ + { + "inHunkIndex": "7", + "inHunkInput": "0" + } + ] + } + ] + }, + { + "type": "image/edgeDetect", + "name": "image/edgeDetect_7", + "inputs": [ + { + "name": "image", + "type": "ImageData" + } + ], + "outputs": [ + { + "name": "image", + "type": "ImageData", + "connections": [ + { + "inHunkIndex": "8", + "inHunkInput": "0" + } + ] + } + ] + }, + { + "type": "image/offset", + "name": "image/offset_8", + "inputs": [ + { + "name": "image", + "type": "Float32Array" + } + ], + "outputs": [ + { + "name": "image", + "type": "ImageData", + "connections": [ + { + "inHunkIndex": "6", + "inHunkInput": "0" + } + ] + } + ], + "states": [ + { + "name": "offset", + "type": "number", + "value": "0.5" + }, + { + "name": "width", + "type": "number", + "value": "190" + }, + { + "name": "height", + "type": "number", + "value": "266" + } + ] + }, + { + "type": "image/orientEdges", + "name": "image/orientEdges_9", + "inputs": [ + { + "name": "image", + "type": "ImageData" + } + ], + "outputs": [ + { + "name": "image", + "type": "ImageData", + "connections": [ + { + "inHunkIndex": "10", + "inHunkInput": "0" + }, + { + "inHunkIndex": "4", + "inHunkInput": "0" + } + ] + } + ] + }, + { + "type": "image/renderVectors", + "name": "image/renderVectors_11", + "inputs": [ + { + "name": "Vectors", + "type": "array" + } + ] + }, + { + "type": "image/vectorize", + "name": "image/vectorize_11", + "inputs": [ + { + "name": "image", + "type": "ImageData" + } + ], + "outputs": [ + { + "name": "Vectors", + "type": "array", + "connections": [ + { + "inHunkIndex": "9", + "inHunkInput": "0" + } + ] + } + ] + } + ] +} \ No newline at end of file