UNPKG

@ai-on-browser/data-analysis-models

Version:

Data analysis model package without any dependencies

97 lines (87 loc) 2.23 kB
/** * Sezan's thresholding */ export default class SezanThresholding { // https://qiita.com/yuji0001/items/29c02b4fa1506edbdf19 /** * @param {number} [gamma] Tradeoff value between black and white * @param {number} [sigma] Sigma of normal distribution */ constructor(gamma = 0.5, sigma = 5) { this._gamma = gamma this._sigma = sigma this._count = 256 } /** * Returns thresholded values. * @param {number[]} x Training data * @returns {(0 | 1)[]} Predicted values */ predict(x) { const max = x.reduce((m, v) => Math.max(m, v), -Infinity) const min = x.reduce((m, v) => Math.min(m, v), Infinity) const hist = Array(this._count).fill(0) for (let i = 0; i < x.length; i++) { if (x[i] === max) { hist[this._count - 1]++ } else { hist[Math.floor(((x[i] - min) / (max - min)) * this._count)]++ } } const kernel = [] const ksize = 55 const ksize2 = Math.floor(ksize / 2) let ksum = 0 for (let i = 0; i < ksize; i++) { kernel[i] = Math.exp(-((i - ksize2) ** 2) / (2 * this._sigma ** 2)) ksum += kernel[i] } for (let i = 0; i < kernel.length; i++) { kernel[i] /= ksum } const histbar = [] for (let i = 0; i < hist.length; i++) { histbar[i] = 0 for (let k = i - ksize2; k <= i + ksize2; k++) { if (k >= 0 && k < hist.length) { histbar[i] += hist[k] * kernel[k - i + ksize2] } } } const histdiff = [0] for (let i = 1; i < histbar.length; i++) { histdiff[i] = histbar[i - 1] - histbar[i] } histdiff.push(0) const m = [] const es = [] for (let i = 0; i < histdiff.length - 1; i++) { if (histdiff[i + 1] >= 0 && histdiff[i] <= 0) { m.push(i) } if (histdiff[i + 1] <= 0 && histdiff[i] >= 0) { es.push(i) } } const m0 = m[0] const m1 = m[m.length - 1] let s0 = 0 let e0 = 0 let s1 = 0 let e1 = 0 for (let i = 0; i < es.length; i++) { if (es[i] < m0) { s0 = es[i] } else if (es[i] > m0 && e0 === 0) { e0 = es[i] } if (es[i] < m1) { s1 = es[i] } else if (es[i] > m1 && e1 === 0) { e1 = es[i] } } this._th = (((1 - this._gamma) * e0 + this._gamma * s1 + 0.5) * (max - min)) / this._count + min return x.map(v => (v < this._th ? 0 : 1)) } }