StackGenVis: Alignment of Data, Algorithms, and Models for Stacking Ensemble Learning Using Performance Metrics
https://doi.org/10.1109/TVCG.2020.3030352
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
4.2 KiB
137 lines
4.2 KiB
4 years ago
|
'use strict'
|
||
|
|
||
|
var clamp = require('clamp')
|
||
|
|
||
|
module.exports = calcSDF
|
||
|
|
||
|
var INF = 1e20;
|
||
|
|
||
|
function calcSDF(src, options) {
|
||
|
if (!options) options = {}
|
||
|
|
||
|
var cutoff = options.cutoff == null ? 0.25 : options.cutoff
|
||
|
var radius = options.radius == null ? 8 : options.radius
|
||
|
var channel = options.channel || 0
|
||
|
var w, h, size, data, intData, stride, ctx, canvas, imgData, i, l
|
||
|
|
||
|
// handle image container
|
||
|
if (ArrayBuffer.isView(src) || Array.isArray(src)) {
|
||
|
if (!options.width || !options.height) throw Error('For raw data width and height should be provided by options')
|
||
|
w = options.width, h = options.height
|
||
|
data = src
|
||
|
|
||
|
if (!options.stride) stride = Math.floor(src.length / w / h)
|
||
|
else stride = options.stride
|
||
|
}
|
||
|
else {
|
||
|
if (window.HTMLCanvasElement && src instanceof window.HTMLCanvasElement) {
|
||
|
canvas = src
|
||
|
ctx = canvas.getContext('2d')
|
||
|
w = canvas.width, h = canvas.height
|
||
|
imgData = ctx.getImageData(0, 0, w, h)
|
||
|
data = imgData.data
|
||
|
stride = 4
|
||
|
}
|
||
|
else if (window.CanvasRenderingContext2D && src instanceof window.CanvasRenderingContext2D) {
|
||
|
canvas = src.canvas
|
||
|
ctx = src
|
||
|
w = canvas.width, h = canvas.height
|
||
|
imgData = ctx.getImageData(0, 0, w, h)
|
||
|
data = imgData.data
|
||
|
stride = 4
|
||
|
}
|
||
|
else if (window.ImageData && src instanceof window.ImageData) {
|
||
|
imgData = src
|
||
|
w = src.width, h = src.height
|
||
|
data = imgData.data
|
||
|
stride = 4
|
||
|
}
|
||
|
}
|
||
|
|
||
|
size = Math.max(w, h)
|
||
|
|
||
|
//convert int data to floats
|
||
|
if ((window.Uint8ClampedArray && data instanceof window.Uint8ClampedArray) || (window.Uint8Array && data instanceof window.Uint8Array)) {
|
||
|
intData = data
|
||
|
data = Array(w*h)
|
||
|
|
||
|
for (i = 0, l = intData.length; i < l; i++) {
|
||
|
data[i] = intData[i*stride + channel] / 255
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (stride !== 1) throw Error('Raw data can have only 1 value per pixel')
|
||
|
}
|
||
|
|
||
|
// temporary arrays for the distance transform
|
||
|
var gridOuter = Array(w * h)
|
||
|
var gridInner = Array(w * h)
|
||
|
var f = Array(size)
|
||
|
var d = Array(size)
|
||
|
var z = Array(size + 1)
|
||
|
var v = Array(size)
|
||
|
|
||
|
for (i = 0, l = w * h; i < l; i++) {
|
||
|
var a = data[i]
|
||
|
gridOuter[i] = a === 1 ? 0 : a === 0 ? INF : Math.pow(Math.max(0, 0.5 - a), 2)
|
||
|
gridInner[i] = a === 1 ? INF : a === 0 ? 0 : Math.pow(Math.max(0, a - 0.5), 2)
|
||
|
}
|
||
|
|
||
|
edt(gridOuter, w, h, f, d, v, z)
|
||
|
edt(gridInner, w, h, f, d, v, z)
|
||
|
|
||
|
var dist = window.Float32Array ? new Float32Array(w * h) : new Array(w * h)
|
||
|
|
||
|
for (i = 0, l = w*h; i < l; i++) {
|
||
|
dist[i] = clamp(1 - ( (gridOuter[i] - gridInner[i]) / radius + cutoff), 0, 1)
|
||
|
}
|
||
|
|
||
|
return dist
|
||
|
}
|
||
|
|
||
|
// 2D Euclidean distance transform by Felzenszwalb & Huttenlocher https://cs.brown.edu/~pff/dt/
|
||
|
function edt(data, width, height, f, d, v, z) {
|
||
|
for (var x = 0; x < width; x++) {
|
||
|
for (var y = 0; y < height; y++) {
|
||
|
f[y] = data[y * width + x]
|
||
|
}
|
||
|
edt1d(f, d, v, z, height)
|
||
|
for (y = 0; y < height; y++) {
|
||
|
data[y * width + x] = d[y]
|
||
|
}
|
||
|
}
|
||
|
for (y = 0; y < height; y++) {
|
||
|
for (x = 0; x < width; x++) {
|
||
|
f[x] = data[y * width + x]
|
||
|
}
|
||
|
edt1d(f, d, v, z, width)
|
||
|
for (x = 0; x < width; x++) {
|
||
|
data[y * width + x] = Math.sqrt(d[x])
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 1D squared distance transform
|
||
|
function edt1d(f, d, v, z, n) {
|
||
|
v[0] = 0;
|
||
|
z[0] = -INF
|
||
|
z[1] = +INF
|
||
|
|
||
|
for (var q = 1, k = 0; q < n; q++) {
|
||
|
var s = ((f[q] + q * q) - (f[v[k]] + v[k] * v[k])) / (2 * q - 2 * v[k])
|
||
|
while (s <= z[k]) {
|
||
|
k--
|
||
|
s = ((f[q] + q * q) - (f[v[k]] + v[k] * v[k])) / (2 * q - 2 * v[k])
|
||
|
}
|
||
|
k++
|
||
|
v[k] = q
|
||
|
z[k] = s
|
||
|
z[k + 1] = +INF
|
||
|
}
|
||
|
|
||
|
for (q = 0, k = 0; q < n; q++) {
|
||
|
while (z[k + 1] < q) k++
|
||
|
d[q] = (q - v[k]) * (q - v[k]) + f[v[k]]
|
||
|
}
|
||
|
}
|